docs/default.css
[roojs1] / roojs-bootstrap-debug.js
index 80c5445..41dfe9f 100644 (file)
@@ -447,7 +447,7 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
         var cfg = {
             cls: 'btn-group',
             html : null
-        }
+        };
         
         cfg.html = this.html || cfg.html;
         
@@ -455,7 +455,7 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
             cfg = {
                 cls: 'btn-toolbar',
                 html: null
-            }
+            };
             
             return cfg;
         }
@@ -985,12 +985,13 @@ Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
  * @cfg {String} tag (header|aside|section) type of HTML tag.
  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
- * @cfg {String} fa (ban|check|...) font awesome icon
+ * @cfg {String} fa font awesome icon
  * @cfg {String} icon (info-sign|check|...) glyphicon name
  * @cfg {Boolean} hidden (true|false) hide the element
  * @cfg {Boolean} expandable (true|false) default false
  * @cfg {Boolean} expanded (true|false) default true
  * @cfg {String} rheader contet on the right of header
+ * @cfg {Boolean} clickable (true|false) default false
 
  *     
  * @constructor
@@ -1016,7 +1017,14 @@ Roo.bootstrap.Container = function(config){
          * 
          * @param {Roo.bootstrap.Container} this
          */
-        "collapse" : true
+        "collapse" : true,
+        /**
+         * @event click
+         * When a element is chick
+         * @param {Roo.bootstrap.Container} this
+         * @param {Roo.EventObject} e
+         */
+        "click" : true
     });
 };
 
@@ -1035,6 +1043,7 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
     expandable : false,
     rheader : '',
     expanded : true,
+    clickable: false,
   
      
     getChildContainer : function() {
@@ -1181,17 +1190,17 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
     
     initEvents: function() 
     {
-        if(!this.expandable){
-            return;
-        }
+        if(this.expandable){
+            var headerEl = this.headerEl();
         
-        var headerEl = this.headerEl();
-        
-        if(!headerEl){
-            return;
+            if(headerEl){
+                headerEl.on('click', this.onToggleClick, this);
+            }
         }
         
-        headerEl.on('click', this.onToggleClick, this);
+        if(this.clickable){
+            this.el.on('click', this.onClick, this);
+        }
         
     },
     
@@ -1310,6 +1319,13 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
         }
         
         t.dom.innerHTML = v;
+    },
+    
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        this.fireEvent('click', this, e);
     }
    
 });
@@ -1360,7 +1376,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
     
     imgResponsive: true,
     border: '',
-    src: '',
+    src: 'about:blank',
     href: false,
     target: false,
     xsUrl: '',
@@ -1378,7 +1394,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
             tag: 'div',
             cls: 'roo-image-responsive-group',
             cn: []
-        }
+        };
         var _this = this;
         
         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
@@ -1392,7 +1408,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
                 html: _this.html || cfg.html,
                 src: _this[size + 'Url']
-            }
+            };
             
             img.cls += ' roo-image-responsive-' + size;
             
@@ -1419,7 +1435,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
                     cn: [
                         img
                     ]
-                }
+                };
 
                 if(this.target){
                     a.target = _this.target;
@@ -1438,8 +1454,9 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
         var cfg = {
             tag: 'img',
             cls: (this.imgResponsive) ? 'img-responsive' : '',
-            html : null
-        }
+            html : null,
+            src : 'about:blank'  // just incase src get's set to undefined?!?
+        };
         
         cfg.html = this.html || cfg.html;
         
@@ -1458,9 +1475,9 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
                 tag: 'a',
                 href: this.href,
                 cn: [
-                   cfg
-               ]
-            }
+                    cfg
+                ]
+            };
             
             if(this.target){
                 a.target = this.target;
@@ -1947,7 +1964,7 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
             cls : 'dropdown-menu' ,
             style : 'z-index:1000'
             
-        }
+        };
        
         if (this.type === 'submenu') {
             cfg.cls = 'submenu active';
@@ -1965,7 +1982,14 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
         
         this.triggerEl.addClass('dropdown-toggle');
-        this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
+        
+        
+        
+        
+        if (Roo.isTouch) {
+            this.el.on('touchstart'  , this.onTouch, this);
+        }
+        this.el.on('click' , this.onClick, this);
 
         this.el.on("mouseover", this.onMouseOver, this);
         this.el.on("mouseout", this.onMouseOut, this);
@@ -1987,6 +2011,12 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         
         return false;
     },
+    
+    onTouch : function(e) {
+        e.stopEvent();
+        this.onClick(e);
+    },
+    
     onClick : function(e){
         Roo.log("menu.onClick");
         var t = this.findTargetItem(e);
@@ -2861,7 +2891,7 @@ Roo.bootstrap.MessageBox = function(){
                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
-                Roo.log(buttons)
+                //Roo.log(buttons);
                 bodyEl = dlg.bodyEl.createChild({
 
                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
@@ -3336,7 +3366,7 @@ Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
         var mark = {
             tag: "div",
             cls:"x-dlg-mask"
-        }
+        };
         
         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
         
@@ -3764,7 +3794,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
         cfg = {
             tag : 'ul',
             cls: 'nav' 
-        }
+        };
         
         if (['tabs','pills'].indexOf(this.type)!==-1) {
             cfg.cls += ' nav-' + this.type
@@ -3779,7 +3809,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
             cfg = {
                 tag: 'ul',
                 cls: 'dashboard-menu sidebar-menu'
-            }
+            };
             
             return cfg;
         }
@@ -3788,7 +3818,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
             cfg = {
                 tag: 'form',
                 cls: 'navbar-form'
-            }
+            };
             
             if (this.align === 'right') {
                 cfg.cls += ' navbar-right';
@@ -4067,7 +4097,8 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
             tag: 'li',
             cls: 'nav-item'
             
-        }
+        };
+        
         if (this.active) {
             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
         }
@@ -4192,7 +4223,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
     },
     setActive : function(state, fire, is_was_active)
     {
-        if (this.active && !state & this.navId) {
+        if (this.active && !state && this.navId) {
             this.was_active = true;
             var nv = Roo.bootstrap.NavGroup.get(this.navId);
             if (nv) {
@@ -4283,7 +4314,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         var options = {
             target : target,
             value : o[1]
-        }
+        };
         
         this.fireEvent('scrollto', this, options, e);
         
@@ -4309,6 +4340,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
  * @class Roo.bootstrap.NavSidebarItem
  * @extends Roo.bootstrap.NavItem
  * Bootstrap Navbar.NavSidebarItem class
+ * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
  * @constructor
  * Create a new Navbar Button
  * @param {Object} config The config object
@@ -4337,6 +4369,7 @@ Roo.bootstrap.NavSidebarItem = function(config){
 
 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
     
+    badgeWeight : 'default',
     
     getAutoCreate : function(){
         
@@ -4352,17 +4385,21 @@ Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
             tag: 'li',
             cls: '',
             cn: [ a ]
-        }
+        };
         var span = {
             tag: 'span',
             html : this.html || ''
-        }
+        };
         
         
         if (this.active) {
             cfg.cls += ' active';
         }
         
+        if (this.disabled) {
+            cfg.cls += ' disabled';
+        }
+        
         // left icon..
         if (this.glyphicon || this.icon) {
             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
@@ -4372,7 +4409,8 @@ Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
         a.cn.push(span);
         // then badge..
         if (this.badge !== '') {
-            a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
+            
+            a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
         }
         // fi
         if (this.menu) {
@@ -4386,7 +4424,94 @@ Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
         return cfg;
          
           
+    },
+    
+    initEvents : function()
+    { 
+        this.el.on('click', this.onClick, this);
+       
+    
+        if(this.badge !== ''){
+            this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
+        }
+        
+    },
+    
+    onClick : function(e)
+    {
+        if(this.disabled){
+            e.preventDefault();
+            return;
+        }
+        
+        if(this.preventDefault){
+            e.preventDefault();
+        }
+        
+        this.fireEvent('click', this);
+    },
+    
+    disable : function()
+    {
+        this.setDisabled(true);
+    },
+    
+    enable : function()
+    {
+        this.setDisabled(false);
+    },
+    
+    setDisabled : function(state)
+    {
+        if(this.disabled == state){
+            return;
+        }
+        
+        this.disabled = state;
+        
+        if (state) {
+            this.el.addClass('disabled');
+            return;
+        }
+        
+        this.el.removeClass('disabled');
+        
+        return;
+    },
+    
+    setActive : function(state)
+    {
+        if(this.active == state){
+            return;
+        }
+        
+        this.active = state;
+        
+        if (state) {
+            this.el.addClass('active');
+            return;
+        }
+        
+        this.el.removeClass('active');
+        
+        return;
+    },
+    
+    isActive: function () 
+    {
+        return this.active;
+    },
+    
+    setBadge : function(str)
+    {
+        if(!this.badgeEl){
+            return;
+        }
+        
+        this.badgeEl.dom.innerHTML = str;
     }
+    
    
      
  
@@ -4478,7 +4603,7 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             tag: this.tag,
             cls: this.cls,
             html: this.html
-        }
+        };
         
         return cfg;
     },
@@ -4698,7 +4823,7 @@ Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
                 }
             ]
-        }
+        };
         
         return cfg;
     }
@@ -4875,6 +5000,18 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} tooltip (Optional)
      */
+    /**
+     * @cfg {Number} xs (Optional)
+     */
+    /**
+     * @cfg {Number} sm (Optional)
+     */
+    /**
+     * @cfg {Number} md (Optional)
+     */
+    /**
+     * @cfg {Number} lg (Optional)
+     */
     /**
      * Returns the id of the column at the specified index.
      * @param {Number} index The column index
@@ -5385,10 +5522,10 @@ Roo.LoadMask.prototype = {
  * @cfg {boolean} condensed Format condensed
  * @cfg {boolean} responsive Format condensed
  * @cfg {Boolean} loadMask (true|false) default false
- * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
- * @cfg {Boolean} thead (true|false) generate thead, default true
- * @cfg {Boolean} RowSelection (true|false) default false
- * @cfg {Boolean} CellSelection (true|false) default false
+ * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
+ * @cfg {Boolean} headerShow (true|false) generate thead, default true
+ * @cfg {Boolean} rowSelection (true|false) default false
+ * @cfg {Boolean} cellSelection (true|false) default false
  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
  
  * 
@@ -5400,6 +5537,13 @@ Roo.LoadMask.prototype = {
 Roo.bootstrap.Table = function(config){
     Roo.bootstrap.Table.superclass.constructor.call(this, config);
     
+    // BC...
+    this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
+    this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
+    this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
+    this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
+    
+    
     if (this.sm) {
         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
         this.sm = this.selModel;
@@ -5520,10 +5664,11 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     cm : false,
     store : false,
     loadMask : false,
-    tfoot : true,
-    thead : true,
-    RowSelection : false,
-    CellSelection : false,
+    footerShow : true,
+    headerShow : true,
+  
+    rowSelection : false,
+    cellSelection : false,
     layout : false,
     
     // Roo.Element - the tbody
@@ -5536,7 +5681,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             tag: 'table',
             cls : 'table',
             cn : []
-        }
+        };
             
         if (this.striped) {
             cfg.cls += ' table-striped';
@@ -5596,13 +5741,13 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         }
         
         if(this.store || this.cm){
-            if(this.thead){
+            if(this.headerShow){
                 cfg.cn.push(this.renderHeader());
             }
             
             cfg.cn.push(this.renderBody());
             
-            if(this.tfoot){
+            if(this.footerShow){
                 cfg.cn.push(this.renderFooter());
             }
             
@@ -5694,7 +5839,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     {
         var cell = Roo.get(el);
         
-        if(!cell || (!this.CellSelection && !this.RowSelection)){
+        if(!cell || (!this.cellSelection && !this.rowSelection)){
             return;
         }
         
@@ -5715,11 +5860,12 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         var cellIndex = cell.dom.cellIndex;
         var rowIndex = this.getRowIndex(row);
         
-        if(this.CellSelection){
+        // why??? - should these not be based on SelectionModel?
+        if(this.cellSelection){
             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
         }
         
-        if(this.RowSelection){
+        if(this.rowSelection){
             this.fireEvent('rowclick', this, row, rowIndex, e);
         }
         
@@ -5798,13 +5944,35 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
             
             var config = cm.config[i];
-                    
+            
             var c = {
                 tag: 'th',
                 style : '',
                 html: cm.getColumnHeader(i)
             };
             
+            var hh = '';
+            
+            if(typeof(config.lgHeader) != 'undefined'){
+                hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
+            }
+            
+            if(typeof(config.mdHeader) != 'undefined'){
+                hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
+            }
+            
+            if(typeof(config.smHeader) != 'undefined'){
+                hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
+            }
+            
+            if(typeof(config.xsHeader) != 'undefined'){
+                hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
+            }
+            
+            if(hh.length){
+                c.html = hh;
+            }
+            
             if(typeof(config.tooltip) != 'undefined'){
                 c.tooltip = config.tooltip;
             }
@@ -5837,6 +6005,21 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
             }
             
+            ['xs','sm','md','lg'].map(function(size){
+                
+                if(typeof(config[size]) == 'undefined'){
+                    return;
+                }
+                
+                if (!config[size]) { // 0 = hidden
+                    cfg.cls += ' hidden-' + size;
+                    return;
+                }
+                
+                cfg.cls += ' col-' + size + '-' + config[size];
+
+            });
+            
             header.cn.push(c)
         }
         
@@ -6075,7 +6258,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 rowIndex : rowIndex,
                 colIndex : i,
                 rowClass : ''
-            }
+            };
 
             this.fireEvent('rowclass', this, rowcfg);
             
@@ -6113,6 +6296,21 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             if(typeof(config.cls) != 'undefined'){
                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
             }
+            
+            ['xs','sm','md','lg'].map(function(size){
+                
+                if(typeof(config[size]) == 'undefined'){
+                    return;
+                }
+                
+                if (!config[size]) { // 0 = hidden
+                    td.cls += ' hidden-' + size;
+                    return;
+                }
+                
+                td.cls += ' col-' + size + '-' + config[size];
+
+            });
              
             row.cn.push(td);
            
@@ -6181,7 +6379,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 var child = {
                     container: t.getChildContainer(),
                     cfg: c
-                }
+                };
                 _this.renderCellObject(child);
             })
         }
@@ -6266,9 +6464,9 @@ Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
     getAutoCreate : function(){
         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
        
-       cfg = {
-           tag: 'td'
-       }
+        cfg = {
+            tag: 'td'
+        };
         
         if(this.tag){
             cfg.tag = this.tag;
@@ -6367,7 +6565,7 @@ Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
        
         cfg = {
             tag: 'tr'
-        }
+        };
             
         if(this.cls){
             cfg.cls = this.cls;
@@ -6431,7 +6629,7 @@ Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
        
         cfg = {
             tag: 'tbody'
-        }
+        };
             
         if (this.cls) {
             cfg.cls=this.cls
@@ -6936,7 +7134,7 @@ Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
             method : this.method || 'POST',
             id : this.id || Roo.id(),
             cls : ''
-        }
+        };
         if (this.parent().xtype.match(/^Nav/)) {
             cfg.cls = 'navbar-form navbar-' + this.align;
             
@@ -7458,11 +7656,9 @@ Roo.form.VTypes = function(){
  * @extends Roo.bootstrap.Component
  * Bootstrap Input class
  * @cfg {Boolean} disabled is it disabled
- * @cfg {String} fieldLabel - the label associated
  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
  * @cfg {String} name name of the input
  * @cfg {string} fieldLabel - the label associated
- * @cfg {string}  inputType - input / file submit ...
  * @cfg {string} placeholder - placeholder to put in text.
  * @cfg {string}  before - input group add on before
  * @cfg {string} after - input group add on after
@@ -7478,6 +7674,8 @@ Roo.form.VTypes = function(){
  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
 
  * @cfg {String} align (left|center|right) Default left
+ * @cfg {Boolean} forceFeedback (true|false) Default false
+ * 
  * 
  * 
  * 
@@ -7673,6 +7871,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
     readOnly : false,
     align : false,
     formatedValue : false,
+    forceFeedback : false,
     
     parentLabelAlign : function()
     {
@@ -8153,26 +8352,55 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         }
         this.el.removeClass(this.invalidClass);
         
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
+            
+            var feedback = this.el.select('.form-control-feedback', true).first();
+            
+            if(feedback){
+                this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
+            }
+            
+        }
+        
         this.fireEvent('valid', this);
     },
     
      /**
      * Mark this field as valid
      */
-    markValid : function(){
+    markValid : function()
+    {
         if(!this.el  || this.preventMark){ // not rendered
             return;
         }
         
         this.el.removeClass([this.invalidClass, this.validClass]);
         
+        var feedback = this.el.select('.form-control-feedback', true).first();
+            
+        if(feedback){
+            this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+        }
+
         if(this.disabled || this.allowBlank){
             return;
         }
         
+        var formGroup = this.el.findParent('.form-group', false, true);
+        
+        if(formGroup){
+            
+            var label = formGroup.select('label', true).first();
+            var icon = formGroup.select('i.fa-star', true).first();
+            
+            if(label && icon){
+                icon.remove();
+            }
+        }
+        
         this.el.addClass(this.validClass);
         
-        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
             
             var feedback = this.el.select('.form-control-feedback', true).first();
             
@@ -8190,17 +8418,41 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
      * Mark this field as invalid
      * @param {String} msg The validation message
      */
-    markInvalid : function(msg){
+    markInvalid : function(msg)
+    {
         if(!this.el  || this.preventMark){ // not rendered
             return;
         }
         
         this.el.removeClass([this.invalidClass, this.validClass]);
         
+        var feedback = this.el.select('.form-control-feedback', true).first();
+            
+        if(feedback){
+            this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+        }
+
         if(this.disabled || this.allowBlank){
             return;
         }
         
+        var formGroup = this.el.findParent('.form-group', false, true);
+        
+        if(formGroup){
+            var label = formGroup.select('label', true).first();
+            var icon = formGroup.select('i.fa-star', true).first();
+
+            if(!this.getValue().length && label && !icon){
+                this.el.findParent('.form-group', false, true).createChild({
+                    tag : 'i',
+                    cls : 'text-danger fa fa-lg fa-star',
+                    tooltip : 'This field is required',
+                    style : 'margin-right:5px;'
+                }, label, true);
+            }
+        }
+        
+        
         this.el.addClass(this.invalidClass);
         
         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
@@ -8210,7 +8462,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             if(feedback){
                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
                 
-                if(this.getValue().length){
+                if(this.getValue().length || this.forceFeedback){
                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
                 }
                 
@@ -8468,16 +8720,146 @@ Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
     inputEl: function ()
     {
         return this.el.select('textarea.form-control',true).first();
-    }
-});
-
-/*
- * - LGPL
- *
- * trigger field - base class for combo..
- * 
- */
+    },
+    
+    /**
+     * Clear any invalid styles/messages for this field
+     */
+    clearInvalid : function()
+    {
+        
+        if(!this.el || this.preventMark){ // not rendered
+            return;
+        }
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+        
+        if(label && icon){
+            icon.remove();
+        }
+        
+        this.el.removeClass(this.invalidClass);
+        
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
+            
+            var feedback = this.el.select('.form-control-feedback', true).first();
+            
+            if(feedback){
+                this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
+            }
+            
+        }
+        
+        this.fireEvent('valid', this);
+    },
+    
+     /**
+     * Mark this field as valid
+     */
+    markValid : function()
+    {
+        if(!this.el  || this.preventMark){ // not rendered
+            return;
+        }
+        
+        this.el.removeClass([this.invalidClass, this.validClass]);
+        
+        var feedback = this.el.select('.form-control-feedback', true).first();
+            
+        if(feedback){
+            this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+        }
+
+        if(this.disabled || this.allowBlank){
+            return;
+        }
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+        
+        if(label && icon){
+            icon.remove();
+        }
+        
+        this.el.addClass(this.validClass);
+        
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
+            
+            var feedback = this.el.select('.form-control-feedback', true).first();
+            
+            if(feedback){
+                this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+                this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
+            }
+            
+        }
+        
+        this.fireEvent('valid', this);
+    },
+    
+     /**
+     * Mark this field as invalid
+     * @param {String} msg The validation message
+     */
+    markInvalid : function(msg)
+    {
+        if(!this.el  || this.preventMark){ // not rendered
+            return;
+        }
+        
+        this.el.removeClass([this.invalidClass, this.validClass]);
+        
+        var feedback = this.el.select('.form-control-feedback', true).first();
+            
+        if(feedback){
+            this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+        }
+
+        if(this.disabled || this.allowBlank){
+            return;
+        }
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+        
+        if(!this.getValue().length && label && !icon){
+            this.el.createChild({
+                tag : 'i',
+                cls : 'text-danger fa fa-lg fa-star',
+                tooltip : 'This field is required',
+                style : 'margin-right:5px;'
+            }, label, true);
+        }
+
+        this.el.addClass(this.invalidClass);
+        
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
+            
+            var feedback = this.el.select('.form-control-feedback', true).first();
+            
+            if(feedback){
+                this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+                
+                if(this.getValue().length || this.forceFeedback){
+                    this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
+                }
+                
+            }
+            
+        }
+        
+        this.fireEvent('invalid', this, msg);
+    }
+});
+
+/*
+ * - LGPL
+ *
+ * trigger field - base class for combo..
+ * 
+ */
  
 /**
  * @class Roo.bootstrap.TriggerField
@@ -9087,7 +9469,9 @@ Roo.data.SortTypes = {
      */
     asFloat : function(s) {
        var val = parseFloat(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
+        if(isNaN(val)) {
+            val = 0;
+        }
        return val;
     },
     
@@ -9098,7 +9482,9 @@ Roo.data.SortTypes = {
      */
     asInt : function(s) {
         var val = parseInt(String(s).replace(/,/g, ""));
-        if(isNaN(val)) val = 0;
+        if(isNaN(val)) {
+            val = 0;
+        }
        return val;
     }
 };/*
@@ -11057,6 +11443,7 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
  * @cfg {Boolean} animate default true
  * @cfg {Boolean} emptyResultText only for touch device
+ * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
  * @constructor
  * Create a new ComboBox.
  * @param {Object} config Configuration options
@@ -11127,7 +11514,20 @@ Roo.bootstrap.ComboBox = function(config){
          * Fires when specialfilter
             * @param {Roo.bootstrap.ComboBox} combo This combo box
             */
-        'specialfilter' : true
+        'specialfilter' : true,
+        /**
+         * @event tick
+         * Fires when tick the element
+            * @param {Roo.bootstrap.ComboBox} combo This combo box
+            */
+        'tick' : true,
+        /**
+         * @event touchviewdisplay
+         * Fires when touch view require special display (default is using displayField)
+            * @param {Roo.bootstrap.ComboBox} combo This combo box
+            * @param {Object} cfg set html .
+            */
+        'touchviewdisplay' : true
         
     });
     
@@ -11347,6 +11747,8 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
     showToggleBtn : true,
     animate : true,
     emptyResultText: 'Empty',
+    triggerText : 'Select',
+    
     // element that contains real text value.. (when hidden is used..)
     
     getAutoCreate : function()
@@ -11388,7 +11790,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                     tag : 'button',
                     type : 'button',
                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
-                    html : 'Edit'
+                    html : this.triggerText
                 },
                 {
                     tag : 'button',
@@ -11449,7 +11851,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                     ]
                 }
             ]
-        }
+        };
         
         var combobox = {
             cls: 'select2-container input-group select2-container-multi',
@@ -11527,16 +11929,44 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         
     },
     
+    _initEventsCalled : false,
+    
     // private
     initEvents: function()
     {
         
+        if (this._initEventsCalled) { // as we call render... prevent looping...
+            return;
+        }
+        this._initEventsCalled = true;
+        
         if (!this.store) {
             throw "can not find store for combo";
         }
         
         this.store = Roo.factory(this.store, Roo.data);
         
+        // if we are building from html. then this element is so complex, that we can not really
+        // use the rendered HTML.
+        // so we have to trash and replace the previous code.
+        if (Roo.XComponent.build_from_html) {
+            
+            // remove this element....
+            var e = this.el.dom, k=0;
+            while (e ) { e = e.previousSibling;  ++k;}
+
+            this.el.remove();
+            
+            this.el=false;
+            this.rendered = false;
+            
+            this.render(this.parent().getChildContainer(true), k);
+            
+            
+            
+        }
+        
+        
         /*
          * Touch Devices
          */
@@ -12050,12 +12480,12 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         }
         
         this.collapse();
-        
-        Roo.log(this.store.reader.jsonData);
-        if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+        // only causes errors at present
+        //Roo.log(this.store.reader.jsonData);
+        //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
             // fixme
             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-        }
+        //}
         
         
     },
@@ -12286,6 +12716,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             Roo.each(this.tickItems, function(v,k){
                 
                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
+                    Roo.log(v);
                     _this.tickItems.splice(k, 1);
                     
                     if(typeof(e) == 'undefined' && view == false){
@@ -12301,7 +12732,9 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                 return;
             }
             
-            this.tickItems.push(r.data);
+            if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
+                this.tickItems.push(r.data);
+            }
             
             if(typeof(e) == 'undefined' && view == false){
                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
@@ -12744,7 +13177,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         }
         // scroll to?
         this.view.select(match);
-        var sn = Roo.get(this.view.getSelectedNodes()[0])
+        var sn = Roo.get(this.view.getSelectedNodes()[0]);
         sn.scrollIntoView(sn.dom.parentNode, false);
     },
     
@@ -12763,7 +13196,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                 tag: 'div',
                 cls: 'loading select2-more-results select2-active',
                 html: 'Loading more results...'
-            })
+            });
             
             this.loading = this.list.select('.loading', true).first();
             
@@ -12817,7 +13250,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             
         }, this.searchField);
         
-        var close = choice.select('a.select2-search-choice-close', true).first()
+        var close = choice.select('a.select2-search-choice-close', true).first();
         
         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
         
@@ -12898,6 +13331,10 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         this.syncValue();
         
         this.validate();
+        
+        if(this.tickable && !Roo.isTouch){
+            this.view.refresh();
+        }
     },
     
     inputEl: function ()
@@ -13306,7 +13743,14 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             var row = this.touchViewListGroup.createChild(template);
             
             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
-                row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
+                var cfg = {
+                    data : d.data,
+                    html : d.data[this.displayField]
+                };
+                
+                if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
+                    row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
+                }
             }
             
             if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
@@ -13332,8 +13776,10 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
         var listHeight = this.touchViewListGroup.getHeight();
         
+        var _this = this;
+        
         if(firstChecked && listHeight > bodyHeight){
-            (function() { firstChecked.findParent('li').scrollIntoView(this.touchViewListGroup.dom); }).defer(500);
+            (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
         }
         
     },
@@ -13716,7 +14162,7 @@ Roo.View = function(config, depreciated_tpl, depreciated_config){
            
          var fctr = this.wrapEl.appendChild(document.createElement("div"));
         
-        this.footer.dataSource = this.store
+        this.footer.dataSource = this.store;
         this.footer.container = fctr;
         this.footer = Roo.factory(this.footer, Roo);
         fctr.insertFirst(this.el);
@@ -14559,7 +15005,7 @@ Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
                     ]
                 }
             ]
-        }
+        };
         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
         
         var size = this.el.select('.fc-content', true).first().getSize();
@@ -15108,7 +15554,7 @@ Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
             var cfg = {
                 cls : 'fc-event-hori fc-event-draggable',
                 html : m.title
-            }
+            };
             var cg = ctr.createChild(cfg);
             
             cg.on('click', _this.onEventClick, _this, m);
@@ -15254,7 +15700,7 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
             if (this.style) {
                 cfg.style = this.style;
             }
-            Roo.log("adding to ")
+            //Roo.log("adding to ");
             this.el = Roo.get(document.body).createChild(cfg, position);
             Roo.log(this.el);
         }
@@ -15562,7 +16008,7 @@ Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
  * Bootstrap Column class
  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
  * @cfg {Boolean} carousel true to make the group behave like a carousel
- * @cfg {Number} bullets show the panel pointer.. default 0
+ * @cfg {Boolean} bullets show bullets for the panels
  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
  * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
  * @cfg {Number} timer auto slide timer .. default 0 millisecond
@@ -15607,23 +16053,23 @@ Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
                cls : 'carousel-inner'
             }];
         
-            if(this.bullets > 0 && !Roo.isTouch){
+            if(this.bullets  && !Roo.isTouch){
                 
                 var bullets = {
                     cls : 'carousel-bullets',
                     cn : []
                 };
-                
+               
                 if(this.bullets_cls){
                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
                 }
-                
+                 /*
                 for (var i = 0; i < this.bullets; i++){
                     bullets.cn.push({
                         cls : 'bullet bullet-' + i
                     });
                 }
-                
+                */
                 bullets.cn.push({
                     cls : 'clear'
                 });
@@ -15639,9 +16085,7 @@ Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
     {
         Roo.log('-------- init events on tab group ---------');
         
-        if(this.bullets > 0 && !Roo.isTouch){
-            this.initBullet();
-        }
+        
         
         Roo.log(this);
         
@@ -15681,6 +16125,7 @@ Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
     {
         this.tabs.push( item);
         item.navId = this.navId; // not really needed..
+        this.addBullet();
     
     },
     
@@ -15815,38 +16260,39 @@ Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
         this.showPanel(this.tabs[i-1]);
     },
     
-    initBullet : function()
+    
+    addBullet: function()
     {
-        if(Roo.isTouch){
+        if(!this.bullets || Roo.isTouch){
             return;
         }
+        var ctr = this.el.select('.carousel-bullets',true).first();
+        var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
+        var bullet = ctr.createChild({
+            cls : 'bullet bullet-' + i
+        },ctr.dom.lastChild);
+        
         
         var _this = this;
         
-        for (var i = 0; i < this.bullets; i++){
-            var bullet = this.el.select('.bullet-' + i, true).first();
+        bullet.on('click', (function(e, el, o, ii, t){
 
-            if(!bullet){
-                continue;
-            }
-
-            bullet.on('click', (function(e, el, o, ii, t){
-
-                e.preventDefault();
+            e.preventDefault();
 
-                _this.showPanel(ii);
+            this.showPanel(ii);
 
-                if(_this.autoslide && _this.slideFn){
-                    clearInterval(_this.slideFn);
-                    _this.slideFn = window.setInterval(function() {
-                        _this.showPanelNext();
-                    }, _this.timer);
-                }
+            if(this.autoslide && this.slideFn){
+                clearInterval(this.slideFn);
+                this.slideFn = window.setInterval(function() {
+                    _this.showPanelNext();
+                }, this.timer);
+            }
 
-            }).createDelegate(this, [i, bullet], true));
-        }
+        }).createDelegate(this, [i, bullet], true));
+                
+        
     },
-    
+     
     setActiveBullet : function(i)
     {
         if(Roo.isTouch){
@@ -16086,7 +16532,14 @@ Roo.bootstrap.DateField = function(config){
              * @param {Roo.bootstrap.DateField} this
              * @param {Mixed} date The date value
              */
-            select : true
+            select : true,
+            /**
+             * @event beforeselect
+             * Fires when before select a date.
+             * @param {Roo.bootstrap.DateField} this
+             * @param {Mixed} date The date value
+             */
+            beforeselect : true
         });
 };
 
@@ -16220,7 +16673,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
         
         if(this.singleMode){
             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
-                v.setVisibilityMode(Roo.Element.DISPLAY)
+                v.setVisibilityMode(Roo.Element.DISPLAY);
                 v.hide();
             });
             
@@ -16239,7 +16692,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
             v.attr('colspan', function(i, val){
                 return parseInt(val) + 1;
             });
-        })
+        });
                        
         
         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
@@ -16307,7 +16760,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 tag: 'span',
                 cls: 'month',
                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
-            }
+            };
             
             months.createChild(month);
         }
@@ -16429,7 +16882,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 tag: 'td',
                 cls: 'day ' + clsName,
                 html: prevMonth.getDate()
-            })
+            });
             
             prevMonth.setDate(prevMonth.getDate()+1);
         }
@@ -16465,7 +16918,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 tag: 'span',
                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
                 html: year
-            })
+            });
             
             year += 1;
         }
@@ -16486,7 +16939,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
     
     place: function()
     {
-        if(this.isInline) return;
+        if(this.isInline) {
+            return;
+        }
         
         this.picker().removeClass(['bottom', 'top']);
         
@@ -16561,7 +17016,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
     
     hide : function()
     {
-        if(this.isInline) return;
+        if(this.isInline) {
+            return;
+        }
         this.picker().hide();
         this.viewMode = this.startViewMode;
         this.showMode();
@@ -16584,28 +17041,25 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
 
     setValue: function(v)
     {
+        if(this.fireEvent('beforeselect', this, v) !== false){
+            var d = new Date(this.parseDate(v) ).clearTime();
         
-        // v can be a string or a date..
-        
-        
-        var d = new Date(this.parseDate(v) ).clearTime();
-        
-        if(isNaN(d.getTime())){
-            this.date = this.viewDate = '';
-            Roo.bootstrap.DateField.superclass.setValue.call(this, '');
-            return;
-        }
-        
-        v = this.formatDate(d);
-        
-        Roo.bootstrap.DateField.superclass.setValue.call(this, v);
-        
-        this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
-     
-        this.update();
+            if(isNaN(d.getTime())){
+                this.date = this.viewDate = '';
+                Roo.bootstrap.DateField.superclass.setValue.call(this, '');
+                return;
+            }
 
-        this.fireEvent('select', this, this.date);
-        
+            v = this.formatDate(d);
+
+            Roo.bootstrap.DateField.superclass.setValue.call(this, v);
+
+            this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
+
+            this.update();
+
+            this.fireEvent('select', this, this.date);
+        }
     },
     
     getValue: function()
@@ -16616,8 +17070,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
     fireKey: function(e)
     {
         if (!this.picker().isVisible()){
-            if (e.keyCode == 27) // allow escape to hide and re-show picker
+            if (e.keyCode == 27) // allow escape to hide and re-show picker
                 this.show();
+            }
             return;
         }
         
@@ -16632,7 +17087,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 break;
             case 37: // left
             case 39: // right
-                if (!this.keyboardNavigation) break;
+                if (!this.keyboardNavigation) {
+                    break;
+                }
                 dir = e.keyCode == 37 ? -1 : 1;
                 
                 if (e.ctrlKey){
@@ -16658,7 +17115,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 break;
             case 38: // up
             case 40: // down
-                if (!this.keyboardNavigation) break;
+                if (!this.keyboardNavigation) {
+                    break;
+                }
                 dir = e.keyCode == 38 ? -1 : 1;
                 if (e.ctrlKey){
                     newDate = this.moveYear(this.date, dir);
@@ -16885,7 +17344,9 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
     
     moveMonth: function(date, dir)
     {
-        if (!dir) return date;
+        if (!dir) {
+            return date;
+        }
         var new_date = new Date(date.valueOf()),
         day = new_date.getUTCDate(),
         month = new_date.getUTCMonth(),
@@ -16907,13 +17368,15 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
             new_month = month + dir;
             new_date.setUTCMonth(new_month);
             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
-            if (new_month < 0 || new_month > 11)
+            if (new_month < 0 || new_month > 11) {
                 new_month = (new_month + 12) % 12;
+            }
         } else {
             // For magnitudes >1, move one month at a time...
-            for (var i=0; i<mag; i++)
+            for (var i=0; i<mag; i++) {
                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
                 new_date = this.moveMonth(new_date, dir);
+            }
             // ...then reset the day, keeping it in the new month
             new_month = new_date.getUTCMonth();
             new_date.setUTCDate(day);
@@ -17757,7 +18220,7 @@ Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
                 tag: 'span',
                 cls: 'month',
                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
-            }
+            };
             
             months.createChild(month);
         }
@@ -17783,7 +18246,9 @@ Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
     
     place: function()
     {
-        if(this.isInline) return;
+        if(this.isInline) {
+            return;
+        }
         
         this.picker().removeClass(['bottom', 'top']);
         
@@ -17833,7 +18298,9 @@ Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
     
     hide : function()
     {
-        if(this.isInline) return;
+        if(this.isInline) {
+            return;
+        }
         this.picker().hide();
         this.fireEvent('hide', this, this.date);
         
@@ -17854,8 +18321,9 @@ Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
     fireKey: function(e)
     {
         if (!this.picker().isVisible()){
-            if (e.keyCode == 27) // allow escape to hide and re-show picker
+            if (e.keyCode == 27)   {// allow escape to hide and re-show picker
                 this.show();
+            }
             return;
         }
         
@@ -18172,7 +18640,7 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
                 //'for': id, // box label is handled by onclick - so no for...
                 cls: 'box-label',
                 html: this.boxLabel
-            }
+            };
             
             if(this.tooltip){
                 boxLabelCfg.tooltip = this.tooltip;
@@ -18386,6 +18854,16 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
         
         this.fireEvent('valid', this);
         
+        var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
+        
+        if(this.groupId){
+            label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
+        }
+        
+        if(label){
+            label.markValid();
+        }
+        
         if(this.inputType == 'radio'){
             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
@@ -18427,6 +18905,16 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
         
         this.fireEvent('invalid', this, msg);
         
+        var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
+        
+        if(this.groupId){
+            label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
+        }
+        
+        if(label){
+            label.markInvalid();
+        }
+            
         if(this.inputType == 'radio'){
             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
@@ -18443,7 +18931,7 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
         }
         
         var group = Roo.bootstrap.CheckBox.get(this.groupId);
-            
+        
         if(!group){
             return;
         }
@@ -18680,7 +19168,7 @@ Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
         
         this.inputEl().on('click', this.onClick,  this);
         if (this.boxLabel) {
-            Roo.log('find label')
+            //Roo.log('find label');
             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
         }
         
@@ -19679,13 +20167,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         var nodeIsBefore   =  ss == 1;
         var nodeIsAfter    = ee == -1;
         
-        if (nodeIsBefore && nodeIsAfter)
+        if (nodeIsBefore && nodeIsAfter) {
             return 0; // outer
-        if (!nodeIsBefore && nodeIsAfter)
+        }
+        if (!nodeIsBefore && nodeIsAfter) {
             return 1; //right trailed.
+        }
         
-        if (nodeIsBefore && !nodeIsAfter)
+        if (nodeIsBefore && !nodeIsAfter) {
             return 2;  // left trailed.
+        }
         // fully contined.
         return 3;
     },
@@ -21374,7 +21865,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * Clears all selections.
      */
     clearSelections : function(fast){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(fast !== true){
             var ds = this.grid.dataSource;
             var s = this.selections;
@@ -21393,7 +21886,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * Selects all rows.
      */
     selectAll : function(){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         this.selections.clear();
         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
             this.selectRow(i, true);
@@ -21482,7 +21977,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * @param {Boolean} keepExisting (optional) True to retain existing selections
      */
     selectRange : function(startRow, endRow, keepExisting){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(!keepExisting){
             this.clearSelections();
         }
@@ -21503,7 +22000,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * @param {Number} endRow The index of the last row in the range
      */
     deselectRange : function(startRow, endRow, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         for(var i = startRow; i <= endRow; i++){
             this.deselectRow(i, preventViewNotify);
         }
@@ -21515,7 +22014,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
     selectRow : function(index, keepExisting, preventViewNotify){
-        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
+        if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
+            return;
+        }
         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
             if(!keepExisting || this.singleSelect){
                 this.clearSelections();
@@ -21536,7 +22037,9 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
      * @param {Number} row The index of the row to deselect
      */
     deselectRow : function(index, preventViewNotify){
-        if(this.locked) return;
+        if(this.locked) {
+            return;
+        }
         if(this.last == index){
             this.last = false;
         }
@@ -21603,28 +22106,37 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
  
 /**
  * @class Roo.bootstrap.PagingToolbar
- * @extends Roo.Row
+ * @extends Roo.bootstrap.NavSimplebar
  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
  * @constructor
  * Create a new PagingToolbar
  * @param {Object} config The config object
+ * @param {Roo.data.Store} store
  */
 Roo.bootstrap.PagingToolbar = function(config)
 {
     // old args format still supported... - xtype is prefered..
         // created from xtype...
-    var ds = config.dataSource;
+    
+    this.ds = config.dataSource;
+    
+    if (config.store && !this.ds) {
+        this.store= Roo.factory(config.store, Roo.data);
+        this.ds = this.store;
+        this.ds.xmodule = this.xmodule || false;
+    }
+    
     this.toolbarItems = [];
     if (config.items) {
         this.toolbarItems = config.items;
-//        config.items = [];
     }
     
     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
-    this.ds = ds;
+    
     this.cursor = 0;
-    if (ds) { 
-        this.bind(ds);
+    
+    if (this.ds) { 
+        this.bind(this.ds);
     }
     
     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
@@ -21715,7 +22227,7 @@ Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
         var _this = this;
         
         if(this.buttons){
-            Roo.each(_this.buttons, function(e){
+            Roo.each(_this.buttons, function(e){ // this might need to use render????
                Roo.factory(e).onRender(_this.el, null);
             });
         }
@@ -21785,7 +22297,7 @@ Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
             preventDefault: true,
             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
         });
-
+        
     },
 
     // private
@@ -21859,8 +22371,9 @@ Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
         {
           var v = this.field.dom.value, pageNum; 
           var increment = (e.shiftKey) ? 10 : 1;
-          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
-            increment *= -1;
+          if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
+                increment *= -1;
+          }
           if(!v || isNaN(pageNum = parseInt(v, 10))) {
             this.field.dom.value = d.activePage;
             return;
@@ -21983,7 +22496,7 @@ Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
                     html: this.html || ''
                 }
             ]
-        }
+        };
         
         if(this.fixed){
             cfg.cls += ' alert-messages-fixed';
@@ -22146,7 +22659,7 @@ Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
         var cfg = {
             tag: 'div',
             html : null
-        }
+        };
         
         
         return  cfg;
@@ -22328,7 +22841,7 @@ Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
                     ]
                 }
             ]
-        }
+        };
         
         if(this.icon){
             cfg.cn.push({
@@ -22489,7 +23002,7 @@ Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
                         ]
                     }
                 ]
-            }
+            };
         }
         
         var cfg = {
@@ -22503,7 +23016,7 @@ Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
                     cn: []
                 }
             ]
-        }
+        };
 
         return  cfg;
     },
@@ -22643,7 +23156,7 @@ Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
         var cfg = {
             tag: 'div',
             cls: 'tab-pane'
-        }
+        };
         
         if(this.active){
             cfg.cls += ' active';
@@ -23144,10 +23657,8 @@ Roo.apply(Roo.bootstrap.Tooltip, {
 
         }
         
-        
-        
         if (this.currentTip.el) {
-            this.currentTip.el.hide(); // force hiding...
+            this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
         }    
         //Roo.log(ev);
         var bindEl = el;
@@ -23316,7 +23827,6 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
         //this.el.setXY([0,0]);
         this.el.show();
         //this.el.dom.style.display='block';
-        this.el.addClass(placement);
         
         //this.el.appendTo(on_el);
         
@@ -23326,12 +23836,31 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
         if (autoPlace) {
             // fixme..
         }
+        
         var align = Roo.bootstrap.Tooltip.alignment[placement];
+        
+        var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
+        
+        if(placement == 'top' || placement == 'bottom'){
+            if(xy[0] < 0){
+                placement = 'right';
+            }
+            
+            if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
+                placement = 'left';
+            }
+        }
+        
+        align = Roo.bootstrap.Tooltip.alignment[placement];
+        
         this.el.alignTo(this.bindEl, align[0],align[1]);
         //var arrow = this.el.select('.arrow',true).first();
         //arrow.set(align[2], 
         
+        this.el.addClass(placement);
+        
         this.el.addClass('in fade');
+        
         this.hoverState = null;
         
         if (this.el.hasClass('fade')) {
@@ -23481,7 +24010,13 @@ Roo.bootstrap.LocationPicker = function(config){
          * Fires when OverlayView Draw
          * @param {Roo.bootstrap.LocationPicker} this
          */
-        OverlayViewHide : true
+        OverlayViewHide : true,
+        /**
+         * @event loadexception
+         * Fires when load google lib failed.
+         * @param {Roo.bootstrap.LocationPicker} this
+         */
+        loadexception : true
     });
         
 };
@@ -23529,6 +24064,11 @@ Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
     
     initial: function()
     {
+        if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
+            this.fireEvent('loadexception', this);
+            return;
+        }
+        
         if(!this.mapTypeId){
             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
         }
@@ -23616,7 +24156,7 @@ Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
     
     getGmapContext: function() 
     {
-        return this.gMapContext
+        return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
     },
     
     GMapContext: function() 
@@ -23926,7 +24466,7 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
         }
         
-        this.faicon = icon
+        this.faicon = icon;
         
         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
     },
@@ -23953,9 +24493,17 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
  * @extends Roo.bootstrap.Component
  * Bootstrap UploadCropbox class
  * @cfg {String} emptyText show when image has been loaded
+ * @cfg {String} rotateNotify show when image too small to rotate
+ * @cfg {Number} errorTimeout default 3000
  * @cfg {Number} minWidth default 300
  * @cfg {Number} minHeight default 300
  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
+ * @cfg {Boolean} isDocument (true|false) default false
+ * @cfg {String} url action url
+ * @cfg {String} paramName default 'imageUpload'
+ * @cfg {String} method default POST
+ * @cfg {Boolean} loadMask (true|false) default true
+ * @cfg {Boolean} loadingText default 'Loading...'
  * 
  * @constructor
  * Create a new UploadCropbox
@@ -23996,7 +24544,7 @@ Roo.bootstrap.UploadCropbox = function(config){
          * @event exception
          * Fire when get exception
          * @param {Roo.bootstrap.UploadCropbox} this
-         * @param {Object} options
+         * @param {XMLHttpRequest} xhr
          */
         "exception" : true,
         /**
@@ -24030,8 +24578,35 @@ Roo.bootstrap.UploadCropbox = function(config){
          * Fire when resize
          * @param {Roo.bootstrap.UploadCropbox} this
          */
-        "resize" : true
-        
+        "resize" : true,
+        /**
+         * @event rotate
+         * Fire when rotate the image
+         * @param {Roo.bootstrap.UploadCropbox} this
+         * @param {String} pos
+         */
+        "rotate" : true,
+        /**
+         * @event inspect
+         * Fire when inspect the file
+         * @param {Roo.bootstrap.UploadCropbox} this
+         * @param {Object} file
+         */
+        "inspect" : true,
+        /**
+         * @event upload
+         * Fire when xhr upload the file
+         * @param {Roo.bootstrap.UploadCropbox} this
+         * @param {Object} data
+         */
+        "upload" : true,
+        /**
+         * @event arrange
+         * Fire when arrange the file data
+         * @param {Roo.bootstrap.UploadCropbox} this
+         * @param {Object} formData
+         */
+        "arrange" : true
     });
     
     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
@@ -24040,6 +24615,8 @@ Roo.bootstrap.UploadCropbox = function(config){
 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     
     emptyText : 'Click to upload image',
+    rotateNotify : 'Image is too small to rotate',
+    errorTimeout : 3000,
     scale : 0,
     baseScale : 1,
     rotate : 0,
@@ -24056,6 +24633,12 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     cropType : 'image/jpeg',
     buttons : false,
     canvasLoaded : false,
+    isDocument : false,
+    method : 'POST',
+    paramName : 'imageUpload',
+    loadMask : true,
+    loadingText : 'Loading...',
+    maskEl : false,
     
     getAutoCreate : function()
     {
@@ -24063,6 +24646,11 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
             tag : 'div',
             cls : 'roo-upload-cropbox',
             cn : [
+                {
+                    tag : 'input',
+                    cls : 'roo-upload-cropbox-selector',
+                    type : 'file'
+                },
                 {
                     tag : 'div',
                     cls : 'roo-upload-cropbox-body',
@@ -24079,8 +24667,12 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
                         {
                             tag : 'div',
                             cls : 'roo-upload-cropbox-empty-notify',
-                            style : 'cursor:pointer',
                             html : this.emptyText
+                        },
+                        {
+                            tag : 'div',
+                            cls : 'roo-upload-cropbox-error-notify alert alert-danger',
+                            html : this.rotateNotify
                         }
                     ]
                 },
@@ -24113,6 +24705,10 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
                 
             }, this);
         }
+        
+        if(this.loadMask){
+            this.maskEl = this.el;
+        }
     },
     
     initEvents : function()
@@ -24124,6 +24720,9 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
+        this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
+        this.selectorEl.hide();
+        
         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
@@ -24134,6 +24733,10 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
+        this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
+        this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.errorEl.hide();
+        
         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         this.footerEl.hide();
@@ -24168,6 +24771,8 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
             Roo.get(document).on('mouseup', this.onMouseUp, this);
         }
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
     },
     
     reset : function()
@@ -24183,6 +24788,8 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         this.cropData = false;
         this.notifyEl.dom.innerHTML = this.emptyText;
         
+        this.selectorEl.dom.value = '';
+        
     },
     
     resize : function()
@@ -24223,7 +24830,27 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     
     beforeSelectFile : function(e)
     {
-        this.fireEvent('beforeselectfile', this);
+        e.preventDefault();
+        
+        if(this.fireEvent('beforeselectfile', this) != false){
+            this.selectorEl.dom.click();
+        }
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        
+        var file = this.selectorEl.dom.files[0];
+        
+        if(this.fireEvent('inspect', this, file) != false){
+            this.prepare(file);
+        }
+        
     },
     
     trash : function(e)
@@ -24254,17 +24881,23 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     
     onLoadCanvas : function()
     {   
+        this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
+        this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
+        
         this.bodyEl.un('click', this.beforeSelectFile, this);
         
         this.notifyEl.hide();
         this.thumbEl.show();
         this.footerEl.show();
         
-        this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
-        this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
+        this.baseRotateLevel();
+        
+        if(this.isDocument){
+            this.setThumbBoxSize();
+        }
         
         this.setThumbBoxPosition();
-        this.baseRotateLevel();
+        
         this.baseScaleLevel();
         
         this.draw();
@@ -24273,6 +24906,10 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         
         this.canvasLoaded = true;
         
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
     },
     
     setCanvasPosition : function()
@@ -24286,6 +24923,7 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         
         this.previewEl.setLeft(pw);
         this.previewEl.setTop(ph);
+        
     },
     
     onMouseDown : function(e)
@@ -24295,6 +24933,11 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         this.dragable = true;
         this.pinching = false;
         
+        if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
+            this.dragable = false;
+            return;
+        }
+        
         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
         
@@ -24348,78 +24991,199 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     {   
         e.stopEvent();
         
+        this.startScale = this.scale;
+        
         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
         
-        var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel());
-        var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel());
+        if(!this.zoomable()){
+            this.scale = this.startScale;
+            return;
+        }
+        
+        this.draw();
+        
+        return;
+    },
+    
+    zoomable : function()
+    {
+        var minScale = this.thumbEl.getWidth() / this.minWidth;
+        
+        if(this.minWidth < this.minHeight){
+            minScale = this.thumbEl.getHeight() / this.minHeight;
+        }
+        
+        var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
+        var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
         
         if(
-                e.getWheelDelta() == -1 &&
+                this.isDocument &&
+                (this.rotate == 0 || this.rotate == 180) && 
                 (
-                    (
-                        (this.rotate == 0 || this.rotate == 180) && (width < this.thumbEl.getWidth() || height < this.thumbEl.getHeight())
-                    )
-                    ||
-                    (
-                        (this.rotate == 90 || this.rotate == 270) && (height < this.thumbEl.getWidth() || width < this.thumbEl.getHeight())
-                    )
+                    width > this.imageEl.OriginWidth || 
+                    height > this.imageEl.OriginHeight ||
+                    (width < this.minWidth && height < this.minHeight)
                 )
         ){
-            this.scale = (e.getWheelDelta() == 1) ? (this.scale - 1) : (this.scale + 1);
-            return;
+            return false;
+        }
+        
+        if(
+                this.isDocument &&
+                (this.rotate == 90 || this.rotate == 270) && 
+                (
+                    width > this.imageEl.OriginWidth || 
+                    height > this.imageEl.OriginHeight ||
+                    (width < this.minHeight && height < this.minWidth)
+                )
+        ){
+            return false;
         }
         
-        this.draw();
-    },
-    
-    onRotateLeft : function(e)
-    {   
         if(
+                !this.isDocument &&
+                (this.rotate == 0 || this.rotate == 180) && 
                 (
-                    (this.rotate == 0 || this.rotate == 180) 
-                    &&
-                    (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())
+                    width < this.minWidth || 
+                    width > this.imageEl.OriginWidth || 
+                    height < this.minHeight || 
+                    height > this.imageEl.OriginHeight
                 )
-                ||
+        ){
+            return false;
+        }
+        
+        if(
+                !this.isDocument &&
+                (this.rotate == 90 || this.rotate == 270) && 
                 (
-                    (this.rotate == 90 || this.rotate == 270) 
-                    &&
-                    (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())
+                    width < this.minHeight || 
+                    width > this.imageEl.OriginWidth || 
+                    height < this.minWidth || 
+                    height > this.imageEl.OriginHeight
                 )
-                
         ){
-            return;
+            return false;
+        }
+        
+        return true;
+        
+    },
+    
+    onRotateLeft : function(e)
+    {   
+        if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+            
+            var minScale = this.thumbEl.getWidth() / this.minWidth;
+            
+            var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+            var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
+            
+            this.startScale = this.scale;
+            
+            while (this.getScaleLevel() < minScale){
+            
+                this.scale = this.scale + 1;
+                
+                if(!this.zoomable()){
+                    break;
+                }
+                
+                if(
+                        Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+                        Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+                ){
+                    continue;
+                }
+                
+                this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
+
+                this.draw();
+                
+                return;
+            }
+            
+            this.scale = this.startScale;
+            
+            this.onRotateFail();
+            
+            return false;
         }
         
         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
 
+        if(this.isDocument){
+            this.setThumbBoxSize();
+            this.setThumbBoxPosition();
+            this.setCanvasPosition();
+        }
+        
         this.draw();
         
+        this.fireEvent('rotate', this, 'left');
+        
     },
     
     onRotateRight : function(e)
     {
-        if(
-                (
-                    (this.rotate == 0 || this.rotate == 180) 
-                    &&
-                    (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())
-                )
-                ||
-                (
-                    (this.rotate == 90 || this.rotate == 270) 
-                    &&
-                    (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())
-                )
+        if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+            
+            var minScale = this.thumbEl.getWidth() / this.minWidth;
+        
+            var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+            var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
+            
+            this.startScale = this.scale;
+            
+            while (this.getScaleLevel() < minScale){
+            
+                this.scale = this.scale + 1;
                 
-        ){
+                if(!this.zoomable()){
+                    break;
+                }
+                
+                if(
+                        Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+                        Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+                ){
+                    continue;
+                }
+                
+                this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
+
+                this.draw();
+                
+                return;
+            }
+            
+            this.scale = this.startScale;
+            
+            this.onRotateFail();
+            
             return false;
         }
         
         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
 
+        if(this.isDocument){
+            this.setThumbBoxSize();
+            this.setThumbBoxPosition();
+            this.setCanvasPosition();
+        }
+        
         this.draw();
         
+        this.fireEvent('rotate', this, 'right');
+    },
+    
+    onRotateFail : function()
+    {
+        this.errorEl.show(true);
+        
+        var _this = this;
+        
+        (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
     },
     
     draw : function()
@@ -24513,44 +25277,232 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         if(!this.canvasLoaded){
             return;
         }
-        var canvas = document.createElement("canvas");
-        
-        var context = canvas.getContext("2d");
-        
-        canvas.width = this.minWidth;
-        canvas.height = this.minHeight;
         
-        var cropWidth = this.thumbEl.getWidth();
-        var cropHeight = this.thumbEl.getHeight();
+        var imageCanvas = document.createElement("canvas");
         
-        var x = this.thumbEl.getLeft(true) - this.previewEl.getLeft(true);
-        var y = this.thumbEl.getTop(true) - this.previewEl.getTop(true);
-        
-        if(this.canvasEl.width - cropWidth < x){
-            x = this.canvasEl.width - cropWidth;
-        }
+        var imageContext = imageCanvas.getContext("2d");
         
-        if(this.canvasEl.height - cropHeight < y){
-            y = this.canvasEl.height - cropHeight;
-        }
+        imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
+        imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
         
-        x = x < 0 ? 0 : x;
-        y = y < 0 ? 0 : y;
+        var center = imageCanvas.width / 2;
         
-        context.drawImage(this.canvasEl, x, y, cropWidth, cropHeight, 0, 0, canvas.width, canvas.height);
+        imageContext.translate(center, center);
         
-        this.cropData = canvas.toDataURL(this.cropType);
+        imageContext.rotate(this.rotate * Math.PI / 180);
         
-        this.fireEvent('crop', this, this.cropData);
+        imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
         
-    },
-    
-    setThumbBoxSize : function()
-    {
-        var height = 300;
-        var width = Math.ceil(this.minWidth * height / this.minHeight);
+        var canvas = document.createElement("canvas");
         
-        if(this.minWidth > this.minHeight){
+        var context = canvas.getContext("2d");
+                
+        canvas.width = this.minWidth;
+        canvas.height = this.minHeight;
+
+        switch (this.rotate) {
+            case 0 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 90 : 
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+                
+                sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 180 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+
+                sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+                sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            case 270 :
+                
+                var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+                var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+                
+                var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+                var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+                
+                var targetWidth = this.minWidth - 2 * x;
+                var targetHeight = this.minHeight - 2 * y;
+                
+                var scale = 1;
+                
+                if((x == 0 && y == 0) || (x == 0 && y > 0)){
+                    scale = targetWidth / width;
+                }
+                
+                if(x > 0 && y == 0){
+                    scale = targetHeight / height;
+                }
+                
+                if(x > 0 && y > 0){
+                    scale = targetWidth / width;
+                    
+                    if(width < height){
+                        scale = targetHeight / height;
+                    }
+                }
+                
+                context.scale(scale, scale);
+                
+                var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+                var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+
+                sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+                sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+                
+                sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+                
+                context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+                
+                break;
+            default : 
+                break;
+        }
+        
+        this.cropData = canvas.toDataURL(this.cropType);
+        
+        if(this.fireEvent('crop', this, this.cropData) !== false){
+            this.process(this.file, this.cropData);
+        }
+        
+        return;
+        
+    },
+    
+    setThumbBoxSize : function()
+    {
+        var width, height;
+        
+        if(this.isDocument && typeof(this.imageEl) != 'undefined'){
+            width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
+            height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
+            
+            this.minWidth = width;
+            this.minHeight = height;
+            
+            if(this.rotate == 90 || this.rotate == 270){
+                this.minWidth = height;
+                this.minHeight = width;
+            }
+        }
+        
+        height = 300;
+        width = Math.ceil(this.minWidth * height / this.minHeight);
+        
+        if(this.minWidth > this.minHeight){
             width = 300;
             height = Math.ceil(this.minHeight * width / this.minWidth);
         }
@@ -24594,10 +25546,36 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
     {
         var width, height;
         
+        if(this.isDocument){
+            
+            if(this.baseRotate == 6 || this.baseRotate == 8){
+            
+                height = this.thumbEl.getHeight();
+                this.baseScale = height / this.imageEl.OriginWidth;
+
+                if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
+                    width = this.thumbEl.getWidth();
+                    this.baseScale = width / this.imageEl.OriginHeight;
+                }
+
+                return;
+            }
+
+            height = this.thumbEl.getHeight();
+            this.baseScale = height / this.imageEl.OriginHeight;
+
+            if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
+                width = this.thumbEl.getWidth();
+                this.baseScale = width / this.imageEl.OriginWidth;
+            }
+
+            return;
+        }
+        
         if(this.baseRotate == 6 || this.baseRotate == 8){
             
             width = this.thumbEl.getHeight();
-            this.baseScale = height / this.imageEl.OriginHeight;
+            this.baseScale = width / this.imageEl.OriginHeight;
             
             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
                 height = this.thumbEl.getWidth();
@@ -24625,7 +25603,6 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
             this.baseScale = height / this.imageEl.OriginHeight;
         }
         
-        
         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
             
             height = this.thumbEl.getHeight();
@@ -24714,28 +25691,13 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         
         this.endDistance = Math.sqrt(x + y);
         
-        var scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
+        this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
         
-        var width = Math.ceil(this.imageEl.OriginWidth * this.baseScale * Math.pow(1.1, scale));
-        var height = Math.ceil(this.imageEl.OriginHeight * this.baseScale * Math.pow(1.1, scale));
-        
-        if(
-                this.endDistance / this.startDistance < 1 &&
-                (
-                    (
-                        (this.rotate == 0 || this.rotate == 180) && (width < this.thumbEl.getWidth() || height < this.thumbEl.getHeight())
-                    )
-                    ||
-                    (
-                        (this.rotate == 90 || this.rotate == 270) && (height < this.thumbEl.getWidth() || width < this.thumbEl.getHeight())
-                    )
-                )
-        ){
+        if(!this.zoomable()){
+            this.scale = this.startScale;
             return;
         }
         
-        this.scale = scale;
-        
         this.draw();
         
     },
@@ -24747,22 +25709,126 @@ Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
         
     },
     
-    prepare : function(input)
-    {        
+    process : function(file, crop)
+    {
+        if(this.loadMask){
+            this.maskEl.mask(this.loadingText);
+        }
+        
+        this.xhr = new XMLHttpRequest();
+        
+        file.xhr = this.xhr;
+
+        this.xhr.open(this.method, this.url, true);
+        
+        var headers = {
+            "Accept": "application/json",
+            "Cache-Control": "no-cache",
+            "X-Requested-With": "XMLHttpRequest"
+        };
+        
+        for (var headerName in headers) {
+            var headerValue = headers[headerName];
+            if (headerValue) {
+                this.xhr.setRequestHeader(headerName, headerValue);
+            }
+        }
+        
+        var _this = this;
+        
+        this.xhr.onload = function()
+        {
+            _this.xhrOnLoad(_this.xhr);
+        }
+        
+        this.xhr.onerror = function()
+        {
+            _this.xhrOnError(_this.xhr);
+        }
+        
+        var formData = new FormData();
+
+        formData.append('returnHTML', 'NO');
+        
+        if(crop){
+            formData.append('crop', crop);
+        }
+        
+        if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
+            formData.append(this.paramName, file, file.name);
+        }
+        
+        if(typeof(file.filename) != 'undefined'){
+            formData.append('filename', file.filename);
+        }
+        
+        if(typeof(file.mimetype) != 'undefined'){
+            formData.append('mimetype', file.mimetype);
+        }
+        
+        if(this.fireEvent('arrange', this, formData) != false){
+            this.xhr.send(formData);
+        };
+    },
+    
+    xhrOnLoad : function(xhr)
+    {
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
+        if (xhr.readyState !== 4) {
+            this.fireEvent('exception', this, xhr);
+            return;
+        }
+
+        var response = Roo.decode(xhr.responseText);
+        
+        if(!response.success){
+            this.fireEvent('exception', this, xhr);
+            return;
+        }
+        
+        var response = Roo.decode(xhr.responseText);
+        
+        this.fireEvent('upload', this, response);
+        
+    },
+    
+    xhrOnError : function()
+    {
+        if(this.loadMask){
+            this.maskEl.unmask();
+        }
+        
+        Roo.log('xhr on error');
+        
+        var response = Roo.decode(xhr.responseText);
+          
+        Roo.log(response);
+        
+    },
+    
+    prepare : function(file)
+    {   
+        if(this.loadMask){
+            this.maskEl.mask(this.loadingText);
+        }
+        
         this.file = false;
         this.exif = {};
         
-        if(typeof(input) === 'string'){
-            this.loadCanvas(input);
+        if(typeof(file) === 'string'){
+            this.loadCanvas(file);
             return;
         }
         
-        if(!input.files || !input.files[0] || !this.urlAPI){
+        if(!file || !this.urlAPI){
             return;
         }
         
-        this.file = input.files[0];
-        this.cropType = this.file.type;
+        this.file = file;
+        this.cropType = file.type;
         
         var _this = this;
         
@@ -25140,6 +26206,32 @@ Roo.apply(Roo.bootstrap.UploadCropbox, {
                     }
                 ]
             }
+        ],
+        ROTATOR : [
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-left',
+                action : 'rotate-left',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-undo"></i>'
+                    }
+                ]
+            },
+            {
+                tag : 'div',
+                cls : 'btn-group roo-upload-cropbox-rotate-right',
+                action : 'rotate-right',
+                cn : [
+                    {
+                        tag : 'button',
+                        cls : 'btn btn-default',
+                        html : '<i class="fa fa-repeat"></i>'
+                    }
+                ]
+            }
         ]
     }
 });
@@ -25155,14 +26247,13 @@ Roo.apply(Roo.bootstrap.UploadCropbox, {
  * @cfg {String} paramName default 'imageUpload'
  * @cfg {String} method default POST
  * @cfg {String} url action url
- * @cfg {Number} boxes number of boxes default 12
+ * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
  * @cfg {Boolean} multiple multiple upload default true
- * @cfg {Number} minWidth default 300
- * @cfg {Number} minHeight default 300
  * @cfg {Number} thumbSize default 300
  * @cfg {String} fieldLabel
  * @cfg {Number} labelWidth default 4
  * @cfg {String} labelAlign (left|top) default left
+ * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
  * 
  * @constructor
  * Create a new DocumentManager
@@ -25219,17 +26310,35 @@ Roo.bootstrap.DocumentManager = function(config){
          * @param {Roo.bootstrap.DocumentManager} this
          * @param {Object} file
          */
-        "click" : true
-        
-    });
-};
-
-Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
-    
-    boxes : 12,
-    inputName : '',
-    minWidth : 300,
-    minHeight : 300,
+        "click" : true,
+        /**
+         * @event edit
+         * Fire when upload a image and editable set to true
+         * @param {Roo.bootstrap.DocumentManager} this
+         * @param {Object} file
+         */
+        "edit" : true,
+        /**
+         * @event beforeselectfile
+         * Fire before select file
+         * @param {Roo.bootstrap.DocumentManager} this
+         */
+        "beforeselectfile" : true,
+        /**
+         * @event process
+         * Fire before process file
+         * @param {Roo.bootstrap.DocumentManager} this
+         * @param {Object} file
+         */
+        "process" : true
+        
+    });
+};
+
+Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
+    
+    boxes : 0,
+    inputName : '',
     thumbSize : 300,
     multiple : true,
     files : [],
@@ -25239,6 +26348,11 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
     fieldLabel : '',
     labelWidth : 4,
     labelAlign : 'left',
+    editable : true,
+    delegates : [],
+    
+    
+    xhr : false, 
     
     getAutoCreate : function()
     {   
@@ -25322,19 +26436,20 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
-        this.selectorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         this.selectorEl.hide();
         
         if(this.multiple){
             this.selectorEl.attr('multiple', 'multiple');
         }
         
-        this.selectorEl.on('change', this.onSelect, this);
+        this.selectorEl.on('change', this.onFileSelected, this);
         
         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
-        this.uploader.on('click', this.onUpload, this);
+        this.uploader.on('click', this.onUploaderClick, this);
+        
+        this.renderProgressDialog();
         
         var _this = this;
         
@@ -25343,15 +26458,61 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         this.fireEvent('initial', this);
     },
     
-    onUpload : function(e)
+    renderProgressDialog : function()
     {
-        e.preventDefault();
+        var _this = this;
+        
+        this.progressDialog = new Roo.bootstrap.Modal({
+            cls : 'roo-document-manager-progress-dialog',
+            allow_close : false,
+            title : '',
+            buttons : [
+                {
+                    name  :'cancel',
+                    weight : 'danger',
+                    html : 'Cancel'
+                }
+            ], 
+            listeners : { 
+                btnclick : function() {
+                    _this.uploadCancel();
+                    this.hide();
+                }
+            }
+        });
+         
+        this.progressDialog.render(Roo.get(document.body));
+         
+        this.progress = new Roo.bootstrap.Progress({
+            cls : 'roo-document-manager-progress',
+            active : true,
+            striped : true
+        });
+        
+        this.progress.render(this.progressDialog.getChildContainer());
         
-        this.selectorEl.dom.click();
+        this.progressBar = new Roo.bootstrap.ProgressBar({
+            cls : 'roo-document-manager-progress-bar',
+            aria_valuenow : 0,
+            aria_valuemin : 0,
+            aria_valuemax : 12,
+            panel : 'success'
+        });
+        
+        this.progressBar.render(this.progress.getChildContainer());
+    },
+    
+    onUploaderClick : function(e)
+    {
+        e.preventDefault();
+     
+        if(this.fireEvent('beforeselectfile', this) != false){
+            this.selectorEl.dom.click();
+        }
         
     },
     
-    onSelect : function(e)
+    onFileSelected : function(e)
     {
         e.preventDefault();
         
@@ -25365,11 +26526,11 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
             }
         }, this);
         
-        this.process();
+        this.queue();
         
     },
     
-    process : function()
+    queue : function()
     {
         this.selectorEl.dom.value = '';
         
@@ -25377,154 +26538,88 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
             return;
         }
         
-        if(this.files.length > this.boxes){
+        if(this.boxes > 0 && this.files.length > this.boxes){
             this.files = this.files.slice(0, this.boxes);
         }
         
-        var xhr = new XMLHttpRequest();
-        
-        Roo.each(this.files, function(file, index){
-            if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
-                return;
-            }
-            
-            file.xhr = xhr;
-            
-            this.managerEl.createChild({
-                tag : 'div',
-                cls : 'roo-document-manager-loading',
-                cn : [
-                    {
-                        tag : 'div',
-                        tooltip : file.name,
-                        cls : 'roo-document-manager-thumb',
-                        html : '<i class="fa fa-spinner fa-pulse"></i>'
-                    }
-                ]
-
-            });
-            
-        }, this);
+        this.uploader.show();
         
-        if(this.files.length > this.boxes - 1 ){
+        if(this.boxes > 0 && this.files.length > this.boxes - 1){
             this.uploader.hide();
         }
         
-        var headers = {
-            "Accept": "application/json",
-            "Cache-Control": "no-cache",
-            "X-Requested-With": "XMLHttpRequest"
-        };
-        
-        xhr.open(this.method, this.url, true);
-        
-        for (var headerName in headers) {
-            var headerValue = headers[headerName];
-            if (headerValue) {
-                xhr.setRequestHeader(headerName, headerValue);
-            }
-        }
-        
         var _this = this;
         
-        xhr.onload = function()
-        {
-            _this.xhrOnLoad(xhr);
-        }
-        
-        xhr.onerror = function()
-        {
-            _this.xhrOnError(xhr);
-        }
+        var files = [];
         
-        var formData = new FormData();
-
-        formData.append('returnHTML', 'NO');
+        var docs = [];
         
-        Roo.each(this.files, function(file, index){
+        Roo.each(this.files, function(file){
             
             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
+                var f = this.renderPreview(file);
+                files.push(f);
                 return;
             }
             
-            formData.append(this.getParamName(index), file, file.name);
+            if(file.type.indexOf('image') != -1){
+                this.delegates.push(
+                    (function(){
+                        _this.process(file);
+                    }).createDelegate(this)
+                );
+        
+                return;
+            }
+            
+            docs.push(
+                (function(){
+                    _this.process(file);
+                }).createDelegate(this)
+            );
             
         }, this);
         
-        if(this.fireEvent('prepare', this, formData) != false){
-            xhr.send(formData);
-        };
+        this.files = files;
         
-    },
-    
-    getParamName : function(i)
-    {
-        if(!this.multiple){
-            return this.paramName;
+        this.delegates = this.delegates.concat(docs);
+        
+        if(!this.delegates.length){
+            this.refresh();
+            return;
         }
         
-        return this.paramName + "_" + i;
+        this.progressBar.aria_valuemax = this.delegates.length;
+        
+        this.arrange();
+        
+        return;
     },
     
-    refresh : function()
+    arrange : function()
     {
-        Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
-            el.remove();
-        }, this);
+        if(!this.delegates.length){
+            this.progressDialog.hide();
+            this.refresh();
+            return;
+        }
         
+        var delegate = this.delegates.shift();
         
-        var files = [];
+        this.progressDialog.show();
         
-        Roo.each(this.files, function(file){
-            
-            if(typeof(file.id) == 'undefined' || file.id * 1 < 1){
-                return;
-            }
-            
-            if(file.target){
-                files.push(file);
-                return;
-            }
-            
-            var previewEl = this.managerEl.createChild({
-                tag : 'div',
-                cls : 'roo-document-manager-preview',
-                cn : [
-                    {
-                        tag : 'div',
-                        tooltip : file.filename,
-                        cls : 'roo-document-manager-thumb',
-                        html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
-                    },
-                    {
-                        tag : 'button',
-                        cls : 'close',
-                        html : 'x'
-                    }
-                ]
-            });
-            
-            var close = previewEl.select('button.close', true).first();
-            
-            close.on('click', this.onRemove, this, file);
-            
-            file.target = previewEl;
-            
-            var image = previewEl.select('img', true).first();
-            
-            image.on('click', this.onClick, this, file);
-            
-            files.push(file);
-            
-            return;
-            
-        }, this);
+        this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
         
-        this.files = files;
+        this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
         
+        delegate();
+    },
+    
+    refresh : function()
+    {
         this.uploader.show();
         
-        if(this.files.length > this.boxes - 1){
+        if(this.boxes > 0 && this.files.length > this.boxes - 1){
             this.uploader.hide();
         }
         
@@ -25560,6 +26655,22 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         this.refresh();
     },
     
+    clear : function()
+    {
+        Roo.each(this.files, function(file){
+            if(!file.target){
+                return;
+            }
+            
+            file.target.remove();
+
+        }, this);
+        
+        this.files = [];
+        
+        this.refresh();
+    },
+    
     onClick : function(e, el, o)
     {
         e.preventDefault();
@@ -25586,8 +26697,12 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
     
     xhrOnLoad : function(xhr)
     {
+        Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
+            el.remove();
+        }, this);
+        
         if (xhr.readyState !== 4) {
-            this.refresh();
+            this.arrange();
             this.fireEvent('exception', this, xhr);
             return;
         }
@@ -25595,27 +26710,16 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         var response = Roo.decode(xhr.responseText);
         
         if(!response.success){
-            this.refresh();
+            this.arrange();
             this.fireEvent('exception', this, xhr);
             return;
         }
         
-        var i = 0;
+        var file = this.renderPreview(response.data);
         
-        Roo.each(this.files, function(file, index){
-            
-            if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
-                return;
-            }
-            
-            this.files[index] = response.data[i];
-            i++;
-            
-            return;
-            
-        }, this);
+        this.files.push(file);
         
-        this.refresh();
+        this.arrange();
         
     },
     
@@ -25626,79 +26730,302 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         var response = Roo.decode(xhr.responseText);
           
         Roo.log(response);
-    }
-    
-    
+        
+        this.arrange();
+    },
     
-});
-/*
-* Licence: LGPL
-*/
+    process : function(file)
+    {
+        if(this.fireEvent('process', this, file) !== false){
+            if(this.editable && file.type.indexOf('image') != -1){
+                this.fireEvent('edit', this, file);
+                return;
+            }
 
-/**
- * @class Roo.bootstrap.DocumentViewer
- * @extends Roo.bootstrap.Component
- * Bootstrap DocumentViewer class
- * 
- * @constructor
- * Create a new DocumentViewer
- * @param {Object} config The config object
- */
+            this.uploadStart(file, false);
 
-Roo.bootstrap.DocumentViewer = function(config){
-    Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        /**
-         * @event initial
-         * Fire after initEvent
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "initial" : true,
-        /**
-         * @event click
-         * Fire after click
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "click" : true,
-        /**
-         * @event trash
-         * Fire after trash button
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "trash" : true
+            return;
+        }
         
-    });
-};
-
-Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
+    },
     
-    getAutoCreate : function()
+    uploadStart : function(file, crop)
     {
-        var cfg = {
+        this.xhr = new XMLHttpRequest();
+        
+        if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
+            this.arrange();
+            return;
+        }
+        
+        file.xhr = this.xhr;
+            
+        this.managerEl.createChild({
             tag : 'div',
-            cls : 'roo-document-viewer',
+            cls : 'roo-document-manager-loading',
             cn : [
                 {
                     tag : 'div',
-                    cls : 'roo-document-viewer-body',
-                    cn : [
-                        {
-                            tag : 'div',
-                            cls : 'roo-document-viewer-thumb',
-                            cn : [
-                                {
-                                    tag : 'img',
-                                    cls : 'roo-document-viewer-image'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    tag : 'div',
-                    cls : 'roo-document-viewer-footer',
-                    cn : {
+                    tooltip : file.name,
+                    cls : 'roo-document-manager-thumb',
+                    html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
+                }
+            ]
+
+        });
+
+        this.xhr.open(this.method, this.url, true);
+        
+        var headers = {
+            "Accept": "application/json",
+            "Cache-Control": "no-cache",
+            "X-Requested-With": "XMLHttpRequest"
+        };
+        
+        for (var headerName in headers) {
+            var headerValue = headers[headerName];
+            if (headerValue) {
+                this.xhr.setRequestHeader(headerName, headerValue);
+            }
+        }
+        
+        var _this = this;
+        
+        this.xhr.onload = function()
+        {
+            _this.xhrOnLoad(_this.xhr);
+        }
+        
+        this.xhr.onerror = function()
+        {
+            _this.xhrOnError(_this.xhr);
+        }
+        
+        var formData = new FormData();
+
+        formData.append('returnHTML', 'NO');
+        
+        if(crop){
+            formData.append('crop', crop);
+        }
+        
+        formData.append(this.paramName, file, file.name);
+        
+        if(this.fireEvent('prepare', this, formData) != false){
+            this.xhr.send(formData);
+        };
+    },
+    
+    uploadCancel : function()
+    {
+        if (this.xhr) {
+            this.xhr.abort();
+        }
+        
+        
+        this.delegates = [];
+        
+        Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
+            el.remove();
+        }, this);
+        
+        this.arrange();
+    },
+    
+    renderPreview : function(file)
+    {
+        if(typeof(file.target) != 'undefined' && file.target){
+            return file;
+        }
+        
+        var previewEl = this.managerEl.createChild({
+            tag : 'div',
+            cls : 'roo-document-manager-preview',
+            cn : [
+                {
+                    tag : 'div',
+                    tooltip : file.filename,
+                    cls : 'roo-document-manager-thumb',
+                    html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
+                },
+                {
+                    tag : 'button',
+                    cls : 'close',
+                    html : '<i class="fa fa-times-circle"></i>'
+                }
+            ]
+        });
+
+        var close = previewEl.select('button.close', true).first();
+
+        close.on('click', this.onRemove, this, file);
+
+        file.target = previewEl;
+
+        var image = previewEl.select('img', true).first();
+        
+        var _this = this;
+        
+        image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
+        
+        image.on('click', this.onClick, this, file);
+        
+        return file;
+        
+    },
+    
+    onPreviewLoad : function(file, image)
+    {
+        if(typeof(file.target) == 'undefined' || !file.target){
+            return;
+        }
+        
+        var width = image.dom.naturalWidth || image.dom.width;
+        var height = image.dom.naturalHeight || image.dom.height;
+        
+        if(width > height){
+            file.target.addClass('wide');
+            return;
+        }
+        
+        file.target.addClass('tall');
+        return;
+        
+    },
+    
+    uploadFromSource : function(file, crop)
+    {
+        this.xhr = new XMLHttpRequest();
+        
+        this.managerEl.createChild({
+            tag : 'div',
+            cls : 'roo-document-manager-loading',
+            cn : [
+                {
+                    tag : 'div',
+                    tooltip : file.name,
+                    cls : 'roo-document-manager-thumb',
+                    html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
+                }
+            ]
+
+        });
+
+        this.xhr.open(this.method, this.url, true);
+        
+        var headers = {
+            "Accept": "application/json",
+            "Cache-Control": "no-cache",
+            "X-Requested-With": "XMLHttpRequest"
+        };
+        
+        for (var headerName in headers) {
+            var headerValue = headers[headerName];
+            if (headerValue) {
+                this.xhr.setRequestHeader(headerName, headerValue);
+            }
+        }
+        
+        var _this = this;
+        
+        this.xhr.onload = function()
+        {
+            _this.xhrOnLoad(_this.xhr);
+        }
+        
+        this.xhr.onerror = function()
+        {
+            _this.xhrOnError(_this.xhr);
+        }
+        
+        var formData = new FormData();
+
+        formData.append('returnHTML', 'NO');
+        
+        formData.append('crop', crop);
+        
+        if(typeof(file.filename) != 'undefined'){
+            formData.append('filename', file.filename);
+        }
+        
+        if(typeof(file.mimetype) != 'undefined'){
+            formData.append('mimetype', file.mimetype);
+        }
+        
+        if(this.fireEvent('prepare', this, formData) != false){
+            this.xhr.send(formData);
+        };
+    }
+});
+
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.bootstrap.DocumentViewer
+ * @extends Roo.bootstrap.Component
+ * Bootstrap DocumentViewer class
+ * 
+ * @constructor
+ * Create a new DocumentViewer
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.DocumentViewer = function(config){
+    Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        /**
+         * @event initial
+         * Fire after initEvent
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "initial" : true,
+        /**
+         * @event click
+         * Fire after click
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "click" : true,
+        /**
+         * @event trash
+         * Fire after trash button
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "trash" : true
+        
+    });
+};
+
+Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
+    
+    getAutoCreate : function()
+    {
+        var cfg = {
+            tag : 'div',
+            cls : 'roo-document-viewer',
+            cn : [
+                {
+                    tag : 'div',
+                    cls : 'roo-document-viewer-body',
+                    cn : [
+                        {
+                            tag : 'div',
+                            cls : 'roo-document-viewer-thumb',
+                            cn : [
+                                {
+                                    tag : 'img',
+                                    cls : 'roo-document-viewer-image'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-document-viewer-footer',
+                    cn : {
                         tag : 'div',
                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
                         cn : [
@@ -25770,3 +27097,941 @@ Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
     }
     
 });
+/*
+ * - LGPL
+ *
+ * nav progress bar
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.NavProgressBar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap NavProgressBar class
+ * 
+ * @constructor
+ * Create a new nav progress bar
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.NavProgressBar = function(config){
+    Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
+
+    this.bullets = this.bullets || [];
+   
+//    Roo.bootstrap.NavProgressBar.register(this);
+     this.addEvents({
+        /**
+            * @event changed
+            * Fires when the active item changes
+            * @param {Roo.bootstrap.NavProgressBar} this
+            * @param {Roo.bootstrap.NavProgressItem} selected The item selected
+            * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
+         */
+        'changed': true
+     });
+    
+};
+
+Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
+    
+    bullets : [],
+    barItems : [],
+    
+    getAutoCreate : function()
+    {
+        var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
+        
+        cfg = {
+            tag : 'div',
+            cls : 'roo-navigation-bar-group',
+            cn : [
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-top-bar'
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-bullets-bar',
+                    cn : [
+                        {
+                            tag : 'ul',
+                            cls : 'roo-navigation-bar'
+                        }
+                    ]
+                },
+                
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-bottom-bar'
+                }
+            ]
+            
+        };
+        
+        return cfg;
+        
+    },
+    
+    initEvents: function() 
+    {
+        
+    },
+    
+    onRender : function(ct, position) 
+    {
+        Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
+        
+        if(this.bullets.length){
+            Roo.each(this.bullets, function(b){
+               this.addItem(b);
+            }, this);
+        }
+        
+        this.format();
+        
+    },
+    
+    addItem : function(cfg)
+    {
+        var item = new Roo.bootstrap.NavProgressItem(cfg);
+        
+        item.parentId = this.id;
+        item.render(this.el.select('.roo-navigation-bar', true).first(), null);
+        
+        if(cfg.html){
+            var top = new Roo.bootstrap.Element({
+                tag : 'div',
+                cls : 'roo-navigation-bar-text'
+            });
+            
+            var bottom = new Roo.bootstrap.Element({
+                tag : 'div',
+                cls : 'roo-navigation-bar-text'
+            });
+            
+            top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
+            bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
+            
+            var topText = new Roo.bootstrap.Element({
+                tag : 'span',
+                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
+            });
+            
+            var bottomText = new Roo.bootstrap.Element({
+                tag : 'span',
+                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
+            });
+            
+            topText.onRender(top.el, null);
+            bottomText.onRender(bottom.el, null);
+            
+            item.topEl = top;
+            item.bottomEl = bottom;
+        }
+        
+        this.barItems.push(item);
+        
+        return item;
+    },
+    
+    getActive : function()
+    {
+        var active = false;
+        
+        Roo.each(this.barItems, function(v){
+            
+            if (!v.isActive()) {
+                return;
+            }
+            
+            active = v;
+            return false;
+            
+        });
+        
+        return active;
+    },
+    
+    setActiveItem : function(item)
+    {
+        var prev = false;
+        
+        Roo.each(this.barItems, function(v){
+            if (v.rid == item.rid) {
+                return ;
+            }
+            
+            if (v.isActive()) {
+                v.setActive(false);
+                prev = v;
+            }
+        });
+
+        item.setActive(true);
+        
+        this.fireEvent('changed', this, item, prev);
+    },
+    
+    getBarItem: function(rid)
+    {
+        var ret = false;
+        
+        Roo.each(this.barItems, function(e) {
+            if (e.rid != rid) {
+                return;
+            }
+            
+            ret =  e;
+            return false;
+        });
+        
+        return ret;
+    },
+    
+    indexOfItem : function(item)
+    {
+        var index = false;
+        
+        Roo.each(this.barItems, function(v, i){
+            
+            if (v.rid != item.rid) {
+                return;
+            }
+            
+            index = i;
+            return false
+        });
+        
+        return index;
+    },
+    
+    setActiveNext : function()
+    {
+        var i = this.indexOfItem(this.getActive());
+        
+        if (i > this.barItems.length) {
+            return;
+        }
+        
+        this.setActiveItem(this.barItems[i+1]);
+    },
+    
+    setActivePrev : function()
+    {
+        var i = this.indexOfItem(this.getActive());
+        
+        if (i  < 1) {
+            return;
+        }
+        
+        this.setActiveItem(this.barItems[i-1]);
+    },
+    
+    format : function()
+    {
+        if(!this.barItems.length){
+            return;
+        }
+     
+        var width = 100 / this.barItems.length;
+        
+        Roo.each(this.barItems, function(i){
+            i.el.setStyle('width', width + '%');
+            i.topEl.el.setStyle('width', width + '%');
+            i.bottomEl.el.setStyle('width', width + '%');
+        }, this);
+        
+    }
+    
+});
+/*
+ * - LGPL
+ *
+ * Nav Progress Item
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.NavProgressItem
+ * @extends Roo.bootstrap.Component
+ * Bootstrap NavProgressItem class
+ * @cfg {String} rid the reference id
+ * @cfg {Boolean} active (true|false) Is item active default false
+ * @cfg {Boolean} disabled (true|false) Is item active default false
+ * @cfg {String} html
+ * @cfg {String} position (top|bottom) text position default bottom
+ * @cfg {String} icon show icon instead of number
+ * 
+ * @constructor
+ * Create a new NavProgressItem
+ * @param {Object} config The config object
+ */
+Roo.bootstrap.NavProgressItem = function(config){
+    Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
+    this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * The raw click event for the entire grid.
+         * @param {Roo.bootstrap.NavProgressItem} this
+         * @param {Roo.EventObject} e
+         */
+        "click" : true
+    });
+   
+};
+
+Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
+    
+    rid : '',
+    active : false,
+    disabled : false,
+    html : '',
+    position : 'bottom',
+    icon : false,
+    
+    getAutoCreate : function()
+    {
+        var iconCls = 'roo-navigation-bar-item-icon';
+        
+        iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
+        
+        var cfg = {
+            tag: 'li',
+            cls: 'roo-navigation-bar-item',
+            cn : [
+                {
+                    tag : 'i',
+                    cls : iconCls
+                }
+            ]
+        };
+        
+        if(this.active){
+            cfg.cls += ' active';
+        }
+        if(this.disabled){
+            cfg.cls += ' disabled';
+        }
+        
+        return cfg;
+    },
+    
+    disable : function()
+    {
+        this.setDisabled(true);
+    },
+    
+    enable : function()
+    {
+        this.setDisabled(false);
+    },
+    
+    initEvents: function() 
+    {
+        this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
+        
+        this.iconEl.on('click', this.onClick, this);
+    },
+    
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        if(this.disabled){
+            return;
+        }
+        
+        if(this.fireEvent('click', this, e) === false){
+            return;
+        };
+        
+        this.parent().setActiveItem(this);
+    },
+    
+    isActive: function () 
+    {
+        return this.active;
+    },
+    
+    setActive : function(state)
+    {
+        if(this.active == state){
+            return;
+        }
+        
+        this.active = state;
+        
+        if (state) {
+            this.el.addClass('active');
+            return;
+        }
+        
+        this.el.removeClass('active');
+        
+        return;
+    },
+    
+    setDisabled : function(state)
+    {
+        if(this.disabled == state){
+            return;
+        }
+        
+        this.disabled = state;
+        
+        if (state) {
+            this.el.addClass('disabled');
+            return;
+        }
+        
+        this.el.removeClass('disabled');
+    },
+    
+    tooltipEl : function()
+    {
+        return this.el.select('.roo-navigation-bar-item-icon', true).first();;
+    }
+});
+
+ /*
+ * - LGPL
+ *
+ * FieldLabel
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.FieldLabel
+ * @extends Roo.bootstrap.Component
+ * Bootstrap FieldLabel class
+ * @cfg {String} html contents of the element
+ * @cfg {String} tag tag of the element default label
+ * @cfg {String} cls class of the element
+ * @cfg {String} target label target 
+ * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
+ * @cfg {String} invalidClass default "text-danger fa fa-lg fa-exclamation-triangle"
+ * @cfg {String} validClass default "text-success fa fa-lg fa-check"
+ * @cfg {String} iconTooltip default "This field is required"
+ * 
+ * @constructor
+ * Create a new FieldLabel
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.FieldLabel = function(config){
+    Roo.bootstrap.Element.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+            /**
+             * @event invalid
+             * Fires after the field has been marked as invalid.
+             * @param {Roo.form.FieldLabel} this
+             * @param {String} msg The validation message
+             */
+            invalid : true,
+            /**
+             * @event valid
+             * Fires after the field has been validated with no errors.
+             * @param {Roo.form.FieldLabel} this
+             */
+            valid : true
+        });
+};
+
+Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
+    
+    tag: 'label',
+    cls: '',
+    html: '',
+    target: '',
+    allowBlank : true,
+    invalidClass : 'text-danger fa fa-lg fa-exclamation-triangle',
+    validClass : 'text-success fa fa-lg fa-check',
+    iconTooltip : 'This field is required',
+    
+    getAutoCreate : function(){
+        
+        var cfg = {
+            tag : this.tag,
+            cls : 'roo-bootstrap-field-label ' + this.cls,
+            for : this.target,
+            cn : [
+                {
+                    tag : 'i',
+                    cls : '',
+                    tooltip : this.iconTooltip
+                },
+                {
+                    tag : 'span',
+                    html : this.html
+                }
+            ] 
+        };
+        
+        return cfg;
+    },
+    
+    initEvents: function() 
+    {
+        Roo.bootstrap.Element.superclass.initEvents.call(this);
+        
+        this.iconEl = this.el.select('i', true).first();
+        
+        this.iconEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
+        
+        Roo.bootstrap.FieldLabel.register(this);
+    },
+    
+    /**
+     * Mark this field as valid
+     */
+    markValid : function()
+    {
+        this.iconEl.show();
+        
+        this.iconEl.removeClass(this.invalidClass);
+        
+        this.iconEl.addClass(this.validClass);
+        
+        this.fireEvent('valid', this);
+    },
+    
+    /**
+     * Mark this field as invalid
+     * @param {String} msg The validation message
+     */
+    markInvalid : function(msg)
+    {
+        this.iconEl.show();
+        
+        this.iconEl.removeClass(this.validClass);
+        
+        this.iconEl.addClass(this.invalidClass);
+        
+        this.fireEvent('invalid', this, msg);
+    }
+    
+   
+});
+
+Roo.apply(Roo.bootstrap.FieldLabel, {
+    
+    groups: {},
+    
+     /**
+    * register a FieldLabel Group
+    * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
+    */
+    register : function(label)
+    {
+        if(this.groups.hasOwnProperty(label.target)){
+            return;
+        }
+     
+        this.groups[label.target] = label;
+       
+    },
+    /**
+    * fetch a FieldLabel Group based on the target
+    * @param {string} target
+    * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
+    */
+    get: function(target) {
+        if (typeof(this.groups[target]) == 'undefined') {
+            return false;
+        }
+        
+        return this.groups[target] ;
+    }
+});
+
+
+ /*
+ * - LGPL
+ *
+ * page DateSplitField.
+ * 
+ */
+
+
+/**
+ * @class Roo.bootstrap.DateSplitField
+ * @extends Roo.bootstrap.Component
+ * Bootstrap DateSplitField class
+ * @cfg {string} fieldLabel - the label associated
+ * @cfg {Number} labelWidth set the width of label (0-12)
+ * @cfg {String} labelAlign (top|left)
+ * @cfg {Boolean} dayAllowBlank (true|false) default false
+ * @cfg {Boolean} monthAllowBlank (true|false) default false
+ * @cfg {Boolean} yearAllowBlank (true|false) default false
+ * @cfg {string} dayPlaceholder 
+ * @cfg {string} monthPlaceholder
+ * @cfg {string} yearPlaceholder
+ * @cfg {string} dayFormat default 'd'
+ * @cfg {string} monthFormat default 'm'
+ * @cfg {string} yearFormat default 'Y'
+
+ *     
+ * @constructor
+ * Create a new DateSplitField
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.DateSplitField = function(config){
+    Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        // raw events
+         /**
+         * @event years
+         * getting the data of years
+         * @param {Roo.bootstrap.DateSplitField} this
+         * @param {Object} years
+         */
+        "years" : true,
+        /**
+         * @event days
+         * getting the data of days
+         * @param {Roo.bootstrap.DateSplitField} this
+         * @param {Object} days
+         */
+        "days" : true,
+        /**
+         * @event invalid
+         * Fires after the field has been marked as invalid.
+         * @param {Roo.form.Field} this
+         * @param {String} msg The validation message
+         */
+        invalid : true,
+       /**
+         * @event valid
+         * Fires after the field has been validated with no errors.
+         * @param {Roo.form.Field} this
+         */
+        valid : true
+    });
+};
+
+Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
+    
+    fieldLabel : '',
+    labelAlign : 'top',
+    labelWidth : 3,
+    dayAllowBlank : false,
+    monthAllowBlank : false,
+    yearAllowBlank : false,
+    dayPlaceholder : '',
+    monthPlaceholder : '',
+    yearPlaceholder : '',
+    dayFormat : 'd',
+    monthFormat : 'm',
+    yearFormat : 'Y',
+    isFormField : true,
+    
+    getAutoCreate : function()
+    {
+        var cfg = {
+            tag : 'div',
+            cls : 'row roo-date-split-field-group',
+            cn : [
+                {
+                    tag : 'input',
+                    type : 'hidden',
+                    cls : 'form-hidden-field roo-date-split-field-group-value',
+                    name : this.name
+                }
+            ]
+        };
+        
+        if(this.fieldLabel){
+            cfg.cn.push({
+                tag : 'div',
+                cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
+                cn : [
+                    {
+                        tag : 'label',
+                        html : this.fieldLabel
+                    }
+                ]
+            });
+        }
+        
+        Roo.each(['day', 'month', 'year'], function(t){
+            cfg.cn.push({
+                tag : 'div',
+                cls : 'column roo-date-split-field-' + t + ' col-md-' + ((this.labelAlign == 'top') ? '4' : ((12 - this.labelWidth) / 3))
+            });
+        }, this);
+        
+        return cfg;
+    },
+    
+    inputEl: function ()
+    {
+        return this.el.select('.roo-date-split-field-group-value', true).first();
+    },
+    
+    onRender : function(ct, position) 
+    {
+        var _this = this;
+        
+        Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
+        
+        this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
+        
+        this.dayField = new Roo.bootstrap.ComboBox({
+            allowBlank : this.dayAllowBlank,
+            alwaysQuery : true,
+            displayField : 'value',
+            editable : false,
+            fieldLabel : '',
+            forceSelection : true,
+            mode : 'local',
+            placeholder : this.dayPlaceholder,
+            selectOnFocus : true,
+            tpl : '<div class="select2-result"><b>{value}</b></div>',
+            triggerAction : 'all',
+            typeAhead : true,
+            valueField : 'value',
+            store : new Roo.data.SimpleStore({
+                data : (function() {    
+                    var days = [];
+                    _this.fireEvent('days', _this, days);
+                    return days;
+                })(),
+                fields : [ 'value' ]
+            }),
+            listeners : {
+                select : function (_self, record, index)
+                {
+                    _this.setValue(_this.getValue());
+                }
+            }
+        });
+
+        this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
+        
+        this.monthField = new Roo.bootstrap.MonthField({
+            after : '<i class=\"fa fa-calendar\"></i>',
+            allowBlank : this.monthAllowBlank,
+            placeholder : this.monthPlaceholder,
+            readOnly : true,
+            listeners : {
+                render : function (_self)
+                {
+                    this.el.select('span.input-group-addon', true).first().on('click', function(e){
+                        e.preventDefault();
+                        _self.focus();
+                    });
+                },
+                select : function (_self, oldvalue, newvalue)
+                {
+                    _this.setValue(_this.getValue());
+                }
+            }
+        });
+        
+        this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
+        
+        this.yearField = new Roo.bootstrap.ComboBox({
+            allowBlank : this.yearAllowBlank,
+            alwaysQuery : true,
+            displayField : 'value',
+            editable : false,
+            fieldLabel : '',
+            forceSelection : true,
+            mode : 'local',
+            placeholder : this.yearPlaceholder,
+            selectOnFocus : true,
+            tpl : '<div class="select2-result"><b>{value}</b></div>',
+            triggerAction : 'all',
+            typeAhead : true,
+            valueField : 'value',
+            store : new Roo.data.SimpleStore({
+                data : (function() {
+                    var years = [];
+                    _this.fireEvent('years', _this, years);
+                    return years;
+                })(),
+                fields : [ 'value' ]
+            }),
+            listeners : {
+                select : function (_self, record, index)
+                {
+                    _this.setValue(_this.getValue());
+                }
+            }
+        });
+
+        this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
+    },
+    
+    setValue : function(v, format)
+    {
+        this.inputEl.dom.value = v;
+        
+        var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
+        
+        var d = Date.parseDate(v, f);
+        
+        if(!d){
+            this.validate();
+            return;
+        }
+        
+        this.setDay(d.format(this.dayFormat));
+        this.setMonth(d.format(this.monthFormat));
+        this.setYear(d.format(this.yearFormat));
+        
+        this.validate();
+        
+        return;
+    },
+    
+    setDay : function(v)
+    {
+        this.dayField.setValue(v);
+        this.inputEl.dom.value = this.getValue();
+        this.validate();
+        return;
+    },
+    
+    setMonth : function(v)
+    {
+        this.monthField.setValue(v, true);
+        this.inputEl.dom.value = this.getValue();
+        this.validate();
+        return;
+    },
+    
+    setYear : function(v)
+    {
+        this.yearField.setValue(v);
+        this.inputEl.dom.value = this.getValue();
+        this.validate();
+        return;
+    },
+    
+    getDay : function()
+    {
+        return this.dayField.getValue();
+    },
+    
+    getMonth : function()
+    {
+        return this.monthField.getValue();
+    },
+    
+    getYear : function()
+    {
+        return this.yearField.getValue();
+    },
+    
+    getValue : function()
+    {
+        var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
+        
+        var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
+        
+        return date;
+    },
+    
+    reset : function()
+    {
+        this.setDay('');
+        this.setMonth('');
+        this.setYear('');
+        this.inputEl.dom.value = '';
+        this.validate();
+        return;
+    },
+    
+    validate : function()
+    {
+        var d = this.dayField.validate();
+        var m = this.monthField.validate();
+        var y = this.yearField.validate();
+        
+        var valid = true;
+        
+        if(
+                (!this.dayAllowBlank && !d) ||
+                (!this.monthAllowBlank && !m) ||
+                (!this.yearAllowBlank && !y)
+        ){
+            valid = false;
+        }
+        
+        if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
+            return valid;
+        }
+        
+        if(valid){
+            this.markValid();
+            return valid;
+        }
+        
+        this.markInvalid();
+        
+        return valid;
+    },
+    
+    markValid : function()
+    {
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+
+        if(label && icon){
+            icon.remove();
+        }
+        
+        this.fireEvent('valid', this);
+    },
+    
+     /**
+     * Mark this field as invalid
+     * @param {String} msg The validation message
+     */
+    markInvalid : function(msg)
+    {
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+
+        if(label && !icon){
+            this.el.select('.roo-date-split-field-label', true).createChild({
+                tag : 'i',
+                cls : 'text-danger fa fa-lg fa-star',
+                tooltip : 'This field is required',
+                style : 'margin-right:5px;'
+            }, label, true);
+        }
+        
+        this.fireEvent('invalid', this, msg);
+    },
+    
+    clearInvalid : function()
+    {
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+
+        if(label && icon){
+            icon.remove();
+        }
+        
+        this.fireEvent('valid', this);
+    },
+    
+    getName: function()
+    {
+        return this.name;
+    }
+    
+});
+
\ No newline at end of file