Roo/bootstrap/Tooltip.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
22  
23  * @constructor
24  * Do not use directly - it does not do anything..
25  * @param {Object} config The config object
26  */
27
28
29
30 Roo.bootstrap.Component = function(config){
31     Roo.bootstrap.Component.superclass.constructor.call(this, config);
32        
33     this.addEvents({
34         /**
35          * @event childrenrendered
36          * Fires when the children have been rendered..
37          * @param {Roo.bootstrap.Component} this
38          */
39         "childrenrendered" : true
40         
41         
42         
43     });
44     
45     
46 };
47
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
49     
50     
51     allowDomMove : false, // to stop relocations in parent onRender...
52     
53     cls : false,
54     
55     style : false,
56     
57     autoCreate : false,
58     
59     tooltip : null,
60     /**
61      * Initialize Events for the element
62      */
63     initEvents : function() { },
64     
65     xattr : false,
66     
67     parentId : false,
68     
69     can_build_overlaid : true,
70     
71     container_method : false,
72     
73     dataId : false,
74     
75     name : false,
76     
77     parent: function() {
78         // returns the parent component..
79         return Roo.ComponentMgr.get(this.parentId)
80         
81         
82     },
83     
84     // private
85     onRender : function(ct, position)
86     {
87        // Roo.log("Call onRender: " + this.xtype);
88         
89         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
90         
91         if(this.el){
92             if (this.el.attr('xtype')) {
93                 this.el.attr('xtypex', this.el.attr('xtype'));
94                 this.el.dom.removeAttribute('xtype');
95                 
96                 this.initEvents();
97             }
98             
99             return;
100         }
101         
102          
103         
104         var cfg = Roo.apply({},  this.getAutoCreate());
105         
106         cfg.id = this.id || Roo.id();
107         
108         // fill in the extra attributes 
109         if (this.xattr && typeof(this.xattr) =='object') {
110             for (var i in this.xattr) {
111                 cfg[i] = this.xattr[i];
112             }
113         }
114         
115         if(this.dataId){
116             cfg.dataId = this.dataId;
117         }
118         
119         if (this.cls) {
120             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121         }
122         
123         if (this.style) { // fixme needs to support more complex style data.
124             cfg.style = this.style;
125         }
126         
127         if(this.name){
128             cfg.name = this.name;
129         }
130         
131         this.el = ct.createChild(cfg, position);
132         
133         if (this.tooltip) {
134             this.tooltipEl().attr('tooltip', this.tooltip);
135         }
136         
137         if(this.tabIndex !== undefined){
138             this.el.dom.setAttribute('tabIndex', this.tabIndex);
139         }
140         
141         this.initEvents();
142         
143     },
144     /**
145      * Fetch the element to add children to
146      * @return {Roo.Element} defaults to this.el
147      */
148     getChildContainer : function()
149     {
150         return this.el;
151     },
152     /**
153      * Fetch the element to display the tooltip on.
154      * @return {Roo.Element} defaults to this.el
155      */
156     tooltipEl : function()
157     {
158         return this.el;
159     },
160         
161     addxtype  : function(tree,cntr)
162     {
163         var cn = this;
164         
165         cn = Roo.factory(tree);
166         //Roo.log(['addxtype', cn]);
167            
168         cn.parentType = this.xtype; //??
169         cn.parentId = this.id;
170         
171         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172         if (typeof(cn.container_method) == 'string') {
173             cntr = cn.container_method;
174         }
175         
176         
177         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
178         
179         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
180         
181         var build_from_html =  Roo.XComponent.build_from_html;
182           
183         var is_body  = (tree.xtype == 'Body') ;
184           
185         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186           
187         var self_cntr_el = Roo.get(this[cntr](false));
188         
189         // do not try and build conditional elements 
190         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191             return false;
192         }
193         
194         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196                 return this.addxtypeChild(tree,cntr, is_body);
197             }
198             
199             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
200                 
201             if(echild){
202                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
203             }
204             
205             Roo.log('skipping render');
206             return cn;
207             
208         }
209         
210         var ret = false;
211         if (!build_from_html) {
212             return false;
213         }
214         
215         // this i think handles overlaying multiple children of the same type
216         // with the sam eelement.. - which might be buggy..
217         while (true) {
218             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
219             
220             if (!echild) {
221                 break;
222             }
223             
224             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225                 break;
226             }
227             
228             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
229         }
230        
231         return ret;
232     },
233     
234     
235     addxtypeChild : function (tree, cntr, is_body)
236     {
237         Roo.debug && Roo.log('addxtypeChild:' + cntr);
238         var cn = this;
239         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
240         
241         
242         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243                     (typeof(tree['flexy:foreach']) != 'undefined');
244           
245     
246         
247         skip_children = false;
248         // render the element if it's not BODY.
249         if (!is_body) {
250             
251             // if parent was disabled, then do not try and create the children..
252             if(!this[cntr](true)){
253                 tree.items = [];
254                 return tree;
255             }
256            
257             cn = Roo.factory(tree);
258            
259             cn.parentType = this.xtype; //??
260             cn.parentId = this.id;
261             
262             var build_from_html =  Roo.XComponent.build_from_html;
263             
264             
265             // does the container contain child eleemnts with 'xtype' attributes.
266             // that match this xtype..
267             // note - when we render we create these as well..
268             // so we should check to see if body has xtype set.
269             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270                
271                 var self_cntr_el = Roo.get(this[cntr](false));
272                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273                 if (echild) { 
274                     //Roo.log(Roo.XComponent.build_from_html);
275                     //Roo.log("got echild:");
276                     //Roo.log(echild);
277                 }
278                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279                 // and are not displayed -this causes this to use up the wrong element when matching.
280                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
281                 
282                 
283                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
285                   
286                   
287                   
288                     cn.el = echild;
289                   //  Roo.log("GOT");
290                     //echild.dom.removeAttribute('xtype');
291                 } else {
292                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293                     Roo.debug && Roo.log(self_cntr_el);
294                     Roo.debug && Roo.log(echild);
295                     Roo.debug && Roo.log(cn);
296                 }
297             }
298            
299             
300            
301             // if object has flexy:if - then it may or may not be rendered.
302             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
303                 // skip a flexy if element.
304                 Roo.debug && Roo.log('skipping render');
305                 Roo.debug && Roo.log(tree);
306                 if (!cn.el) {
307                     Roo.debug && Roo.log('skipping all children');
308                     skip_children = true;
309                 }
310                 
311              } else {
312                  
313                 // actually if flexy:foreach is found, we really want to create 
314                 // multiple copies here...
315                 //Roo.log('render');
316                 //Roo.log(this[cntr]());
317                 // some elements do not have render methods.. like the layouts...
318                 /*
319                 if(this[cntr](true) === false){
320                     cn.items = [];
321                     return cn;
322                 }
323                 */
324                 cn.render && cn.render(this[cntr](true));
325                 
326              }
327             // then add the element..
328         }
329          
330         // handle the kids..
331         
332         var nitems = [];
333         /*
334         if (typeof (tree.menu) != 'undefined') {
335             tree.menu.parentType = cn.xtype;
336             tree.menu.triggerEl = cn.el;
337             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
338             
339         }
340         */
341         if (!tree.items || !tree.items.length) {
342             cn.items = nitems;
343             //Roo.log(["no children", this]);
344             
345             return cn;
346         }
347          
348         var items = tree.items;
349         delete tree.items;
350         
351         //Roo.log(items.length);
352             // add the items..
353         if (!skip_children) {    
354             for(var i =0;i < items.length;i++) {
355               //  Roo.log(['add child', items[i]]);
356                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
357             }
358         }
359         
360         cn.items = nitems;
361         
362         //Roo.log("fire childrenrendered");
363         
364         cn.fireEvent('childrenrendered', this);
365         
366         return cn;
367     },
368     
369     /**
370      * Set the element that will be used to show or hide
371      */
372     setVisibilityEl : function(el)
373     {
374         this.visibilityEl = el;
375     },
376     
377      /**
378      * Get the element that will be used to show or hide
379      */
380     getVisibilityEl : function()
381     {
382         if (typeof(this.visibilityEl) == 'object') {
383             return this.visibilityEl;
384         }
385         
386         if (typeof(this.visibilityEl) == 'string') {
387             return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
388         }
389         
390         return this.getEl();
391     },
392     
393     /**
394      * Show a component - removes 'hidden' class
395      */
396     show : function()
397     {
398         if(!this.getVisibilityEl()){
399             return;
400         }
401          
402         this.getVisibilityEl().removeClass('hidden');
403         
404         this.fireEvent('show', this);
405         
406         
407     },
408     /**
409      * Hide a component - adds 'hidden' class
410      */
411     hide: function()
412     {
413         if(!this.getVisibilityEl()){
414             return;
415         }
416         
417         this.getVisibilityEl().addClass('hidden');
418         
419         this.fireEvent('hide', this);
420         
421     }
422 });
423
424  /*
425  * - LGPL
426  *
427  * Body
428  *
429  */
430
431 /**
432  * @class Roo.bootstrap.Body
433  * @extends Roo.bootstrap.Component
434  * Bootstrap Body class
435  *
436  * @constructor
437  * Create a new body
438  * @param {Object} config The config object
439  */
440
441 Roo.bootstrap.Body = function(config){
442
443     config = config || {};
444
445     Roo.bootstrap.Body.superclass.constructor.call(this, config);
446     this.el = Roo.get(config.el ? config.el : document.body );
447     if (this.cls && this.cls.length) {
448         Roo.get(document.body).addClass(this.cls);
449     }
450 };
451
452 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
453
454     is_body : true,// just to make sure it's constructed?
455
456         autoCreate : {
457         cls: 'container'
458     },
459     onRender : function(ct, position)
460     {
461        /* Roo.log("Roo.bootstrap.Body - onRender");
462         if (this.cls && this.cls.length) {
463             Roo.get(document.body).addClass(this.cls);
464         }
465         // style??? xttr???
466         */
467     }
468
469
470
471
472 });
473 /*
474  * - LGPL
475  *
476  * button group
477  * 
478  */
479
480
481 /**
482  * @class Roo.bootstrap.ButtonGroup
483  * @extends Roo.bootstrap.Component
484  * Bootstrap ButtonGroup class
485  * @cfg {String} size lg | sm | xs (default empty normal)
486  * @cfg {String} align vertical | justified  (default none)
487  * @cfg {String} direction up | down (default down)
488  * @cfg {Boolean} toolbar false | true
489  * @cfg {Boolean} btn true | false
490  * 
491  * 
492  * @constructor
493  * Create a new Input
494  * @param {Object} config The config object
495  */
496
497 Roo.bootstrap.ButtonGroup = function(config){
498     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
499 };
500
501 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
502     
503     size: '',
504     align: '',
505     direction: '',
506     toolbar: false,
507     btn: true,
508
509     getAutoCreate : function(){
510         var cfg = {
511             cls: 'btn-group',
512             html : null
513         };
514         
515         cfg.html = this.html || cfg.html;
516         
517         if (this.toolbar) {
518             cfg = {
519                 cls: 'btn-toolbar',
520                 html: null
521             };
522             
523             return cfg;
524         }
525         
526         if (['vertical','justified'].indexOf(this.align)!==-1) {
527             cfg.cls = 'btn-group-' + this.align;
528             
529             if (this.align == 'justified') {
530                 console.log(this.items);
531             }
532         }
533         
534         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
535             cfg.cls += ' btn-group-' + this.size;
536         }
537         
538         if (this.direction == 'up') {
539             cfg.cls += ' dropup' ;
540         }
541         
542         return cfg;
543     }
544    
545 });
546
547  /*
548  * - LGPL
549  *
550  * button
551  * 
552  */
553
554 /**
555  * @class Roo.bootstrap.Button
556  * @extends Roo.bootstrap.Component
557  * Bootstrap Button class
558  * @cfg {String} html The button content
559  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
560  * @cfg {String} size ( lg | sm | xs)
561  * @cfg {String} tag ( a | input | submit)
562  * @cfg {String} href empty or href
563  * @cfg {Boolean} disabled default false;
564  * @cfg {Boolean} isClose default false;
565  * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
566  * @cfg {String} badge text for badge
567  * @cfg {String} theme (default|glow)  
568  * @cfg {Boolean} inverse dark themed version
569  * @cfg {Boolean} toggle is it a slidy toggle button
570  * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
571  * @cfg {String} ontext text for on slidy toggle state
572  * @cfg {String} offtext text for off slidy toggle state
573  * @cfg {Boolean} preventDefault  default true (stop click event triggering the URL if it's a link.)
574  * @cfg {Boolean} removeClass remove the standard class..
575  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
576  * 
577  * @constructor
578  * Create a new button
579  * @param {Object} config The config object
580  */
581
582
583 Roo.bootstrap.Button = function(config){
584     Roo.bootstrap.Button.superclass.constructor.call(this, config);
585     this.weightClass = ["btn-default", 
586                        "btn-primary", 
587                        "btn-success", 
588                        "btn-info", 
589                        "btn-warning",
590                        "btn-danger",
591                        "btn-link"
592                       ],  
593     this.addEvents({
594         // raw events
595         /**
596          * @event click
597          * When a butotn is pressed
598          * @param {Roo.bootstrap.Button} btn
599          * @param {Roo.EventObject} e
600          */
601         "click" : true,
602          /**
603          * @event toggle
604          * After the button has been toggles
605          * @param {Roo.bootstrap.Button} btn
606          * @param {Roo.EventObject} e
607          * @param {boolean} pressed (also available as button.pressed)
608          */
609         "toggle" : true
610     });
611 };
612
613 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
614     html: false,
615     active: false,
616     weight: '',
617     size: '',
618     tag: 'button',
619     href: '',
620     disabled: false,
621     isClose: false,
622     glyphicon: '',
623     badge: '',
624     theme: 'default',
625     inverse: false,
626     
627     toggle: false,
628     ontext: 'ON',
629     offtext: 'OFF',
630     defaulton: true,
631     preventDefault: true,
632     removeClass: false,
633     name: false,
634     target: false,
635      
636     pressed : null,
637      
638     
639     getAutoCreate : function(){
640         
641         var cfg = {
642             tag : 'button',
643             cls : 'roo-button',
644             html: ''
645         };
646         
647         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
648             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649             this.tag = 'button';
650         } else {
651             cfg.tag = this.tag;
652         }
653         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
654         
655         if (this.toggle == true) {
656             cfg={
657                 tag: 'div',
658                 cls: 'slider-frame roo-button',
659                 cn: [
660                     {
661                         tag: 'span',
662                         'data-on-text':'ON',
663                         'data-off-text':'OFF',
664                         cls: 'slider-button',
665                         html: this.offtext
666                     }
667                 ]
668             };
669             
670             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
671                 cfg.cls += ' '+this.weight;
672             }
673             
674             return cfg;
675         }
676         
677         if (this.isClose) {
678             cfg.cls += ' close';
679             
680             cfg["aria-hidden"] = true;
681             
682             cfg.html = "&times;";
683             
684             return cfg;
685         }
686         
687          
688         if (this.theme==='default') {
689             cfg.cls = 'btn roo-button';
690             
691             //if (this.parentType != 'Navbar') {
692             this.weight = this.weight.length ?  this.weight : 'default';
693             //}
694             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
695                 
696                 cfg.cls += ' btn-' + this.weight;
697             }
698         } else if (this.theme==='glow') {
699             
700             cfg.tag = 'a';
701             cfg.cls = 'btn-glow roo-button';
702             
703             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
704                 
705                 cfg.cls += ' ' + this.weight;
706             }
707         }
708    
709         
710         if (this.inverse) {
711             this.cls += ' inverse';
712         }
713         
714         
715         if (this.active || this.pressed === true) {
716             cfg.cls += ' active';
717         }
718         
719         if (this.disabled) {
720             cfg.disabled = 'disabled';
721         }
722         
723         if (this.items) {
724             Roo.log('changing to ul' );
725             cfg.tag = 'ul';
726             this.glyphicon = 'caret';
727         }
728         
729         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
730          
731         //gsRoo.log(this.parentType);
732         if (this.parentType === 'Navbar' && !this.parent().bar) {
733             Roo.log('changing to li?');
734             
735             cfg.tag = 'li';
736             
737             cfg.cls = '';
738             cfg.cn =  [{
739                 tag : 'a',
740                 cls : 'roo-button',
741                 html : this.html,
742                 href : this.href || '#'
743             }];
744             if (this.menu) {
745                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
746                 cfg.cls += ' dropdown';
747             }   
748             
749             delete cfg.html;
750             
751         }
752         
753        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
754         
755         if (this.glyphicon) {
756             cfg.html = ' ' + cfg.html;
757             
758             cfg.cn = [
759                 {
760                     tag: 'span',
761                     cls: 'glyphicon glyphicon-' + this.glyphicon
762                 }
763             ];
764         }
765         
766         if (this.badge) {
767             cfg.html += ' ';
768             
769             cfg.tag = 'a';
770             
771 //            cfg.cls='btn roo-button';
772             
773             cfg.href=this.href;
774             
775             var value = cfg.html;
776             
777             if(this.glyphicon){
778                 value = {
779                             tag: 'span',
780                             cls: 'glyphicon glyphicon-' + this.glyphicon,
781                             html: this.html
782                         };
783                 
784             }
785             
786             cfg.cn = [
787                 value,
788                 {
789                     tag: 'span',
790                     cls: 'badge',
791                     html: this.badge
792                 }
793             ];
794             
795             cfg.html='';
796         }
797         
798         if (this.menu) {
799             cfg.cls += ' dropdown';
800             cfg.html = typeof(cfg.html) != 'undefined' ?
801                     cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
802         }
803         
804         if (cfg.tag !== 'a' && this.href !== '') {
805             throw "Tag must be a to set href.";
806         } else if (this.href.length > 0) {
807             cfg.href = this.href;
808         }
809         
810         if(this.removeClass){
811             cfg.cls = '';
812         }
813         
814         if(this.target){
815             cfg.target = this.target;
816         }
817         
818         return cfg;
819     },
820     initEvents: function() {
821        // Roo.log('init events?');
822 //        Roo.log(this.el.dom);
823         // add the menu...
824         
825         if (typeof (this.menu) != 'undefined') {
826             this.menu.parentType = this.xtype;
827             this.menu.triggerEl = this.el;
828             this.addxtype(Roo.apply({}, this.menu));
829         }
830
831
832        if (this.el.hasClass('roo-button')) {
833             this.el.on('click', this.onClick, this);
834        } else {
835             this.el.select('.roo-button').on('click', this.onClick, this);
836        }
837        
838        if(this.removeClass){
839            this.el.on('click', this.onClick, this);
840        }
841        
842        this.el.enableDisplayMode();
843         
844     },
845     onClick : function(e)
846     {
847         if (this.disabled) {
848             return;
849         }
850         
851         Roo.log('button on click ');
852         if(this.preventDefault){
853             e.preventDefault();
854         }
855         
856         if (this.pressed === true || this.pressed === false) {
857             this.toggleActive(e);
858         }
859         
860         
861         this.fireEvent('click', this, e);
862     },
863     
864     /**
865      * Enables this button
866      */
867     enable : function()
868     {
869         this.disabled = false;
870         this.el.removeClass('disabled');
871     },
872     
873     /**
874      * Disable this button
875      */
876     disable : function()
877     {
878         this.disabled = true;
879         this.el.addClass('disabled');
880     },
881      /**
882      * sets the active state on/off, 
883      * @param {Boolean} state (optional) Force a particular state
884      */
885     setActive : function(v) {
886         
887         this.el[v ? 'addClass' : 'removeClass']('active');
888         this.pressed = v;
889     },
890      /**
891      * toggles the current active state 
892      */
893     toggleActive : function(e)
894     {
895         this.setActive(!this.pressed);
896         this.fireEvent('toggle', this, e, !this.pressed);
897     },
898      /**
899      * get the current active state
900      * @return {boolean} true if it's active
901      */
902     isActive : function()
903     {
904         return this.el.hasClass('active');
905     },
906     /**
907      * set the text of the first selected button
908      */
909     setText : function(str)
910     {
911         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
912     },
913     /**
914      * get the text of the first selected button
915      */
916     getText : function()
917     {
918         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
919     },
920     hide: function() {
921        
922      
923         this.el.hide();   
924     },
925     show: function() {
926        
927         this.el.show();   
928     },
929     setWeight : function(str)
930     {
931         this.el.removeClass(this.weightClass);
932         this.el.addClass('btn-' + str);        
933     }
934     
935     
936 });
937
938  /*
939  * - LGPL
940  *
941  * column
942  * 
943  */
944
945 /**
946  * @class Roo.bootstrap.Column
947  * @extends Roo.bootstrap.Component
948  * Bootstrap Column class
949  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
950  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
951  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
952  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
953  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
954  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
955  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
956  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
957  *
958  * 
959  * @cfg {Boolean} hidden (true|false) hide the element
960  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
961  * @cfg {String} fa (ban|check|...) font awesome icon
962  * @cfg {Number} fasize (1|2|....) font awsome size
963
964  * @cfg {String} icon (info-sign|check|...) glyphicon name
965
966  * @cfg {String} html content of column.
967  * 
968  * @constructor
969  * Create a new Column
970  * @param {Object} config The config object
971  */
972
973 Roo.bootstrap.Column = function(config){
974     Roo.bootstrap.Column.superclass.constructor.call(this, config);
975 };
976
977 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
978     
979     xs: false,
980     sm: false,
981     md: false,
982     lg: false,
983     xsoff: false,
984     smoff: false,
985     mdoff: false,
986     lgoff: false,
987     html: '',
988     offset: 0,
989     alert: false,
990     fa: false,
991     icon : false,
992     hidden : false,
993     fasize : 1,
994     
995     getAutoCreate : function(){
996         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
997         
998         cfg = {
999             tag: 'div',
1000             cls: 'column'
1001         };
1002         
1003         var settings=this;
1004         ['xs','sm','md','lg'].map(function(size){
1005             //Roo.log( size + ':' + settings[size]);
1006             
1007             if (settings[size+'off'] !== false) {
1008                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1009             }
1010             
1011             if (settings[size] === false) {
1012                 return;
1013             }
1014             
1015             if (!settings[size]) { // 0 = hidden
1016                 cfg.cls += ' hidden-' + size;
1017                 return;
1018             }
1019             cfg.cls += ' col-' + size + '-' + settings[size];
1020             
1021         });
1022         
1023         if (this.hidden) {
1024             cfg.cls += ' hidden';
1025         }
1026         
1027         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1028             cfg.cls +=' alert alert-' + this.alert;
1029         }
1030         
1031         
1032         if (this.html.length) {
1033             cfg.html = this.html;
1034         }
1035         if (this.fa) {
1036             var fasize = '';
1037             if (this.fasize > 1) {
1038                 fasize = ' fa-' + this.fasize + 'x';
1039             }
1040             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1041             
1042             
1043         }
1044         if (this.icon) {
1045             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
1046         }
1047         
1048         return cfg;
1049     }
1050    
1051 });
1052
1053  
1054
1055  /*
1056  * - LGPL
1057  *
1058  * page container.
1059  * 
1060  */
1061
1062
1063 /**
1064  * @class Roo.bootstrap.Container
1065  * @extends Roo.bootstrap.Component
1066  * Bootstrap Container class
1067  * @cfg {Boolean} jumbotron is it a jumbotron element
1068  * @cfg {String} html content of element
1069  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1070  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1071  * @cfg {String} header content of header (for panel)
1072  * @cfg {String} footer content of footer (for panel)
1073  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1074  * @cfg {String} tag (header|aside|section) type of HTML tag.
1075  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1076  * @cfg {String} fa font awesome icon
1077  * @cfg {String} icon (info-sign|check|...) glyphicon name
1078  * @cfg {Boolean} hidden (true|false) hide the element
1079  * @cfg {Boolean} expandable (true|false) default false
1080  * @cfg {Boolean} expanded (true|false) default true
1081  * @cfg {String} rheader contet on the right of header
1082  * @cfg {Boolean} clickable (true|false) default false
1083
1084  *     
1085  * @constructor
1086  * Create a new Container
1087  * @param {Object} config The config object
1088  */
1089
1090 Roo.bootstrap.Container = function(config){
1091     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1092     
1093     this.addEvents({
1094         // raw events
1095          /**
1096          * @event expand
1097          * After the panel has been expand
1098          * 
1099          * @param {Roo.bootstrap.Container} this
1100          */
1101         "expand" : true,
1102         /**
1103          * @event collapse
1104          * After the panel has been collapsed
1105          * 
1106          * @param {Roo.bootstrap.Container} this
1107          */
1108         "collapse" : true,
1109         /**
1110          * @event click
1111          * When a element is chick
1112          * @param {Roo.bootstrap.Container} this
1113          * @param {Roo.EventObject} e
1114          */
1115         "click" : true
1116     });
1117 };
1118
1119 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1120     
1121     jumbotron : false,
1122     well: '',
1123     panel : '',
1124     header: '',
1125     footer : '',
1126     sticky: '',
1127     tag : false,
1128     alert : false,
1129     fa: false,
1130     icon : false,
1131     expandable : false,
1132     rheader : '',
1133     expanded : true,
1134     clickable: false,
1135   
1136      
1137     getChildContainer : function() {
1138         
1139         if(!this.el){
1140             return false;
1141         }
1142         
1143         if (this.panel.length) {
1144             return this.el.select('.panel-body',true).first();
1145         }
1146         
1147         return this.el;
1148     },
1149     
1150     
1151     getAutoCreate : function(){
1152         
1153         var cfg = {
1154             tag : this.tag || 'div',
1155             html : '',
1156             cls : ''
1157         };
1158         if (this.jumbotron) {
1159             cfg.cls = 'jumbotron';
1160         }
1161         
1162         
1163         
1164         // - this is applied by the parent..
1165         //if (this.cls) {
1166         //    cfg.cls = this.cls + '';
1167         //}
1168         
1169         if (this.sticky.length) {
1170             
1171             var bd = Roo.get(document.body);
1172             if (!bd.hasClass('bootstrap-sticky')) {
1173                 bd.addClass('bootstrap-sticky');
1174                 Roo.select('html',true).setStyle('height', '100%');
1175             }
1176              
1177             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1178         }
1179         
1180         
1181         if (this.well.length) {
1182             switch (this.well) {
1183                 case 'lg':
1184                 case 'sm':
1185                     cfg.cls +=' well well-' +this.well;
1186                     break;
1187                 default:
1188                     cfg.cls +=' well';
1189                     break;
1190             }
1191         }
1192         
1193         if (this.hidden) {
1194             cfg.cls += ' hidden';
1195         }
1196         
1197         
1198         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1199             cfg.cls +=' alert alert-' + this.alert;
1200         }
1201         
1202         var body = cfg;
1203         
1204         if (this.panel.length) {
1205             cfg.cls += ' panel panel-' + this.panel;
1206             cfg.cn = [];
1207             if (this.header.length) {
1208                 
1209                 var h = [];
1210                 
1211                 if(this.expandable){
1212                     
1213                     cfg.cls = cfg.cls + ' expandable';
1214                     
1215                     h.push({
1216                         tag: 'i',
1217                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1218                     });
1219                     
1220                 }
1221                 
1222                 h.push(
1223                     {
1224                         tag: 'span',
1225                         cls : 'panel-title',
1226                         html : (this.expandable ? '&nbsp;' : '') + this.header
1227                     },
1228                     {
1229                         tag: 'span',
1230                         cls: 'panel-header-right',
1231                         html: this.rheader
1232                     }
1233                 );
1234                 
1235                 cfg.cn.push({
1236                     cls : 'panel-heading',
1237                     style : this.expandable ? 'cursor: pointer' : '',
1238                     cn : h
1239                 });
1240                 
1241             }
1242             
1243             body = false;
1244             cfg.cn.push({
1245                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1246                 html : this.html
1247             });
1248             
1249             
1250             if (this.footer.length) {
1251                 cfg.cn.push({
1252                     cls : 'panel-footer',
1253                     html : this.footer
1254                     
1255                 });
1256             }
1257             
1258         }
1259         
1260         if (body) {
1261             body.html = this.html || cfg.html;
1262             // prefix with the icons..
1263             if (this.fa) {
1264                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1265             }
1266             if (this.icon) {
1267                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1268             }
1269             
1270             
1271         }
1272         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1273             cfg.cls =  'container';
1274         }
1275         
1276         return cfg;
1277     },
1278     
1279     initEvents: function() 
1280     {
1281         if(this.expandable){
1282             var headerEl = this.headerEl();
1283         
1284             if(headerEl){
1285                 headerEl.on('click', this.onToggleClick, this);
1286             }
1287         }
1288         
1289         if(this.clickable){
1290             this.el.on('click', this.onClick, this);
1291         }
1292         
1293     },
1294     
1295     onToggleClick : function()
1296     {
1297         var headerEl = this.headerEl();
1298         
1299         if(!headerEl){
1300             return;
1301         }
1302         
1303         if(this.expanded){
1304             this.collapse();
1305             return;
1306         }
1307         
1308         this.expand();
1309     },
1310     
1311     expand : function()
1312     {
1313         if(this.fireEvent('expand', this)) {
1314             
1315             this.expanded = true;
1316             
1317             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1318             
1319             this.el.select('.panel-body',true).first().removeClass('hide');
1320             
1321             var toggleEl = this.toggleEl();
1322
1323             if(!toggleEl){
1324                 return;
1325             }
1326
1327             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1328         }
1329         
1330     },
1331     
1332     collapse : function()
1333     {
1334         if(this.fireEvent('collapse', this)) {
1335             
1336             this.expanded = false;
1337             
1338             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1339             this.el.select('.panel-body',true).first().addClass('hide');
1340         
1341             var toggleEl = this.toggleEl();
1342
1343             if(!toggleEl){
1344                 return;
1345             }
1346
1347             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1348         }
1349     },
1350     
1351     toggleEl : function()
1352     {
1353         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1354             return;
1355         }
1356         
1357         return this.el.select('.panel-heading .fa',true).first();
1358     },
1359     
1360     headerEl : function()
1361     {
1362         if(!this.el || !this.panel.length || !this.header.length){
1363             return;
1364         }
1365         
1366         return this.el.select('.panel-heading',true).first()
1367     },
1368     
1369     bodyEl : function()
1370     {
1371         if(!this.el || !this.panel.length){
1372             return;
1373         }
1374         
1375         return this.el.select('.panel-body',true).first()
1376     },
1377     
1378     titleEl : function()
1379     {
1380         if(!this.el || !this.panel.length || !this.header.length){
1381             return;
1382         }
1383         
1384         return this.el.select('.panel-title',true).first();
1385     },
1386     
1387     setTitle : function(v)
1388     {
1389         var titleEl = this.titleEl();
1390         
1391         if(!titleEl){
1392             return;
1393         }
1394         
1395         titleEl.dom.innerHTML = v;
1396     },
1397     
1398     getTitle : function()
1399     {
1400         
1401         var titleEl = this.titleEl();
1402         
1403         if(!titleEl){
1404             return '';
1405         }
1406         
1407         return titleEl.dom.innerHTML;
1408     },
1409     
1410     setRightTitle : function(v)
1411     {
1412         var t = this.el.select('.panel-header-right',true).first();
1413         
1414         if(!t){
1415             return;
1416         }
1417         
1418         t.dom.innerHTML = v;
1419     },
1420     
1421     onClick : function(e)
1422     {
1423         e.preventDefault();
1424         
1425         this.fireEvent('click', this, e);
1426     }
1427 });
1428
1429  /*
1430  * - LGPL
1431  *
1432  * image
1433  * 
1434  */
1435
1436
1437 /**
1438  * @class Roo.bootstrap.Img
1439  * @extends Roo.bootstrap.Component
1440  * Bootstrap Img class
1441  * @cfg {Boolean} imgResponsive false | true
1442  * @cfg {String} border rounded | circle | thumbnail
1443  * @cfg {String} src image source
1444  * @cfg {String} alt image alternative text
1445  * @cfg {String} href a tag href
1446  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1447  * @cfg {String} xsUrl xs image source
1448  * @cfg {String} smUrl sm image source
1449  * @cfg {String} mdUrl md image source
1450  * @cfg {String} lgUrl lg image source
1451  * 
1452  * @constructor
1453  * Create a new Input
1454  * @param {Object} config The config object
1455  */
1456
1457 Roo.bootstrap.Img = function(config){
1458     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1459     
1460     this.addEvents({
1461         // img events
1462         /**
1463          * @event click
1464          * The img click event for the img.
1465          * @param {Roo.EventObject} e
1466          */
1467         "click" : true
1468     });
1469 };
1470
1471 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1472     
1473     imgResponsive: true,
1474     border: '',
1475     src: 'about:blank',
1476     href: false,
1477     target: false,
1478     xsUrl: '',
1479     smUrl: '',
1480     mdUrl: '',
1481     lgUrl: '',
1482
1483     getAutoCreate : function()
1484     {   
1485         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1486             return this.createSingleImg();
1487         }
1488         
1489         var cfg = {
1490             tag: 'div',
1491             cls: 'roo-image-responsive-group',
1492             cn: []
1493         };
1494         var _this = this;
1495         
1496         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1497             
1498             if(!_this[size + 'Url']){
1499                 return;
1500             }
1501             
1502             var img = {
1503                 tag: 'img',
1504                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1505                 html: _this.html || cfg.html,
1506                 src: _this[size + 'Url']
1507             };
1508             
1509             img.cls += ' roo-image-responsive-' + size;
1510             
1511             var s = ['xs', 'sm', 'md', 'lg'];
1512             
1513             s.splice(s.indexOf(size), 1);
1514             
1515             Roo.each(s, function(ss){
1516                 img.cls += ' hidden-' + ss;
1517             });
1518             
1519             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1520                 cfg.cls += ' img-' + _this.border;
1521             }
1522             
1523             if(_this.alt){
1524                 cfg.alt = _this.alt;
1525             }
1526             
1527             if(_this.href){
1528                 var a = {
1529                     tag: 'a',
1530                     href: _this.href,
1531                     cn: [
1532                         img
1533                     ]
1534                 };
1535
1536                 if(this.target){
1537                     a.target = _this.target;
1538                 }
1539             }
1540             
1541             cfg.cn.push((_this.href) ? a : img);
1542             
1543         });
1544         
1545         return cfg;
1546     },
1547     
1548     createSingleImg : function()
1549     {
1550         var cfg = {
1551             tag: 'img',
1552             cls: (this.imgResponsive) ? 'img-responsive' : '',
1553             html : null,
1554             src : 'about:blank'  // just incase src get's set to undefined?!?
1555         };
1556         
1557         cfg.html = this.html || cfg.html;
1558         
1559         cfg.src = this.src || cfg.src;
1560         
1561         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1562             cfg.cls += ' img-' + this.border;
1563         }
1564         
1565         if(this.alt){
1566             cfg.alt = this.alt;
1567         }
1568         
1569         if(this.href){
1570             var a = {
1571                 tag: 'a',
1572                 href: this.href,
1573                 cn: [
1574                     cfg
1575                 ]
1576             };
1577             
1578             if(this.target){
1579                 a.target = this.target;
1580             }
1581             
1582         }
1583         
1584         return (this.href) ? a : cfg;
1585     },
1586     
1587     initEvents: function() 
1588     {
1589         if(!this.href){
1590             this.el.on('click', this.onClick, this);
1591         }
1592         
1593     },
1594     
1595     onClick : function(e)
1596     {
1597         Roo.log('img onclick');
1598         this.fireEvent('click', this, e);
1599     },
1600     /**
1601      * Sets the url of the image - used to update it
1602      * @param {String} url the url of the image
1603      */
1604     
1605     setSrc : function(url)
1606     {
1607         this.src =  url;
1608         
1609         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1610             this.el.dom.src =  url;
1611             return;
1612         }
1613         
1614         this.el.select('img', true).first().dom.src =  url;
1615     }
1616     
1617     
1618    
1619 });
1620
1621  /*
1622  * - LGPL
1623  *
1624  * image
1625  * 
1626  */
1627
1628
1629 /**
1630  * @class Roo.bootstrap.Link
1631  * @extends Roo.bootstrap.Component
1632  * Bootstrap Link Class
1633  * @cfg {String} alt image alternative text
1634  * @cfg {String} href a tag href
1635  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1636  * @cfg {String} html the content of the link.
1637  * @cfg {String} anchor name for the anchor link
1638  * @cfg {String} fa - favicon
1639
1640  * @cfg {Boolean} preventDefault (true | false) default false
1641
1642  * 
1643  * @constructor
1644  * Create a new Input
1645  * @param {Object} config The config object
1646  */
1647
1648 Roo.bootstrap.Link = function(config){
1649     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1650     
1651     this.addEvents({
1652         // img events
1653         /**
1654          * @event click
1655          * The img click event for the img.
1656          * @param {Roo.EventObject} e
1657          */
1658         "click" : true
1659     });
1660 };
1661
1662 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1663     
1664     href: false,
1665     target: false,
1666     preventDefault: false,
1667     anchor : false,
1668     alt : false,
1669     fa: false,
1670
1671
1672     getAutoCreate : function()
1673     {
1674         var html = this.html || '';
1675         
1676         if (this.fa !== false) {
1677             html = '<i class="fa fa-' + this.fa + '"></i>';
1678         }
1679         var cfg = {
1680             tag: 'a'
1681         };
1682         // anchor's do not require html/href...
1683         if (this.anchor === false) {
1684             cfg.html = html;
1685             cfg.href = this.href || '#';
1686         } else {
1687             cfg.name = this.anchor;
1688             if (this.html !== false || this.fa !== false) {
1689                 cfg.html = html;
1690             }
1691             if (this.href !== false) {
1692                 cfg.href = this.href;
1693             }
1694         }
1695         
1696         if(this.alt !== false){
1697             cfg.alt = this.alt;
1698         }
1699         
1700         
1701         if(this.target !== false) {
1702             cfg.target = this.target;
1703         }
1704         
1705         return cfg;
1706     },
1707     
1708     initEvents: function() {
1709         
1710         if(!this.href || this.preventDefault){
1711             this.el.on('click', this.onClick, this);
1712         }
1713     },
1714     
1715     onClick : function(e)
1716     {
1717         if(this.preventDefault){
1718             e.preventDefault();
1719         }
1720         //Roo.log('img onclick');
1721         this.fireEvent('click', this, e);
1722     }
1723    
1724 });
1725
1726  /*
1727  * - LGPL
1728  *
1729  * header
1730  * 
1731  */
1732
1733 /**
1734  * @class Roo.bootstrap.Header
1735  * @extends Roo.bootstrap.Component
1736  * Bootstrap Header class
1737  * @cfg {String} html content of header
1738  * @cfg {Number} level (1|2|3|4|5|6) default 1
1739  * 
1740  * @constructor
1741  * Create a new Header
1742  * @param {Object} config The config object
1743  */
1744
1745
1746 Roo.bootstrap.Header  = function(config){
1747     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1748 };
1749
1750 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1751     
1752     //href : false,
1753     html : false,
1754     level : 1,
1755     
1756     
1757     
1758     getAutoCreate : function(){
1759         
1760         
1761         
1762         var cfg = {
1763             tag: 'h' + (1 *this.level),
1764             html: this.html || ''
1765         } ;
1766         
1767         return cfg;
1768     }
1769    
1770 });
1771
1772  
1773
1774  /*
1775  * Based on:
1776  * Ext JS Library 1.1.1
1777  * Copyright(c) 2006-2007, Ext JS, LLC.
1778  *
1779  * Originally Released Under LGPL - original licence link has changed is not relivant.
1780  *
1781  * Fork - LGPL
1782  * <script type="text/javascript">
1783  */
1784  
1785 /**
1786  * @class Roo.bootstrap.MenuMgr
1787  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1788  * @singleton
1789  */
1790 Roo.bootstrap.MenuMgr = function(){
1791    var menus, active, groups = {}, attached = false, lastShow = new Date();
1792
1793    // private - called when first menu is created
1794    function init(){
1795        menus = {};
1796        active = new Roo.util.MixedCollection();
1797        Roo.get(document).addKeyListener(27, function(){
1798            if(active.length > 0){
1799                hideAll();
1800            }
1801        });
1802    }
1803
1804    // private
1805    function hideAll(){
1806        if(active && active.length > 0){
1807            var c = active.clone();
1808            c.each(function(m){
1809                m.hide();
1810            });
1811        }
1812    }
1813
1814    // private
1815    function onHide(m){
1816        active.remove(m);
1817        if(active.length < 1){
1818            Roo.get(document).un("mouseup", onMouseDown);
1819             
1820            attached = false;
1821        }
1822    }
1823
1824    // private
1825    function onShow(m){
1826        var last = active.last();
1827        lastShow = new Date();
1828        active.add(m);
1829        if(!attached){
1830           Roo.get(document).on("mouseup", onMouseDown);
1831            
1832            attached = true;
1833        }
1834        if(m.parentMenu){
1835           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1836           m.parentMenu.activeChild = m;
1837        }else if(last && last.isVisible()){
1838           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1839        }
1840    }
1841
1842    // private
1843    function onBeforeHide(m){
1844        if(m.activeChild){
1845            m.activeChild.hide();
1846        }
1847        if(m.autoHideTimer){
1848            clearTimeout(m.autoHideTimer);
1849            delete m.autoHideTimer;
1850        }
1851    }
1852
1853    // private
1854    function onBeforeShow(m){
1855        var pm = m.parentMenu;
1856        if(!pm && !m.allowOtherMenus){
1857            hideAll();
1858        }else if(pm && pm.activeChild && active != m){
1859            pm.activeChild.hide();
1860        }
1861    }
1862
1863    // private this should really trigger on mouseup..
1864    function onMouseDown(e){
1865         Roo.log("on Mouse Up");
1866         
1867         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1868             Roo.log("MenuManager hideAll");
1869             hideAll();
1870             e.stopEvent();
1871         }
1872         
1873         
1874    }
1875
1876    // private
1877    function onBeforeCheck(mi, state){
1878        if(state){
1879            var g = groups[mi.group];
1880            for(var i = 0, l = g.length; i < l; i++){
1881                if(g[i] != mi){
1882                    g[i].setChecked(false);
1883                }
1884            }
1885        }
1886    }
1887
1888    return {
1889
1890        /**
1891         * Hides all menus that are currently visible
1892         */
1893        hideAll : function(){
1894             hideAll();  
1895        },
1896
1897        // private
1898        register : function(menu){
1899            if(!menus){
1900                init();
1901            }
1902            menus[menu.id] = menu;
1903            menu.on("beforehide", onBeforeHide);
1904            menu.on("hide", onHide);
1905            menu.on("beforeshow", onBeforeShow);
1906            menu.on("show", onShow);
1907            var g = menu.group;
1908            if(g && menu.events["checkchange"]){
1909                if(!groups[g]){
1910                    groups[g] = [];
1911                }
1912                groups[g].push(menu);
1913                menu.on("checkchange", onCheck);
1914            }
1915        },
1916
1917         /**
1918          * Returns a {@link Roo.menu.Menu} object
1919          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1920          * be used to generate and return a new Menu instance.
1921          */
1922        get : function(menu){
1923            if(typeof menu == "string"){ // menu id
1924                return menus[menu];
1925            }else if(menu.events){  // menu instance
1926                return menu;
1927            }
1928            /*else if(typeof menu.length == 'number'){ // array of menu items?
1929                return new Roo.bootstrap.Menu({items:menu});
1930            }else{ // otherwise, must be a config
1931                return new Roo.bootstrap.Menu(menu);
1932            }
1933            */
1934            return false;
1935        },
1936
1937        // private
1938        unregister : function(menu){
1939            delete menus[menu.id];
1940            menu.un("beforehide", onBeforeHide);
1941            menu.un("hide", onHide);
1942            menu.un("beforeshow", onBeforeShow);
1943            menu.un("show", onShow);
1944            var g = menu.group;
1945            if(g && menu.events["checkchange"]){
1946                groups[g].remove(menu);
1947                menu.un("checkchange", onCheck);
1948            }
1949        },
1950
1951        // private
1952        registerCheckable : function(menuItem){
1953            var g = menuItem.group;
1954            if(g){
1955                if(!groups[g]){
1956                    groups[g] = [];
1957                }
1958                groups[g].push(menuItem);
1959                menuItem.on("beforecheckchange", onBeforeCheck);
1960            }
1961        },
1962
1963        // private
1964        unregisterCheckable : function(menuItem){
1965            var g = menuItem.group;
1966            if(g){
1967                groups[g].remove(menuItem);
1968                menuItem.un("beforecheckchange", onBeforeCheck);
1969            }
1970        }
1971    };
1972 }();/*
1973  * - LGPL
1974  *
1975  * menu
1976  * 
1977  */
1978
1979 /**
1980  * @class Roo.bootstrap.Menu
1981  * @extends Roo.bootstrap.Component
1982  * Bootstrap Menu class - container for MenuItems
1983  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1984  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1985  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1986  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1987  * 
1988  * @constructor
1989  * Create a new Menu
1990  * @param {Object} config The config object
1991  */
1992
1993
1994 Roo.bootstrap.Menu = function(config){
1995     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1996     if (this.registerMenu && this.type != 'treeview')  {
1997         Roo.bootstrap.MenuMgr.register(this);
1998     }
1999     this.addEvents({
2000         /**
2001          * @event beforeshow
2002          * Fires before this menu is displayed
2003          * @param {Roo.menu.Menu} this
2004          */
2005         beforeshow : true,
2006         /**
2007          * @event beforehide
2008          * Fires before this menu is hidden
2009          * @param {Roo.menu.Menu} this
2010          */
2011         beforehide : true,
2012         /**
2013          * @event show
2014          * Fires after this menu is displayed
2015          * @param {Roo.menu.Menu} this
2016          */
2017         show : true,
2018         /**
2019          * @event hide
2020          * Fires after this menu is hidden
2021          * @param {Roo.menu.Menu} this
2022          */
2023         hide : true,
2024         /**
2025          * @event click
2026          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2027          * @param {Roo.menu.Menu} this
2028          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2029          * @param {Roo.EventObject} e
2030          */
2031         click : true,
2032         /**
2033          * @event mouseover
2034          * Fires when the mouse is hovering over this menu
2035          * @param {Roo.menu.Menu} this
2036          * @param {Roo.EventObject} e
2037          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2038          */
2039         mouseover : true,
2040         /**
2041          * @event mouseout
2042          * Fires when the mouse exits this menu
2043          * @param {Roo.menu.Menu} this
2044          * @param {Roo.EventObject} e
2045          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2046          */
2047         mouseout : true,
2048         /**
2049          * @event itemclick
2050          * Fires when a menu item contained in this menu is clicked
2051          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2052          * @param {Roo.EventObject} e
2053          */
2054         itemclick: true
2055     });
2056     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2057 };
2058
2059 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2060     
2061    /// html : false,
2062     //align : '',
2063     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2064     type: false,
2065     /**
2066      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2067      */
2068     registerMenu : true,
2069     
2070     menuItems :false, // stores the menu items..
2071     
2072     hidden:true,
2073         
2074     parentMenu : false,
2075     
2076     stopEvent : true,
2077     
2078     isLink : false,
2079     
2080     getChildContainer : function() {
2081         return this.el;  
2082     },
2083     
2084     getAutoCreate : function(){
2085          
2086         //if (['right'].indexOf(this.align)!==-1) {
2087         //    cfg.cn[1].cls += ' pull-right'
2088         //}
2089         
2090         
2091         var cfg = {
2092             tag : 'ul',
2093             cls : 'dropdown-menu' ,
2094             style : 'z-index:1000'
2095             
2096         };
2097         
2098         if (this.type === 'submenu') {
2099             cfg.cls = 'submenu active';
2100         }
2101         if (this.type === 'treeview') {
2102             cfg.cls = 'treeview-menu';
2103         }
2104         
2105         return cfg;
2106     },
2107     initEvents : function() {
2108         
2109        // Roo.log("ADD event");
2110        // Roo.log(this.triggerEl.dom);
2111         
2112         this.triggerEl.on('click', this.onTriggerClick, this);
2113         
2114         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2115         
2116         this.triggerEl.addClass('dropdown-toggle');
2117         
2118         if (Roo.isTouch) {
2119             this.el.on('touchstart'  , this.onTouch, this);
2120         }
2121         this.el.on('click' , this.onClick, this);
2122
2123         this.el.on("mouseover", this.onMouseOver, this);
2124         this.el.on("mouseout", this.onMouseOut, this);
2125         
2126     },
2127     
2128     findTargetItem : function(e)
2129     {
2130         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2131         if(!t){
2132             return false;
2133         }
2134         //Roo.log(t);         Roo.log(t.id);
2135         if(t && t.id){
2136             //Roo.log(this.menuitems);
2137             return this.menuitems.get(t.id);
2138             
2139             //return this.items.get(t.menuItemId);
2140         }
2141         
2142         return false;
2143     },
2144     
2145     onTouch : function(e) 
2146     {
2147         Roo.log("menu.onTouch");
2148         //e.stopEvent(); this make the user popdown broken
2149         this.onClick(e);
2150     },
2151     
2152     onClick : function(e)
2153     {
2154         Roo.log("menu.onClick");
2155         
2156         var t = this.findTargetItem(e);
2157         if(!t || t.isContainer){
2158             return;
2159         }
2160         Roo.log(e);
2161         /*
2162         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2163             if(t == this.activeItem && t.shouldDeactivate(e)){
2164                 this.activeItem.deactivate();
2165                 delete this.activeItem;
2166                 return;
2167             }
2168             if(t.canActivate){
2169                 this.setActiveItem(t, true);
2170             }
2171             return;
2172             
2173             
2174         }
2175         */
2176        
2177         Roo.log('pass click event');
2178         
2179         t.onClick(e);
2180         
2181         this.fireEvent("click", this, t, e);
2182         
2183         var _this = this;
2184         
2185         if(!t.href.length || t.href == '#'){
2186             (function() { _this.hide(); }).defer(100);
2187         }
2188         
2189     },
2190     
2191     onMouseOver : function(e){
2192         var t  = this.findTargetItem(e);
2193         //Roo.log(t);
2194         //if(t){
2195         //    if(t.canActivate && !t.disabled){
2196         //        this.setActiveItem(t, true);
2197         //    }
2198         //}
2199         
2200         this.fireEvent("mouseover", this, e, t);
2201     },
2202     isVisible : function(){
2203         return !this.hidden;
2204     },
2205      onMouseOut : function(e){
2206         var t  = this.findTargetItem(e);
2207         
2208         //if(t ){
2209         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2210         //        this.activeItem.deactivate();
2211         //        delete this.activeItem;
2212         //    }
2213         //}
2214         this.fireEvent("mouseout", this, e, t);
2215     },
2216     
2217     
2218     /**
2219      * Displays this menu relative to another element
2220      * @param {String/HTMLElement/Roo.Element} element The element to align to
2221      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2222      * the element (defaults to this.defaultAlign)
2223      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2224      */
2225     show : function(el, pos, parentMenu){
2226         this.parentMenu = parentMenu;
2227         if(!this.el){
2228             this.render();
2229         }
2230         this.fireEvent("beforeshow", this);
2231         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2232     },
2233      /**
2234      * Displays this menu at a specific xy position
2235      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2236      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2237      */
2238     showAt : function(xy, parentMenu, /* private: */_e){
2239         this.parentMenu = parentMenu;
2240         if(!this.el){
2241             this.render();
2242         }
2243         if(_e !== false){
2244             this.fireEvent("beforeshow", this);
2245             //xy = this.el.adjustForConstraints(xy);
2246         }
2247         
2248         //this.el.show();
2249         this.hideMenuItems();
2250         this.hidden = false;
2251         this.triggerEl.addClass('open');
2252         
2253         // reassign x when hitting right
2254         if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2255             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2256         }
2257         
2258         // reassign y when hitting bottom
2259         if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2260             xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2261         }
2262         
2263         // but the list may align on trigger left or trigger top... should it be a properity?
2264         
2265         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2266             this.el.setXY(xy);
2267         }
2268         
2269         this.focus();
2270         this.fireEvent("show", this);
2271     },
2272     
2273     focus : function(){
2274         return;
2275         if(!this.hidden){
2276             this.doFocus.defer(50, this);
2277         }
2278     },
2279
2280     doFocus : function(){
2281         if(!this.hidden){
2282             this.focusEl.focus();
2283         }
2284     },
2285
2286     /**
2287      * Hides this menu and optionally all parent menus
2288      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2289      */
2290     hide : function(deep)
2291     {
2292         
2293         this.hideMenuItems();
2294         if(this.el && this.isVisible()){
2295             this.fireEvent("beforehide", this);
2296             if(this.activeItem){
2297                 this.activeItem.deactivate();
2298                 this.activeItem = null;
2299             }
2300             this.triggerEl.removeClass('open');;
2301             this.hidden = true;
2302             this.fireEvent("hide", this);
2303         }
2304         if(deep === true && this.parentMenu){
2305             this.parentMenu.hide(true);
2306         }
2307     },
2308     
2309     onTriggerClick : function(e)
2310     {
2311         Roo.log('trigger click');
2312         
2313         var target = e.getTarget();
2314         
2315         Roo.log(target.nodeName.toLowerCase());
2316         
2317         if(target.nodeName.toLowerCase() === 'i'){
2318             e.preventDefault();
2319         }
2320         
2321     },
2322     
2323     onTriggerPress  : function(e)
2324     {
2325         Roo.log('trigger press');
2326         //Roo.log(e.getTarget());
2327        // Roo.log(this.triggerEl.dom);
2328        
2329         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2330         var pel = Roo.get(e.getTarget());
2331         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2332             Roo.log('is treeview or dropdown?');
2333             return;
2334         }
2335         
2336         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2337             return;
2338         }
2339         
2340         if (this.isVisible()) {
2341             Roo.log('hide');
2342             this.hide();
2343         } else {
2344             Roo.log('show');
2345             this.show(this.triggerEl, false, false);
2346         }
2347         
2348         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2349             e.stopEvent();
2350         }
2351         
2352     },
2353        
2354     
2355     hideMenuItems : function()
2356     {
2357         Roo.log("hide Menu Items");
2358         if (!this.el) { 
2359             return;
2360         }
2361         //$(backdrop).remove()
2362         this.el.select('.open',true).each(function(aa) {
2363             
2364             aa.removeClass('open');
2365           //var parent = getParent($(this))
2366           //var relatedTarget = { relatedTarget: this }
2367           
2368            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2369           //if (e.isDefaultPrevented()) return
2370            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2371         });
2372     },
2373     addxtypeChild : function (tree, cntr) {
2374         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2375           
2376         this.menuitems.add(comp);
2377         return comp;
2378
2379     },
2380     getEl : function()
2381     {
2382         Roo.log(this.el);
2383         return this.el;
2384     },
2385     
2386     clear : function()
2387     {
2388         this.getEl().dom.innerHTML = '';
2389         this.menuitems.clear();
2390     }
2391 });
2392
2393  
2394  /*
2395  * - LGPL
2396  *
2397  * menu item
2398  * 
2399  */
2400
2401
2402 /**
2403  * @class Roo.bootstrap.MenuItem
2404  * @extends Roo.bootstrap.Component
2405  * Bootstrap MenuItem class
2406  * @cfg {String} html the menu label
2407  * @cfg {String} href the link
2408  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2409  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2410  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2411  * @cfg {String} fa favicon to show on left of menu item.
2412  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2413  * 
2414  * 
2415  * @constructor
2416  * Create a new MenuItem
2417  * @param {Object} config The config object
2418  */
2419
2420
2421 Roo.bootstrap.MenuItem = function(config){
2422     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2423     this.addEvents({
2424         // raw events
2425         /**
2426          * @event click
2427          * The raw click event for the entire grid.
2428          * @param {Roo.bootstrap.MenuItem} this
2429          * @param {Roo.EventObject} e
2430          */
2431         "click" : true
2432     });
2433 };
2434
2435 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2436     
2437     href : false,
2438     html : false,
2439     preventDefault: false,
2440     isContainer : false,
2441     active : false,
2442     fa: false,
2443     
2444     getAutoCreate : function(){
2445         
2446         if(this.isContainer){
2447             return {
2448                 tag: 'li',
2449                 cls: 'dropdown-menu-item'
2450             };
2451         }
2452         var ctag = {
2453             tag: 'span',
2454             html: 'Link'
2455         };
2456         
2457         var anc = {
2458             tag : 'a',
2459             href : '#',
2460             cn : [  ]
2461         };
2462         
2463         if (this.fa !== false) {
2464             anc.cn.push({
2465                 tag : 'i',
2466                 cls : 'fa fa-' + this.fa
2467             });
2468         }
2469         
2470         anc.cn.push(ctag);
2471         
2472         
2473         var cfg= {
2474             tag: 'li',
2475             cls: 'dropdown-menu-item',
2476             cn: [ anc ]
2477         };
2478         if (this.parent().type == 'treeview') {
2479             cfg.cls = 'treeview-menu';
2480         }
2481         if (this.active) {
2482             cfg.cls += ' active';
2483         }
2484         
2485         
2486         
2487         anc.href = this.href || cfg.cn[0].href ;
2488         ctag.html = this.html || cfg.cn[0].html ;
2489         return cfg;
2490     },
2491     
2492     initEvents: function()
2493     {
2494         if (this.parent().type == 'treeview') {
2495             this.el.select('a').on('click', this.onClick, this);
2496         }
2497         
2498         if (this.menu) {
2499             this.menu.parentType = this.xtype;
2500             this.menu.triggerEl = this.el;
2501             this.menu = this.addxtype(Roo.apply({}, this.menu));
2502         }
2503         
2504     },
2505     onClick : function(e)
2506     {
2507         Roo.log('item on click ');
2508         
2509         if(this.preventDefault){
2510             e.preventDefault();
2511         }
2512         //this.parent().hideMenuItems();
2513         
2514         this.fireEvent('click', this, e);
2515     },
2516     getEl : function()
2517     {
2518         return this.el;
2519     } 
2520 });
2521
2522  
2523
2524  /*
2525  * - LGPL
2526  *
2527  * menu separator
2528  * 
2529  */
2530
2531
2532 /**
2533  * @class Roo.bootstrap.MenuSeparator
2534  * @extends Roo.bootstrap.Component
2535  * Bootstrap MenuSeparator class
2536  * 
2537  * @constructor
2538  * Create a new MenuItem
2539  * @param {Object} config The config object
2540  */
2541
2542
2543 Roo.bootstrap.MenuSeparator = function(config){
2544     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2545 };
2546
2547 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2548     
2549     getAutoCreate : function(){
2550         var cfg = {
2551             cls: 'divider',
2552             tag : 'li'
2553         };
2554         
2555         return cfg;
2556     }
2557    
2558 });
2559
2560  
2561
2562  
2563 /*
2564 * Licence: LGPL
2565 */
2566
2567 /**
2568  * @class Roo.bootstrap.Modal
2569  * @extends Roo.bootstrap.Component
2570  * Bootstrap Modal class
2571  * @cfg {String} title Title of dialog
2572  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2573  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2574  * @cfg {Boolean} specificTitle default false
2575  * @cfg {Array} buttons Array of buttons or standard button set..
2576  * @cfg {String} buttonPosition (left|right|center) default right
2577  * @cfg {Boolean} animate default true
2578  * @cfg {Boolean} allow_close default true
2579  * @cfg {Boolean} fitwindow default false
2580  * @cfg {String} size (sm|lg) default empty
2581  * @cfg {Number} max_width set the max width of modal
2582  *
2583  *
2584  * @constructor
2585  * Create a new Modal Dialog
2586  * @param {Object} config The config object
2587  */
2588
2589 Roo.bootstrap.Modal = function(config){
2590     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2591     this.addEvents({
2592         // raw events
2593         /**
2594          * @event btnclick
2595          * The raw btnclick event for the button
2596          * @param {Roo.EventObject} e
2597          */
2598         "btnclick" : true,
2599         /**
2600          * @event resize
2601          * Fire when dialog resize
2602          * @param {Roo.bootstrap.Modal} this
2603          * @param {Roo.EventObject} e
2604          */
2605         "resize" : true
2606     });
2607     this.buttons = this.buttons || [];
2608
2609     if (this.tmpl) {
2610         this.tmpl = Roo.factory(this.tmpl);
2611     }
2612
2613 };
2614
2615 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2616
2617     title : 'test dialog',
2618
2619     buttons : false,
2620
2621     // set on load...
2622
2623     html: false,
2624
2625     tmp: false,
2626
2627     specificTitle: false,
2628
2629     buttonPosition: 'right',
2630
2631     allow_close : true,
2632
2633     animate : true,
2634
2635     fitwindow: false,
2636
2637
2638      // private
2639     dialogEl: false,
2640     bodyEl:  false,
2641     footerEl:  false,
2642     titleEl:  false,
2643     closeEl:  false,
2644
2645     size: '',
2646     
2647     max_width: 0,
2648
2649
2650     onRender : function(ct, position)
2651     {
2652         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2653
2654         if(!this.el){
2655             var cfg = Roo.apply({},  this.getAutoCreate());
2656             cfg.id = Roo.id();
2657             //if(!cfg.name){
2658             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2659             //}
2660             //if (!cfg.name.length) {
2661             //    delete cfg.name;
2662            // }
2663             if (this.cls) {
2664                 cfg.cls += ' ' + this.cls;
2665             }
2666             if (this.style) {
2667                 cfg.style = this.style;
2668             }
2669             this.el = Roo.get(document.body).createChild(cfg, position);
2670         }
2671         //var type = this.el.dom.type;
2672
2673
2674         if(this.tabIndex !== undefined){
2675             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2676         }
2677
2678         this.dialogEl = this.el.select('.modal-dialog',true).first();
2679         this.bodyEl = this.el.select('.modal-body',true).first();
2680         this.closeEl = this.el.select('.modal-header .close', true).first();
2681         this.headerEl = this.el.select('.modal-header',true).first();
2682         this.titleEl = this.el.select('.modal-title',true).first();
2683         this.footerEl = this.el.select('.modal-footer',true).first();
2684
2685         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2686         
2687         //this.el.addClass("x-dlg-modal");
2688
2689         if (this.buttons.length) {
2690             Roo.each(this.buttons, function(bb) {
2691                 var b = Roo.apply({}, bb);
2692                 b.xns = b.xns || Roo.bootstrap;
2693                 b.xtype = b.xtype || 'Button';
2694                 if (typeof(b.listeners) == 'undefined') {
2695                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2696                 }
2697
2698                 var btn = Roo.factory(b);
2699
2700                 btn.render(this.el.select('.modal-footer div').first());
2701
2702             },this);
2703         }
2704         // render the children.
2705         var nitems = [];
2706
2707         if(typeof(this.items) != 'undefined'){
2708             var items = this.items;
2709             delete this.items;
2710
2711             for(var i =0;i < items.length;i++) {
2712                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2713             }
2714         }
2715
2716         this.items = nitems;
2717
2718         // where are these used - they used to be body/close/footer
2719
2720
2721         this.initEvents();
2722         //this.el.addClass([this.fieldClass, this.cls]);
2723
2724     },
2725
2726     getAutoCreate : function()
2727     {
2728         var bdy = {
2729                 cls : 'modal-body',
2730                 html : this.html || ''
2731         };
2732
2733         var title = {
2734             tag: 'h4',
2735             cls : 'modal-title',
2736             html : this.title
2737         };
2738
2739         if(this.specificTitle){
2740             title = this.title;
2741
2742         };
2743
2744         var header = [];
2745         if (this.allow_close) {
2746             header.push({
2747                 tag: 'button',
2748                 cls : 'close',
2749                 html : '&times'
2750             });
2751         }
2752
2753         header.push(title);
2754
2755         var size = '';
2756
2757         if(this.size.length){
2758             size = 'modal-' + this.size;
2759         }
2760
2761         var modal = {
2762             cls: "modal",
2763              cn : [
2764                 {
2765                     cls: "modal-dialog " + size,
2766                     cn : [
2767                         {
2768                             cls : "modal-content",
2769                             cn : [
2770                                 {
2771                                     cls : 'modal-header',
2772                                     cn : header
2773                                 },
2774                                 bdy,
2775                                 {
2776                                     cls : 'modal-footer',
2777                                     cn : [
2778                                         {
2779                                             tag: 'div',
2780                                             cls: 'btn-' + this.buttonPosition
2781                                         }
2782                                     ]
2783
2784                                 }
2785
2786
2787                             ]
2788
2789                         }
2790                     ]
2791
2792                 }
2793             ]
2794         };
2795
2796         if(this.animate){
2797             modal.cls += ' fade';
2798         }
2799
2800         return modal;
2801
2802     },
2803     getChildContainer : function() {
2804
2805          return this.bodyEl;
2806
2807     },
2808     getButtonContainer : function() {
2809          return this.el.select('.modal-footer div',true).first();
2810
2811     },
2812     initEvents : function()
2813     {
2814         if (this.allow_close) {
2815             this.closeEl.on('click', this.hide, this);
2816         }
2817         Roo.EventManager.onWindowResize(this.resize, this, true);
2818
2819
2820     },
2821
2822     resize : function()
2823     {
2824         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2825         
2826         if (this.fitwindow) {
2827             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2828             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2829             this.setSize(w,h);
2830         }
2831         
2832         if(!this.fitwindow && this.max_width !== 0){
2833             
2834             var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2835             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2836             this.setSize(w,h);
2837         }
2838         
2839     },
2840
2841     setSize : function(w,h)
2842     {
2843         if (!w && !h) {
2844             return;
2845         }
2846         this.resizeTo(w,h);
2847     },
2848
2849     show : function() {
2850
2851         if (!this.rendered) {
2852             this.render();
2853         }
2854
2855         //this.el.setStyle('display', 'block');
2856         this.el.removeClass('hideing');        
2857         this.el.addClass('show');
2858  
2859         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2860             var _this = this;
2861             (function(){
2862                 this.el.addClass('in');
2863             }).defer(50, this);
2864         }else{
2865             this.el.addClass('in');
2866         }
2867
2868         // not sure how we can show data in here..
2869         //if (this.tmpl) {
2870         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2871         //}
2872
2873         Roo.get(document.body).addClass("x-body-masked");
2874         
2875         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2876         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2877         this.maskEl.addClass('show');
2878         
2879         this.resize();
2880         
2881         this.fireEvent('show', this);
2882
2883         // set zindex here - otherwise it appears to be ignored...
2884         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2885
2886         (function () {
2887             this.items.forEach( function(e) {
2888                 e.layout ? e.layout() : false;
2889
2890             });
2891         }).defer(100,this);
2892
2893     },
2894     hide : function()
2895     {
2896         if(this.fireEvent("beforehide", this) !== false){
2897             this.maskEl.removeClass('show');
2898             Roo.get(document.body).removeClass("x-body-masked");
2899             this.el.removeClass('in');
2900             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2901
2902             if(this.animate){ // why
2903                 this.el.addClass('hideing');
2904                 (function(){
2905                     if (!this.el.hasClass('hideing')) {
2906                         return; // it's been shown again...
2907                     }
2908                     this.el.removeClass('show');
2909                     this.el.removeClass('hideing');
2910                 }).defer(150,this);
2911                 
2912             }else{
2913                  this.el.removeClass('show');
2914             }
2915             this.fireEvent('hide', this);
2916         }
2917     },
2918     isVisible : function()
2919     {
2920         
2921         return this.el.hasClass('show') && !this.el.hasClass('hideing');
2922         
2923     },
2924
2925     addButton : function(str, cb)
2926     {
2927
2928
2929         var b = Roo.apply({}, { html : str } );
2930         b.xns = b.xns || Roo.bootstrap;
2931         b.xtype = b.xtype || 'Button';
2932         if (typeof(b.listeners) == 'undefined') {
2933             b.listeners = { click : cb.createDelegate(this)  };
2934         }
2935
2936         var btn = Roo.factory(b);
2937
2938         btn.render(this.el.select('.modal-footer div').first());
2939
2940         return btn;
2941
2942     },
2943
2944     setDefaultButton : function(btn)
2945     {
2946         //this.el.select('.modal-footer').()
2947     },
2948     diff : false,
2949
2950     resizeTo: function(w,h)
2951     {
2952         // skip.. ?? why??
2953
2954         this.dialogEl.setWidth(w);
2955         if (this.diff === false) {
2956             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2957         }
2958
2959         this.bodyEl.setHeight(h-this.diff);
2960
2961         this.fireEvent('resize', this);
2962
2963     },
2964     setContentSize  : function(w, h)
2965     {
2966
2967     },
2968     onButtonClick: function(btn,e)
2969     {
2970         //Roo.log([a,b,c]);
2971         this.fireEvent('btnclick', btn.name, e);
2972     },
2973      /**
2974      * Set the title of the Dialog
2975      * @param {String} str new Title
2976      */
2977     setTitle: function(str) {
2978         this.titleEl.dom.innerHTML = str;
2979     },
2980     /**
2981      * Set the body of the Dialog
2982      * @param {String} str new Title
2983      */
2984     setBody: function(str) {
2985         this.bodyEl.dom.innerHTML = str;
2986     },
2987     /**
2988      * Set the body of the Dialog using the template
2989      * @param {Obj} data - apply this data to the template and replace the body contents.
2990      */
2991     applyBody: function(obj)
2992     {
2993         if (!this.tmpl) {
2994             Roo.log("Error - using apply Body without a template");
2995             //code
2996         }
2997         this.tmpl.overwrite(this.bodyEl, obj);
2998     }
2999
3000 });
3001
3002
3003 Roo.apply(Roo.bootstrap.Modal,  {
3004     /**
3005          * Button config that displays a single OK button
3006          * @type Object
3007          */
3008         OK :  [{
3009             name : 'ok',
3010             weight : 'primary',
3011             html : 'OK'
3012         }],
3013         /**
3014          * Button config that displays Yes and No buttons
3015          * @type Object
3016          */
3017         YESNO : [
3018             {
3019                 name  : 'no',
3020                 html : 'No'
3021             },
3022             {
3023                 name  :'yes',
3024                 weight : 'primary',
3025                 html : 'Yes'
3026             }
3027         ],
3028
3029         /**
3030          * Button config that displays OK and Cancel buttons
3031          * @type Object
3032          */
3033         OKCANCEL : [
3034             {
3035                name : 'cancel',
3036                 html : 'Cancel'
3037             },
3038             {
3039                 name : 'ok',
3040                 weight : 'primary',
3041                 html : 'OK'
3042             }
3043         ],
3044         /**
3045          * Button config that displays Yes, No and Cancel buttons
3046          * @type Object
3047          */
3048         YESNOCANCEL : [
3049             {
3050                 name : 'yes',
3051                 weight : 'primary',
3052                 html : 'Yes'
3053             },
3054             {
3055                 name : 'no',
3056                 html : 'No'
3057             },
3058             {
3059                 name : 'cancel',
3060                 html : 'Cancel'
3061             }
3062         ],
3063         
3064         zIndex : 10001
3065 });
3066 /*
3067  * - LGPL
3068  *
3069  * messagebox - can be used as a replace
3070  * 
3071  */
3072 /**
3073  * @class Roo.MessageBox
3074  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3075  * Example usage:
3076  *<pre><code>
3077 // Basic alert:
3078 Roo.Msg.alert('Status', 'Changes saved successfully.');
3079
3080 // Prompt for user data:
3081 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3082     if (btn == 'ok'){
3083         // process text value...
3084     }
3085 });
3086
3087 // Show a dialog using config options:
3088 Roo.Msg.show({
3089    title:'Save Changes?',
3090    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3091    buttons: Roo.Msg.YESNOCANCEL,
3092    fn: processResult,
3093    animEl: 'elId'
3094 });
3095 </code></pre>
3096  * @singleton
3097  */
3098 Roo.bootstrap.MessageBox = function(){
3099     var dlg, opt, mask, waitTimer;
3100     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3101     var buttons, activeTextEl, bwidth;
3102
3103     
3104     // private
3105     var handleButton = function(button){
3106         dlg.hide();
3107         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3108     };
3109
3110     // private
3111     var handleHide = function(){
3112         if(opt && opt.cls){
3113             dlg.el.removeClass(opt.cls);
3114         }
3115         //if(waitTimer){
3116         //    Roo.TaskMgr.stop(waitTimer);
3117         //    waitTimer = null;
3118         //}
3119     };
3120
3121     // private
3122     var updateButtons = function(b){
3123         var width = 0;
3124         if(!b){
3125             buttons["ok"].hide();
3126             buttons["cancel"].hide();
3127             buttons["yes"].hide();
3128             buttons["no"].hide();
3129             //dlg.footer.dom.style.display = 'none';
3130             return width;
3131         }
3132         dlg.footerEl.dom.style.display = '';
3133         for(var k in buttons){
3134             if(typeof buttons[k] != "function"){
3135                 if(b[k]){
3136                     buttons[k].show();
3137                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3138                     width += buttons[k].el.getWidth()+15;
3139                 }else{
3140                     buttons[k].hide();
3141                 }
3142             }
3143         }
3144         return width;
3145     };
3146
3147     // private
3148     var handleEsc = function(d, k, e){
3149         if(opt && opt.closable !== false){
3150             dlg.hide();
3151         }
3152         if(e){
3153             e.stopEvent();
3154         }
3155     };
3156
3157     return {
3158         /**
3159          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3160          * @return {Roo.BasicDialog} The BasicDialog element
3161          */
3162         getDialog : function(){
3163            if(!dlg){
3164                 dlg = new Roo.bootstrap.Modal( {
3165                     //draggable: true,
3166                     //resizable:false,
3167                     //constraintoviewport:false,
3168                     //fixedcenter:true,
3169                     //collapsible : false,
3170                     //shim:true,
3171                     //modal: true,
3172                 //    width: 'auto',
3173                   //  height:100,
3174                     //buttonAlign:"center",
3175                     closeClick : function(){
3176                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3177                             handleButton("no");
3178                         }else{
3179                             handleButton("cancel");
3180                         }
3181                     }
3182                 });
3183                 dlg.render();
3184                 dlg.on("hide", handleHide);
3185                 mask = dlg.mask;
3186                 //dlg.addKeyListener(27, handleEsc);
3187                 buttons = {};
3188                 this.buttons = buttons;
3189                 var bt = this.buttonText;
3190                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3191                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3192                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3193                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3194                 //Roo.log(buttons);
3195                 bodyEl = dlg.bodyEl.createChild({
3196
3197                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3198                         '<textarea class="roo-mb-textarea"></textarea>' +
3199                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3200                 });
3201                 msgEl = bodyEl.dom.firstChild;
3202                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3203                 textboxEl.enableDisplayMode();
3204                 textboxEl.addKeyListener([10,13], function(){
3205                     if(dlg.isVisible() && opt && opt.buttons){
3206                         if(opt.buttons.ok){
3207                             handleButton("ok");
3208                         }else if(opt.buttons.yes){
3209                             handleButton("yes");
3210                         }
3211                     }
3212                 });
3213                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3214                 textareaEl.enableDisplayMode();
3215                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3216                 progressEl.enableDisplayMode();
3217                 
3218                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3219                 var pf = progressEl.dom.firstChild;
3220                 if (pf) {
3221                     pp = Roo.get(pf.firstChild);
3222                     pp.setHeight(pf.offsetHeight);
3223                 }
3224                 
3225             }
3226             return dlg;
3227         },
3228
3229         /**
3230          * Updates the message box body text
3231          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3232          * the XHTML-compliant non-breaking space character '&amp;#160;')
3233          * @return {Roo.MessageBox} This message box
3234          */
3235         updateText : function(text)
3236         {
3237             if(!dlg.isVisible() && !opt.width){
3238                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3239                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3240             }
3241             msgEl.innerHTML = text || '&#160;';
3242       
3243             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3244             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3245             var w = Math.max(
3246                     Math.min(opt.width || cw , this.maxWidth), 
3247                     Math.max(opt.minWidth || this.minWidth, bwidth)
3248             );
3249             if(opt.prompt){
3250                 activeTextEl.setWidth(w);
3251             }
3252             if(dlg.isVisible()){
3253                 dlg.fixedcenter = false;
3254             }
3255             // to big, make it scroll. = But as usual stupid IE does not support
3256             // !important..
3257             
3258             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3259                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3260                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3261             } else {
3262                 bodyEl.dom.style.height = '';
3263                 bodyEl.dom.style.overflowY = '';
3264             }
3265             if (cw > w) {
3266                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3267             } else {
3268                 bodyEl.dom.style.overflowX = '';
3269             }
3270             
3271             dlg.setContentSize(w, bodyEl.getHeight());
3272             if(dlg.isVisible()){
3273                 dlg.fixedcenter = true;
3274             }
3275             return this;
3276         },
3277
3278         /**
3279          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3280          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3281          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3282          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3283          * @return {Roo.MessageBox} This message box
3284          */
3285         updateProgress : function(value, text){
3286             if(text){
3287                 this.updateText(text);
3288             }
3289             
3290             if (pp) { // weird bug on my firefox - for some reason this is not defined
3291                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3292                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3293             }
3294             return this;
3295         },        
3296
3297         /**
3298          * Returns true if the message box is currently displayed
3299          * @return {Boolean} True if the message box is visible, else false
3300          */
3301         isVisible : function(){
3302             return dlg && dlg.isVisible();  
3303         },
3304
3305         /**
3306          * Hides the message box if it is displayed
3307          */
3308         hide : function(){
3309             if(this.isVisible()){
3310                 dlg.hide();
3311             }  
3312         },
3313
3314         /**
3315          * Displays a new message box, or reinitializes an existing message box, based on the config options
3316          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3317          * The following config object properties are supported:
3318          * <pre>
3319 Property    Type             Description
3320 ----------  ---------------  ------------------------------------------------------------------------------------
3321 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3322                                    closes (defaults to undefined)
3323 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3324                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3325 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3326                                    progress and wait dialogs will ignore this property and always hide the
3327                                    close button as they can only be closed programmatically.
3328 cls               String           A custom CSS class to apply to the message box element
3329 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3330                                    displayed (defaults to 75)
3331 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3332                                    function will be btn (the name of the button that was clicked, if applicable,
3333                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3334                                    Progress and wait dialogs will ignore this option since they do not respond to
3335                                    user actions and can only be closed programmatically, so any required function
3336                                    should be called by the same code after it closes the dialog.
3337 icon              String           A CSS class that provides a background image to be used as an icon for
3338                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3339 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3340 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3341 modal             Boolean          False to allow user interaction with the page while the message box is
3342                                    displayed (defaults to true)
3343 msg               String           A string that will replace the existing message box body text (defaults
3344                                    to the XHTML-compliant non-breaking space character '&#160;')
3345 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3346 progress          Boolean          True to display a progress bar (defaults to false)
3347 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3348 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3349 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3350 title             String           The title text
3351 value             String           The string value to set into the active textbox element if displayed
3352 wait              Boolean          True to display a progress bar (defaults to false)
3353 width             Number           The width of the dialog in pixels
3354 </pre>
3355          *
3356          * Example usage:
3357          * <pre><code>
3358 Roo.Msg.show({
3359    title: 'Address',
3360    msg: 'Please enter your address:',
3361    width: 300,
3362    buttons: Roo.MessageBox.OKCANCEL,
3363    multiline: true,
3364    fn: saveAddress,
3365    animEl: 'addAddressBtn'
3366 });
3367 </code></pre>
3368          * @param {Object} config Configuration options
3369          * @return {Roo.MessageBox} This message box
3370          */
3371         show : function(options)
3372         {
3373             
3374             // this causes nightmares if you show one dialog after another
3375             // especially on callbacks..
3376              
3377             if(this.isVisible()){
3378                 
3379                 this.hide();
3380                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3381                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3382                 Roo.log("New Dialog Message:" +  options.msg )
3383                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3384                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3385                 
3386             }
3387             var d = this.getDialog();
3388             opt = options;
3389             d.setTitle(opt.title || "&#160;");
3390             d.closeEl.setDisplayed(opt.closable !== false);
3391             activeTextEl = textboxEl;
3392             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3393             if(opt.prompt){
3394                 if(opt.multiline){
3395                     textboxEl.hide();
3396                     textareaEl.show();
3397                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3398                         opt.multiline : this.defaultTextHeight);
3399                     activeTextEl = textareaEl;
3400                 }else{
3401                     textboxEl.show();
3402                     textareaEl.hide();
3403                 }
3404             }else{
3405                 textboxEl.hide();
3406                 textareaEl.hide();
3407             }
3408             progressEl.setDisplayed(opt.progress === true);
3409             this.updateProgress(0);
3410             activeTextEl.dom.value = opt.value || "";
3411             if(opt.prompt){
3412                 dlg.setDefaultButton(activeTextEl);
3413             }else{
3414                 var bs = opt.buttons;
3415                 var db = null;
3416                 if(bs && bs.ok){
3417                     db = buttons["ok"];
3418                 }else if(bs && bs.yes){
3419                     db = buttons["yes"];
3420                 }
3421                 dlg.setDefaultButton(db);
3422             }
3423             bwidth = updateButtons(opt.buttons);
3424             this.updateText(opt.msg);
3425             if(opt.cls){
3426                 d.el.addClass(opt.cls);
3427             }
3428             d.proxyDrag = opt.proxyDrag === true;
3429             d.modal = opt.modal !== false;
3430             d.mask = opt.modal !== false ? mask : false;
3431             if(!d.isVisible()){
3432                 // force it to the end of the z-index stack so it gets a cursor in FF
3433                 document.body.appendChild(dlg.el.dom);
3434                 d.animateTarget = null;
3435                 d.show(options.animEl);
3436             }
3437             return this;
3438         },
3439
3440         /**
3441          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3442          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3443          * and closing the message box when the process is complete.
3444          * @param {String} title The title bar text
3445          * @param {String} msg The message box body text
3446          * @return {Roo.MessageBox} This message box
3447          */
3448         progress : function(title, msg){
3449             this.show({
3450                 title : title,
3451                 msg : msg,
3452                 buttons: false,
3453                 progress:true,
3454                 closable:false,
3455                 minWidth: this.minProgressWidth,
3456                 modal : true
3457             });
3458             return this;
3459         },
3460
3461         /**
3462          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3463          * If a callback function is passed it will be called after the user clicks the button, and the
3464          * id of the button that was clicked will be passed as the only parameter to the callback
3465          * (could also be the top-right close button).
3466          * @param {String} title The title bar text
3467          * @param {String} msg The message box body text
3468          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3469          * @param {Object} scope (optional) The scope of the callback function
3470          * @return {Roo.MessageBox} This message box
3471          */
3472         alert : function(title, msg, fn, scope)
3473         {
3474             this.show({
3475                 title : title,
3476                 msg : msg,
3477                 buttons: this.OK,
3478                 fn: fn,
3479                 closable : false,
3480                 scope : scope,
3481                 modal : true
3482             });
3483             return this;
3484         },
3485
3486         /**
3487          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3488          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3489          * You are responsible for closing the message box when the process is complete.
3490          * @param {String} msg The message box body text
3491          * @param {String} title (optional) The title bar text
3492          * @return {Roo.MessageBox} This message box
3493          */
3494         wait : function(msg, title){
3495             this.show({
3496                 title : title,
3497                 msg : msg,
3498                 buttons: false,
3499                 closable:false,
3500                 progress:true,
3501                 modal:true,
3502                 width:300,
3503                 wait:true
3504             });
3505             waitTimer = Roo.TaskMgr.start({
3506                 run: function(i){
3507                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3508                 },
3509                 interval: 1000
3510             });
3511             return this;
3512         },
3513
3514         /**
3515          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3516          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3517          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3518          * @param {String} title The title bar text
3519          * @param {String} msg The message box body text
3520          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3521          * @param {Object} scope (optional) The scope of the callback function
3522          * @return {Roo.MessageBox} This message box
3523          */
3524         confirm : function(title, msg, fn, scope){
3525             this.show({
3526                 title : title,
3527                 msg : msg,
3528                 buttons: this.YESNO,
3529                 fn: fn,
3530                 scope : scope,
3531                 modal : true
3532             });
3533             return this;
3534         },
3535
3536         /**
3537          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3538          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3539          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3540          * (could also be the top-right close button) and the text that was entered will be passed as the two
3541          * parameters to the callback.
3542          * @param {String} title The title bar text
3543          * @param {String} msg The message box body text
3544          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3545          * @param {Object} scope (optional) The scope of the callback function
3546          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3547          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3548          * @return {Roo.MessageBox} This message box
3549          */
3550         prompt : function(title, msg, fn, scope, multiline){
3551             this.show({
3552                 title : title,
3553                 msg : msg,
3554                 buttons: this.OKCANCEL,
3555                 fn: fn,
3556                 minWidth:250,
3557                 scope : scope,
3558                 prompt:true,
3559                 multiline: multiline,
3560                 modal : true
3561             });
3562             return this;
3563         },
3564
3565         /**
3566          * Button config that displays a single OK button
3567          * @type Object
3568          */
3569         OK : {ok:true},
3570         /**
3571          * Button config that displays Yes and No buttons
3572          * @type Object
3573          */
3574         YESNO : {yes:true, no:true},
3575         /**
3576          * Button config that displays OK and Cancel buttons
3577          * @type Object
3578          */
3579         OKCANCEL : {ok:true, cancel:true},
3580         /**
3581          * Button config that displays Yes, No and Cancel buttons
3582          * @type Object
3583          */
3584         YESNOCANCEL : {yes:true, no:true, cancel:true},
3585
3586         /**
3587          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3588          * @type Number
3589          */
3590         defaultTextHeight : 75,
3591         /**
3592          * The maximum width in pixels of the message box (defaults to 600)
3593          * @type Number
3594          */
3595         maxWidth : 600,
3596         /**
3597          * The minimum width in pixels of the message box (defaults to 100)
3598          * @type Number
3599          */
3600         minWidth : 100,
3601         /**
3602          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3603          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3604          * @type Number
3605          */
3606         minProgressWidth : 250,
3607         /**
3608          * An object containing the default button text strings that can be overriden for localized language support.
3609          * Supported properties are: ok, cancel, yes and no.
3610          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3611          * @type Object
3612          */
3613         buttonText : {
3614             ok : "OK",
3615             cancel : "Cancel",
3616             yes : "Yes",
3617             no : "No"
3618         }
3619     };
3620 }();
3621
3622 /**
3623  * Shorthand for {@link Roo.MessageBox}
3624  */
3625 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3626 Roo.Msg = Roo.Msg || Roo.MessageBox;
3627 /*
3628  * - LGPL
3629  *
3630  * navbar
3631  * 
3632  */
3633
3634 /**
3635  * @class Roo.bootstrap.Navbar
3636  * @extends Roo.bootstrap.Component
3637  * Bootstrap Navbar class
3638
3639  * @constructor
3640  * Create a new Navbar
3641  * @param {Object} config The config object
3642  */
3643
3644
3645 Roo.bootstrap.Navbar = function(config){
3646     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3647     this.addEvents({
3648         // raw events
3649         /**
3650          * @event beforetoggle
3651          * Fire before toggle the menu
3652          * @param {Roo.EventObject} e
3653          */
3654         "beforetoggle" : true
3655     });
3656 };
3657
3658 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3659     
3660     
3661    
3662     // private
3663     navItems : false,
3664     loadMask : false,
3665     
3666     
3667     getAutoCreate : function(){
3668         
3669         
3670         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3671         
3672     },
3673     
3674     initEvents :function ()
3675     {
3676         //Roo.log(this.el.select('.navbar-toggle',true));
3677         this.el.select('.navbar-toggle',true).on('click', function() {
3678             if(this.fireEvent('beforetoggle', this) !== false){
3679                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3680             }
3681             
3682         }, this);
3683         
3684         var mark = {
3685             tag: "div",
3686             cls:"x-dlg-mask"
3687         };
3688         
3689         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3690         
3691         var size = this.el.getSize();
3692         this.maskEl.setSize(size.width, size.height);
3693         this.maskEl.enableDisplayMode("block");
3694         this.maskEl.hide();
3695         
3696         if(this.loadMask){
3697             this.maskEl.show();
3698         }
3699     },
3700     
3701     
3702     getChildContainer : function()
3703     {
3704         if (this.el.select('.collapse').getCount()) {
3705             return this.el.select('.collapse',true).first();
3706         }
3707         
3708         return this.el;
3709     },
3710     
3711     mask : function()
3712     {
3713         this.maskEl.show();
3714     },
3715     
3716     unmask : function()
3717     {
3718         this.maskEl.hide();
3719     } 
3720     
3721     
3722     
3723     
3724 });
3725
3726
3727
3728  
3729
3730  /*
3731  * - LGPL
3732  *
3733  * navbar
3734  * 
3735  */
3736
3737 /**
3738  * @class Roo.bootstrap.NavSimplebar
3739  * @extends Roo.bootstrap.Navbar
3740  * Bootstrap Sidebar class
3741  *
3742  * @cfg {Boolean} inverse is inverted color
3743  * 
3744  * @cfg {String} type (nav | pills | tabs)
3745  * @cfg {Boolean} arrangement stacked | justified
3746  * @cfg {String} align (left | right) alignment
3747  * 
3748  * @cfg {Boolean} main (true|false) main nav bar? default false
3749  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3750  * 
3751  * @cfg {String} tag (header|footer|nav|div) default is nav 
3752
3753  * 
3754  * 
3755  * 
3756  * @constructor
3757  * Create a new Sidebar
3758  * @param {Object} config The config object
3759  */
3760
3761
3762 Roo.bootstrap.NavSimplebar = function(config){
3763     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3764 };
3765
3766 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3767     
3768     inverse: false,
3769     
3770     type: false,
3771     arrangement: '',
3772     align : false,
3773     
3774     
3775     
3776     main : false,
3777     
3778     
3779     tag : false,
3780     
3781     
3782     getAutoCreate : function(){
3783         
3784         
3785         var cfg = {
3786             tag : this.tag || 'div',
3787             cls : 'navbar'
3788         };
3789           
3790         
3791         cfg.cn = [
3792             {
3793                 cls: 'nav',
3794                 tag : 'ul'
3795             }
3796         ];
3797         
3798          
3799         this.type = this.type || 'nav';
3800         if (['tabs','pills'].indexOf(this.type)!==-1) {
3801             cfg.cn[0].cls += ' nav-' + this.type
3802         
3803         
3804         } else {
3805             if (this.type!=='nav') {
3806                 Roo.log('nav type must be nav/tabs/pills')
3807             }
3808             cfg.cn[0].cls += ' navbar-nav'
3809         }
3810         
3811         
3812         
3813         
3814         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3815             cfg.cn[0].cls += ' nav-' + this.arrangement;
3816         }
3817         
3818         
3819         if (this.align === 'right') {
3820             cfg.cn[0].cls += ' navbar-right';
3821         }
3822         
3823         if (this.inverse) {
3824             cfg.cls += ' navbar-inverse';
3825             
3826         }
3827         
3828         
3829         return cfg;
3830     
3831         
3832     }
3833     
3834     
3835     
3836 });
3837
3838
3839
3840  
3841
3842  
3843        /*
3844  * - LGPL
3845  *
3846  * navbar
3847  * 
3848  */
3849
3850 /**
3851  * @class Roo.bootstrap.NavHeaderbar
3852  * @extends Roo.bootstrap.NavSimplebar
3853  * Bootstrap Sidebar class
3854  *
3855  * @cfg {String} brand what is brand
3856  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3857  * @cfg {String} brand_href href of the brand
3858  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3859  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3860  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3861  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3862  * 
3863  * @constructor
3864  * Create a new Sidebar
3865  * @param {Object} config The config object
3866  */
3867
3868
3869 Roo.bootstrap.NavHeaderbar = function(config){
3870     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3871       
3872 };
3873
3874 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3875     
3876     position: '',
3877     brand: '',
3878     brand_href: false,
3879     srButton : true,
3880     autohide : false,
3881     desktopCenter : false,
3882    
3883     
3884     getAutoCreate : function(){
3885         
3886         var   cfg = {
3887             tag: this.nav || 'nav',
3888             cls: 'navbar',
3889             role: 'navigation',
3890             cn: []
3891         };
3892         
3893         var cn = cfg.cn;
3894         if (this.desktopCenter) {
3895             cn.push({cls : 'container', cn : []});
3896             cn = cn[0].cn;
3897         }
3898         
3899         if(this.srButton){
3900             cn.push({
3901                 tag: 'div',
3902                 cls: 'navbar-header',
3903                 cn: [
3904                     {
3905                         tag: 'button',
3906                         type: 'button',
3907                         cls: 'navbar-toggle',
3908                         'data-toggle': 'collapse',
3909                         cn: [
3910                             {
3911                                 tag: 'span',
3912                                 cls: 'sr-only',
3913                                 html: 'Toggle navigation'
3914                             },
3915                             {
3916                                 tag: 'span',
3917                                 cls: 'icon-bar'
3918                             },
3919                             {
3920                                 tag: 'span',
3921                                 cls: 'icon-bar'
3922                             },
3923                             {
3924                                 tag: 'span',
3925                                 cls: 'icon-bar'
3926                             }
3927                         ]
3928                     }
3929                 ]
3930             });
3931         }
3932         
3933         cn.push({
3934             tag: 'div',
3935             cls: 'collapse navbar-collapse',
3936             cn : []
3937         });
3938         
3939         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3940         
3941         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3942             cfg.cls += ' navbar-' + this.position;
3943             
3944             // tag can override this..
3945             
3946             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3947         }
3948         
3949         if (this.brand !== '') {
3950             cn[0].cn.push({
3951                 tag: 'a',
3952                 href: this.brand_href ? this.brand_href : '#',
3953                 cls: 'navbar-brand',
3954                 cn: [
3955                 this.brand
3956                 ]
3957             });
3958         }
3959         
3960         if(this.main){
3961             cfg.cls += ' main-nav';
3962         }
3963         
3964         
3965         return cfg;
3966
3967         
3968     },
3969     getHeaderChildContainer : function()
3970     {
3971         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3972             return this.el.select('.navbar-header',true).first();
3973         }
3974         
3975         return this.getChildContainer();
3976     },
3977     
3978     
3979     initEvents : function()
3980     {
3981         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3982         
3983         if (this.autohide) {
3984             
3985             var prevScroll = 0;
3986             var ft = this.el;
3987             
3988             Roo.get(document).on('scroll',function(e) {
3989                 var ns = Roo.get(document).getScroll().top;
3990                 var os = prevScroll;
3991                 prevScroll = ns;
3992                 
3993                 if(ns > os){
3994                     ft.removeClass('slideDown');
3995                     ft.addClass('slideUp');
3996                     return;
3997                 }
3998                 ft.removeClass('slideUp');
3999                 ft.addClass('slideDown');
4000                  
4001               
4002           },this);
4003         }
4004     }    
4005     
4006 });
4007
4008
4009
4010  
4011
4012  /*
4013  * - LGPL
4014  *
4015  * navbar
4016  * 
4017  */
4018
4019 /**
4020  * @class Roo.bootstrap.NavSidebar
4021  * @extends Roo.bootstrap.Navbar
4022  * Bootstrap Sidebar class
4023  * 
4024  * @constructor
4025  * Create a new Sidebar
4026  * @param {Object} config The config object
4027  */
4028
4029
4030 Roo.bootstrap.NavSidebar = function(config){
4031     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4032 };
4033
4034 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4035     
4036     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4037     
4038     getAutoCreate : function(){
4039         
4040         
4041         return  {
4042             tag: 'div',
4043             cls: 'sidebar sidebar-nav'
4044         };
4045     
4046         
4047     }
4048     
4049     
4050     
4051 });
4052
4053
4054
4055  
4056
4057  /*
4058  * - LGPL
4059  *
4060  * nav group
4061  * 
4062  */
4063
4064 /**
4065  * @class Roo.bootstrap.NavGroup
4066  * @extends Roo.bootstrap.Component
4067  * Bootstrap NavGroup class
4068  * @cfg {String} align (left|right)
4069  * @cfg {Boolean} inverse
4070  * @cfg {String} type (nav|pills|tab) default nav
4071  * @cfg {String} navId - reference Id for navbar.
4072
4073  * 
4074  * @constructor
4075  * Create a new nav group
4076  * @param {Object} config The config object
4077  */
4078
4079 Roo.bootstrap.NavGroup = function(config){
4080     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4081     this.navItems = [];
4082    
4083     Roo.bootstrap.NavGroup.register(this);
4084      this.addEvents({
4085         /**
4086              * @event changed
4087              * Fires when the active item changes
4088              * @param {Roo.bootstrap.NavGroup} this
4089              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4090              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4091          */
4092         'changed': true
4093      });
4094     
4095 };
4096
4097 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4098     
4099     align: '',
4100     inverse: false,
4101     form: false,
4102     type: 'nav',
4103     navId : '',
4104     // private
4105     
4106     navItems : false, 
4107     
4108     getAutoCreate : function()
4109     {
4110         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4111         
4112         cfg = {
4113             tag : 'ul',
4114             cls: 'nav' 
4115         };
4116         
4117         if (['tabs','pills'].indexOf(this.type)!==-1) {
4118             cfg.cls += ' nav-' + this.type
4119         } else {
4120             if (this.type!=='nav') {
4121                 Roo.log('nav type must be nav/tabs/pills')
4122             }
4123             cfg.cls += ' navbar-nav'
4124         }
4125         
4126         if (this.parent() && this.parent().sidebar) {
4127             cfg = {
4128                 tag: 'ul',
4129                 cls: 'dashboard-menu sidebar-menu'
4130             };
4131             
4132             return cfg;
4133         }
4134         
4135         if (this.form === true) {
4136             cfg = {
4137                 tag: 'form',
4138                 cls: 'navbar-form'
4139             };
4140             
4141             if (this.align === 'right') {
4142                 cfg.cls += ' navbar-right';
4143             } else {
4144                 cfg.cls += ' navbar-left';
4145             }
4146         }
4147         
4148         if (this.align === 'right') {
4149             cfg.cls += ' navbar-right';
4150         }
4151         
4152         if (this.inverse) {
4153             cfg.cls += ' navbar-inverse';
4154             
4155         }
4156         
4157         
4158         return cfg;
4159     },
4160     /**
4161     * sets the active Navigation item
4162     * @param {Roo.bootstrap.NavItem} the new current navitem
4163     */
4164     setActiveItem : function(item)
4165     {
4166         var prev = false;
4167         Roo.each(this.navItems, function(v){
4168             if (v == item) {
4169                 return ;
4170             }
4171             if (v.isActive()) {
4172                 v.setActive(false, true);
4173                 prev = v;
4174                 
4175             }
4176             
4177         });
4178
4179         item.setActive(true, true);
4180         this.fireEvent('changed', this, item, prev);
4181         
4182         
4183     },
4184     /**
4185     * gets the active Navigation item
4186     * @return {Roo.bootstrap.NavItem} the current navitem
4187     */
4188     getActive : function()
4189     {
4190         
4191         var prev = false;
4192         Roo.each(this.navItems, function(v){
4193             
4194             if (v.isActive()) {
4195                 prev = v;
4196                 
4197             }
4198             
4199         });
4200         return prev;
4201     },
4202     
4203     indexOfNav : function()
4204     {
4205         
4206         var prev = false;
4207         Roo.each(this.navItems, function(v,i){
4208             
4209             if (v.isActive()) {
4210                 prev = i;
4211                 
4212             }
4213             
4214         });
4215         return prev;
4216     },
4217     /**
4218     * adds a Navigation item
4219     * @param {Roo.bootstrap.NavItem} the navitem to add
4220     */
4221     addItem : function(cfg)
4222     {
4223         var cn = new Roo.bootstrap.NavItem(cfg);
4224         this.register(cn);
4225         cn.parentId = this.id;
4226         cn.onRender(this.el, null);
4227         return cn;
4228     },
4229     /**
4230     * register a Navigation item
4231     * @param {Roo.bootstrap.NavItem} the navitem to add
4232     */
4233     register : function(item)
4234     {
4235         this.navItems.push( item);
4236         item.navId = this.navId;
4237     
4238     },
4239     
4240     /**
4241     * clear all the Navigation item
4242     */
4243    
4244     clearAll : function()
4245     {
4246         this.navItems = [];
4247         this.el.dom.innerHTML = '';
4248     },
4249     
4250     getNavItem: function(tabId)
4251     {
4252         var ret = false;
4253         Roo.each(this.navItems, function(e) {
4254             if (e.tabId == tabId) {
4255                ret =  e;
4256                return false;
4257             }
4258             return true;
4259             
4260         });
4261         return ret;
4262     },
4263     
4264     setActiveNext : function()
4265     {
4266         var i = this.indexOfNav(this.getActive());
4267         if (i > this.navItems.length) {
4268             return;
4269         }
4270         this.setActiveItem(this.navItems[i+1]);
4271     },
4272     setActivePrev : function()
4273     {
4274         var i = this.indexOfNav(this.getActive());
4275         if (i  < 1) {
4276             return;
4277         }
4278         this.setActiveItem(this.navItems[i-1]);
4279     },
4280     clearWasActive : function(except) {
4281         Roo.each(this.navItems, function(e) {
4282             if (e.tabId != except.tabId && e.was_active) {
4283                e.was_active = false;
4284                return false;
4285             }
4286             return true;
4287             
4288         });
4289     },
4290     getWasActive : function ()
4291     {
4292         var r = false;
4293         Roo.each(this.navItems, function(e) {
4294             if (e.was_active) {
4295                r = e;
4296                return false;
4297             }
4298             return true;
4299             
4300         });
4301         return r;
4302     }
4303     
4304     
4305 });
4306
4307  
4308 Roo.apply(Roo.bootstrap.NavGroup, {
4309     
4310     groups: {},
4311      /**
4312     * register a Navigation Group
4313     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4314     */
4315     register : function(navgrp)
4316     {
4317         this.groups[navgrp.navId] = navgrp;
4318         
4319     },
4320     /**
4321     * fetch a Navigation Group based on the navigation ID
4322     * @param {string} the navgroup to add
4323     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4324     */
4325     get: function(navId) {
4326         if (typeof(this.groups[navId]) == 'undefined') {
4327             return false;
4328             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4329         }
4330         return this.groups[navId] ;
4331     }
4332     
4333     
4334     
4335 });
4336
4337  /*
4338  * - LGPL
4339  *
4340  * row
4341  * 
4342  */
4343
4344 /**
4345  * @class Roo.bootstrap.NavItem
4346  * @extends Roo.bootstrap.Component
4347  * Bootstrap Navbar.NavItem class
4348  * @cfg {String} href  link to
4349  * @cfg {String} html content of button
4350  * @cfg {String} badge text inside badge
4351  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4352  * @cfg {String} glyphicon name of glyphicon
4353  * @cfg {String} icon name of font awesome icon
4354  * @cfg {Boolean} active Is item active
4355  * @cfg {Boolean} disabled Is item disabled
4356  
4357  * @cfg {Boolean} preventDefault (true | false) default false
4358  * @cfg {String} tabId the tab that this item activates.
4359  * @cfg {String} tagtype (a|span) render as a href or span?
4360  * @cfg {Boolean} animateRef (true|false) link to element default false  
4361   
4362  * @constructor
4363  * Create a new Navbar Item
4364  * @param {Object} config The config object
4365  */
4366 Roo.bootstrap.NavItem = function(config){
4367     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4368     this.addEvents({
4369         // raw events
4370         /**
4371          * @event click
4372          * The raw click event for the entire grid.
4373          * @param {Roo.EventObject} e
4374          */
4375         "click" : true,
4376          /**
4377             * @event changed
4378             * Fires when the active item active state changes
4379             * @param {Roo.bootstrap.NavItem} this
4380             * @param {boolean} state the new state
4381              
4382          */
4383         'changed': true,
4384         /**
4385             * @event scrollto
4386             * Fires when scroll to element
4387             * @param {Roo.bootstrap.NavItem} this
4388             * @param {Object} options
4389             * @param {Roo.EventObject} e
4390              
4391          */
4392         'scrollto': true
4393     });
4394    
4395 };
4396
4397 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4398     
4399     href: false,
4400     html: '',
4401     badge: '',
4402     icon: false,
4403     glyphicon: false,
4404     active: false,
4405     preventDefault : false,
4406     tabId : false,
4407     tagtype : 'a',
4408     disabled : false,
4409     animateRef : false,
4410     was_active : false,
4411     
4412     getAutoCreate : function(){
4413          
4414         var cfg = {
4415             tag: 'li',
4416             cls: 'nav-item'
4417             
4418         };
4419         
4420         if (this.active) {
4421             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4422         }
4423         if (this.disabled) {
4424             cfg.cls += ' disabled';
4425         }
4426         
4427         if (this.href || this.html || this.glyphicon || this.icon) {
4428             cfg.cn = [
4429                 {
4430                     tag: this.tagtype,
4431                     href : this.href || "#",
4432                     html: this.html || ''
4433                 }
4434             ];
4435             
4436             if (this.icon) {
4437                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4438             }
4439
4440             if(this.glyphicon) {
4441                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4442             }
4443             
4444             if (this.menu) {
4445                 
4446                 cfg.cn[0].html += " <span class='caret'></span>";
4447              
4448             }
4449             
4450             if (this.badge !== '') {
4451                  
4452                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4453             }
4454         }
4455         
4456         
4457         
4458         return cfg;
4459     },
4460     initEvents: function() 
4461     {
4462         if (typeof (this.menu) != 'undefined') {
4463             this.menu.parentType = this.xtype;
4464             this.menu.triggerEl = this.el;
4465             this.menu = this.addxtype(Roo.apply({}, this.menu));
4466         }
4467         
4468         this.el.select('a',true).on('click', this.onClick, this);
4469         
4470         if(this.tagtype == 'span'){
4471             this.el.select('span',true).on('click', this.onClick, this);
4472         }
4473        
4474         // at this point parent should be available..
4475         this.parent().register(this);
4476     },
4477     
4478     onClick : function(e)
4479     {
4480         if (e.getTarget('.dropdown-menu-item')) {
4481             // did you click on a menu itemm.... - then don't trigger onclick..
4482             return;
4483         }
4484         
4485         if(
4486                 this.preventDefault || 
4487                 this.href == '#' 
4488         ){
4489             Roo.log("NavItem - prevent Default?");
4490             e.preventDefault();
4491         }
4492         
4493         if (this.disabled) {
4494             return;
4495         }
4496         
4497         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4498         if (tg && tg.transition) {
4499             Roo.log("waiting for the transitionend");
4500             return;
4501         }
4502         
4503         
4504         
4505         //Roo.log("fire event clicked");
4506         if(this.fireEvent('click', this, e) === false){
4507             return;
4508         };
4509         
4510         if(this.tagtype == 'span'){
4511             return;
4512         }
4513         
4514         //Roo.log(this.href);
4515         var ael = this.el.select('a',true).first();
4516         //Roo.log(ael);
4517         
4518         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4519             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4520             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4521                 return; // ignore... - it's a 'hash' to another page.
4522             }
4523             Roo.log("NavItem - prevent Default?");
4524             e.preventDefault();
4525             this.scrollToElement(e);
4526         }
4527         
4528         
4529         var p =  this.parent();
4530    
4531         if (['tabs','pills'].indexOf(p.type)!==-1) {
4532             if (typeof(p.setActiveItem) !== 'undefined') {
4533                 p.setActiveItem(this);
4534             }
4535         }
4536         
4537         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4538         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4539             // remove the collapsed menu expand...
4540             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4541         }
4542     },
4543     
4544     isActive: function () {
4545         return this.active
4546     },
4547     setActive : function(state, fire, is_was_active)
4548     {
4549         if (this.active && !state && this.navId) {
4550             this.was_active = true;
4551             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4552             if (nv) {
4553                 nv.clearWasActive(this);
4554             }
4555             
4556         }
4557         this.active = state;
4558         
4559         if (!state ) {
4560             this.el.removeClass('active');
4561         } else if (!this.el.hasClass('active')) {
4562             this.el.addClass('active');
4563         }
4564         if (fire) {
4565             this.fireEvent('changed', this, state);
4566         }
4567         
4568         // show a panel if it's registered and related..
4569         
4570         if (!this.navId || !this.tabId || !state || is_was_active) {
4571             return;
4572         }
4573         
4574         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4575         if (!tg) {
4576             return;
4577         }
4578         var pan = tg.getPanelByName(this.tabId);
4579         if (!pan) {
4580             return;
4581         }
4582         // if we can not flip to new panel - go back to old nav highlight..
4583         if (false == tg.showPanel(pan)) {
4584             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4585             if (nv) {
4586                 var onav = nv.getWasActive();
4587                 if (onav) {
4588                     onav.setActive(true, false, true);
4589                 }
4590             }
4591             
4592         }
4593         
4594         
4595         
4596     },
4597      // this should not be here...
4598     setDisabled : function(state)
4599     {
4600         this.disabled = state;
4601         if (!state ) {
4602             this.el.removeClass('disabled');
4603         } else if (!this.el.hasClass('disabled')) {
4604             this.el.addClass('disabled');
4605         }
4606         
4607     },
4608     
4609     /**
4610      * Fetch the element to display the tooltip on.
4611      * @return {Roo.Element} defaults to this.el
4612      */
4613     tooltipEl : function()
4614     {
4615         return this.el.select('' + this.tagtype + '', true).first();
4616     },
4617     
4618     scrollToElement : function(e)
4619     {
4620         var c = document.body;
4621         
4622         /*
4623          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4624          */
4625         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4626             c = document.documentElement;
4627         }
4628         
4629         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4630         
4631         if(!target){
4632             return;
4633         }
4634
4635         var o = target.calcOffsetsTo(c);
4636         
4637         var options = {
4638             target : target,
4639             value : o[1]
4640         };
4641         
4642         this.fireEvent('scrollto', this, options, e);
4643         
4644         Roo.get(c).scrollTo('top', options.value, true);
4645         
4646         return;
4647     }
4648 });
4649  
4650
4651  /*
4652  * - LGPL
4653  *
4654  * sidebar item
4655  *
4656  *  li
4657  *    <span> icon </span>
4658  *    <span> text </span>
4659  *    <span>badge </span>
4660  */
4661
4662 /**
4663  * @class Roo.bootstrap.NavSidebarItem
4664  * @extends Roo.bootstrap.NavItem
4665  * Bootstrap Navbar.NavSidebarItem class
4666  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4667  * {Boolean} open is the menu open
4668  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4669  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4670  * {String} buttonSize (sm|md|lg)the extra classes for the button
4671  * {Boolean} showArrow show arrow next to the text (default true)
4672  * @constructor
4673  * Create a new Navbar Button
4674  * @param {Object} config The config object
4675  */
4676 Roo.bootstrap.NavSidebarItem = function(config){
4677     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4678     this.addEvents({
4679         // raw events
4680         /**
4681          * @event click
4682          * The raw click event for the entire grid.
4683          * @param {Roo.EventObject} e
4684          */
4685         "click" : true,
4686          /**
4687             * @event changed
4688             * Fires when the active item active state changes
4689             * @param {Roo.bootstrap.NavSidebarItem} this
4690             * @param {boolean} state the new state
4691              
4692          */
4693         'changed': true
4694     });
4695    
4696 };
4697
4698 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4699     
4700     badgeWeight : 'default',
4701     
4702     open: false,
4703     
4704     buttonView : false,
4705     
4706     buttonWeight : 'default',
4707     
4708     buttonSize : 'md',
4709     
4710     showArrow : true,
4711     
4712     getAutoCreate : function(){
4713         
4714         
4715         var a = {
4716                 tag: 'a',
4717                 href : this.href || '#',
4718                 cls: '',
4719                 html : '',
4720                 cn : []
4721         };
4722         
4723         if(this.buttonView){
4724             a = {
4725                 tag: 'button',
4726                 href : this.href || '#',
4727                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4728                 html : this.html,
4729                 cn : []
4730             };
4731         }
4732         
4733         var cfg = {
4734             tag: 'li',
4735             cls: '',
4736             cn: [ a ]
4737         };
4738         
4739         if (this.active) {
4740             cfg.cls += ' active';
4741         }
4742         
4743         if (this.disabled) {
4744             cfg.cls += ' disabled';
4745         }
4746         if (this.open) {
4747             cfg.cls += ' open x-open';
4748         }
4749         // left icon..
4750         if (this.glyphicon || this.icon) {
4751             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4752             a.cn.push({ tag : 'i', cls : c }) ;
4753         }
4754         
4755         if(!this.buttonView){
4756             var span = {
4757                 tag: 'span',
4758                 html : this.html || ''
4759             };
4760
4761             a.cn.push(span);
4762             
4763         }
4764         
4765         if (this.badge !== '') {
4766             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4767         }
4768         
4769         if (this.menu) {
4770             
4771             if(this.showArrow){
4772                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4773             }
4774             
4775             a.cls += ' dropdown-toggle treeview' ;
4776         }
4777         
4778         return cfg;
4779     },
4780     
4781     initEvents : function()
4782     { 
4783         if (typeof (this.menu) != 'undefined') {
4784             this.menu.parentType = this.xtype;
4785             this.menu.triggerEl = this.el;
4786             this.menu = this.addxtype(Roo.apply({}, this.menu));
4787         }
4788         
4789         this.el.on('click', this.onClick, this);
4790         
4791         if(this.badge !== ''){
4792             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4793         }
4794         
4795     },
4796     
4797     onClick : function(e)
4798     {
4799         if(this.disabled){
4800             e.preventDefault();
4801             return;
4802         }
4803         
4804         if(this.preventDefault){
4805             e.preventDefault();
4806         }
4807         
4808         this.fireEvent('click', this);
4809     },
4810     
4811     disable : function()
4812     {
4813         this.setDisabled(true);
4814     },
4815     
4816     enable : function()
4817     {
4818         this.setDisabled(false);
4819     },
4820     
4821     setDisabled : function(state)
4822     {
4823         if(this.disabled == state){
4824             return;
4825         }
4826         
4827         this.disabled = state;
4828         
4829         if (state) {
4830             this.el.addClass('disabled');
4831             return;
4832         }
4833         
4834         this.el.removeClass('disabled');
4835         
4836         return;
4837     },
4838     
4839     setActive : function(state)
4840     {
4841         if(this.active == state){
4842             return;
4843         }
4844         
4845         this.active = state;
4846         
4847         if (state) {
4848             this.el.addClass('active');
4849             return;
4850         }
4851         
4852         this.el.removeClass('active');
4853         
4854         return;
4855     },
4856     
4857     isActive: function () 
4858     {
4859         return this.active;
4860     },
4861     
4862     setBadge : function(str)
4863     {
4864         if(!this.badgeEl){
4865             return;
4866         }
4867         
4868         this.badgeEl.dom.innerHTML = str;
4869     }
4870     
4871    
4872      
4873  
4874 });
4875  
4876
4877  /*
4878  * - LGPL
4879  *
4880  * row
4881  * 
4882  */
4883
4884 /**
4885  * @class Roo.bootstrap.Row
4886  * @extends Roo.bootstrap.Component
4887  * Bootstrap Row class (contains columns...)
4888  * 
4889  * @constructor
4890  * Create a new Row
4891  * @param {Object} config The config object
4892  */
4893
4894 Roo.bootstrap.Row = function(config){
4895     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4896 };
4897
4898 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4899     
4900     getAutoCreate : function(){
4901        return {
4902             cls: 'row clearfix'
4903        };
4904     }
4905     
4906     
4907 });
4908
4909  
4910
4911  /*
4912  * - LGPL
4913  *
4914  * element
4915  * 
4916  */
4917
4918 /**
4919  * @class Roo.bootstrap.Element
4920  * @extends Roo.bootstrap.Component
4921  * Bootstrap Element class
4922  * @cfg {String} html contents of the element
4923  * @cfg {String} tag tag of the element
4924  * @cfg {String} cls class of the element
4925  * @cfg {Boolean} preventDefault (true|false) default false
4926  * @cfg {Boolean} clickable (true|false) default false
4927  * 
4928  * @constructor
4929  * Create a new Element
4930  * @param {Object} config The config object
4931  */
4932
4933 Roo.bootstrap.Element = function(config){
4934     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4935     
4936     this.addEvents({
4937         // raw events
4938         /**
4939          * @event click
4940          * When a element is chick
4941          * @param {Roo.bootstrap.Element} this
4942          * @param {Roo.EventObject} e
4943          */
4944         "click" : true
4945     });
4946 };
4947
4948 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4949     
4950     tag: 'div',
4951     cls: '',
4952     html: '',
4953     preventDefault: false, 
4954     clickable: false,
4955     
4956     getAutoCreate : function(){
4957         
4958         var cfg = {
4959             tag: this.tag,
4960             // cls: this.cls, double assign in parent class Component.js :: onRender
4961             html: this.html
4962         };
4963         
4964         return cfg;
4965     },
4966     
4967     initEvents: function() 
4968     {
4969         Roo.bootstrap.Element.superclass.initEvents.call(this);
4970         
4971         if(this.clickable){
4972             this.el.on('click', this.onClick, this);
4973         }
4974         
4975     },
4976     
4977     onClick : function(e)
4978     {
4979         if(this.preventDefault){
4980             e.preventDefault();
4981         }
4982         
4983         this.fireEvent('click', this, e);
4984     },
4985     
4986     getValue : function()
4987     {
4988         return this.el.dom.innerHTML;
4989     },
4990     
4991     setValue : function(value)
4992     {
4993         this.el.dom.innerHTML = value;
4994     }
4995    
4996 });
4997
4998  
4999
5000  /*
5001  * - LGPL
5002  *
5003  * pagination
5004  * 
5005  */
5006
5007 /**
5008  * @class Roo.bootstrap.Pagination
5009  * @extends Roo.bootstrap.Component
5010  * Bootstrap Pagination class
5011  * @cfg {String} size xs | sm | md | lg
5012  * @cfg {Boolean} inverse false | true
5013  * 
5014  * @constructor
5015  * Create a new Pagination
5016  * @param {Object} config The config object
5017  */
5018
5019 Roo.bootstrap.Pagination = function(config){
5020     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5021 };
5022
5023 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
5024     
5025     cls: false,
5026     size: false,
5027     inverse: false,
5028     
5029     getAutoCreate : function(){
5030         var cfg = {
5031             tag: 'ul',
5032                 cls: 'pagination'
5033         };
5034         if (this.inverse) {
5035             cfg.cls += ' inverse';
5036         }
5037         if (this.html) {
5038             cfg.html=this.html;
5039         }
5040         if (this.cls) {
5041             cfg.cls += " " + this.cls;
5042         }
5043         return cfg;
5044     }
5045    
5046 });
5047
5048  
5049
5050  /*
5051  * - LGPL
5052  *
5053  * Pagination item
5054  * 
5055  */
5056
5057
5058 /**
5059  * @class Roo.bootstrap.PaginationItem
5060  * @extends Roo.bootstrap.Component
5061  * Bootstrap PaginationItem class
5062  * @cfg {String} html text
5063  * @cfg {String} href the link
5064  * @cfg {Boolean} preventDefault (true | false) default true
5065  * @cfg {Boolean} active (true | false) default false
5066  * @cfg {Boolean} disabled default false
5067  * 
5068  * 
5069  * @constructor
5070  * Create a new PaginationItem
5071  * @param {Object} config The config object
5072  */
5073
5074
5075 Roo.bootstrap.PaginationItem = function(config){
5076     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5077     this.addEvents({
5078         // raw events
5079         /**
5080          * @event click
5081          * The raw click event for the entire grid.
5082          * @param {Roo.EventObject} e
5083          */
5084         "click" : true
5085     });
5086 };
5087
5088 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5089     
5090     href : false,
5091     html : false,
5092     preventDefault: true,
5093     active : false,
5094     cls : false,
5095     disabled: false,
5096     
5097     getAutoCreate : function(){
5098         var cfg= {
5099             tag: 'li',
5100             cn: [
5101                 {
5102                     tag : 'a',
5103                     href : this.href ? this.href : '#',
5104                     html : this.html ? this.html : ''
5105                 }
5106             ]
5107         };
5108         
5109         if(this.cls){
5110             cfg.cls = this.cls;
5111         }
5112         
5113         if(this.disabled){
5114             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5115         }
5116         
5117         if(this.active){
5118             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5119         }
5120         
5121         return cfg;
5122     },
5123     
5124     initEvents: function() {
5125         
5126         this.el.on('click', this.onClick, this);
5127         
5128     },
5129     onClick : function(e)
5130     {
5131         Roo.log('PaginationItem on click ');
5132         if(this.preventDefault){
5133             e.preventDefault();
5134         }
5135         
5136         if(this.disabled){
5137             return;
5138         }
5139         
5140         this.fireEvent('click', this, e);
5141     }
5142    
5143 });
5144
5145  
5146
5147  /*
5148  * - LGPL
5149  *
5150  * slider
5151  * 
5152  */
5153
5154
5155 /**
5156  * @class Roo.bootstrap.Slider
5157  * @extends Roo.bootstrap.Component
5158  * Bootstrap Slider class
5159  *    
5160  * @constructor
5161  * Create a new Slider
5162  * @param {Object} config The config object
5163  */
5164
5165 Roo.bootstrap.Slider = function(config){
5166     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5167 };
5168
5169 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5170     
5171     getAutoCreate : function(){
5172         
5173         var cfg = {
5174             tag: 'div',
5175             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5176             cn: [
5177                 {
5178                     tag: 'a',
5179                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5180                 }
5181             ]
5182         };
5183         
5184         return cfg;
5185     }
5186    
5187 });
5188
5189  /*
5190  * Based on:
5191  * Ext JS Library 1.1.1
5192  * Copyright(c) 2006-2007, Ext JS, LLC.
5193  *
5194  * Originally Released Under LGPL - original licence link has changed is not relivant.
5195  *
5196  * Fork - LGPL
5197  * <script type="text/javascript">
5198  */
5199  
5200
5201 /**
5202  * @class Roo.grid.ColumnModel
5203  * @extends Roo.util.Observable
5204  * This is the default implementation of a ColumnModel used by the Grid. It defines
5205  * the columns in the grid.
5206  * <br>Usage:<br>
5207  <pre><code>
5208  var colModel = new Roo.grid.ColumnModel([
5209         {header: "Ticker", width: 60, sortable: true, locked: true},
5210         {header: "Company Name", width: 150, sortable: true},
5211         {header: "Market Cap.", width: 100, sortable: true},
5212         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5213         {header: "Employees", width: 100, sortable: true, resizable: false}
5214  ]);
5215  </code></pre>
5216  * <p>
5217  
5218  * The config options listed for this class are options which may appear in each
5219  * individual column definition.
5220  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5221  * @constructor
5222  * @param {Object} config An Array of column config objects. See this class's
5223  * config objects for details.
5224 */
5225 Roo.grid.ColumnModel = function(config){
5226         /**
5227      * The config passed into the constructor
5228      */
5229     this.config = config;
5230     this.lookup = {};
5231
5232     // if no id, create one
5233     // if the column does not have a dataIndex mapping,
5234     // map it to the order it is in the config
5235     for(var i = 0, len = config.length; i < len; i++){
5236         var c = config[i];
5237         if(typeof c.dataIndex == "undefined"){
5238             c.dataIndex = i;
5239         }
5240         if(typeof c.renderer == "string"){
5241             c.renderer = Roo.util.Format[c.renderer];
5242         }
5243         if(typeof c.id == "undefined"){
5244             c.id = Roo.id();
5245         }
5246         if(c.editor && c.editor.xtype){
5247             c.editor  = Roo.factory(c.editor, Roo.grid);
5248         }
5249         if(c.editor && c.editor.isFormField){
5250             c.editor = new Roo.grid.GridEditor(c.editor);
5251         }
5252         this.lookup[c.id] = c;
5253     }
5254
5255     /**
5256      * The width of columns which have no width specified (defaults to 100)
5257      * @type Number
5258      */
5259     this.defaultWidth = 100;
5260
5261     /**
5262      * Default sortable of columns which have no sortable specified (defaults to false)
5263      * @type Boolean
5264      */
5265     this.defaultSortable = false;
5266
5267     this.addEvents({
5268         /**
5269              * @event widthchange
5270              * Fires when the width of a column changes.
5271              * @param {ColumnModel} this
5272              * @param {Number} columnIndex The column index
5273              * @param {Number} newWidth The new width
5274              */
5275             "widthchange": true,
5276         /**
5277              * @event headerchange
5278              * Fires when the text of a header changes.
5279              * @param {ColumnModel} this
5280              * @param {Number} columnIndex The column index
5281              * @param {Number} newText The new header text
5282              */
5283             "headerchange": true,
5284         /**
5285              * @event hiddenchange
5286              * Fires when a column is hidden or "unhidden".
5287              * @param {ColumnModel} this
5288              * @param {Number} columnIndex The column index
5289              * @param {Boolean} hidden true if hidden, false otherwise
5290              */
5291             "hiddenchange": true,
5292             /**
5293          * @event columnmoved
5294          * Fires when a column is moved.
5295          * @param {ColumnModel} this
5296          * @param {Number} oldIndex
5297          * @param {Number} newIndex
5298          */
5299         "columnmoved" : true,
5300         /**
5301          * @event columlockchange
5302          * Fires when a column's locked state is changed
5303          * @param {ColumnModel} this
5304          * @param {Number} colIndex
5305          * @param {Boolean} locked true if locked
5306          */
5307         "columnlockchange" : true
5308     });
5309     Roo.grid.ColumnModel.superclass.constructor.call(this);
5310 };
5311 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5312     /**
5313      * @cfg {String} header The header text to display in the Grid view.
5314      */
5315     /**
5316      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5317      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5318      * specified, the column's index is used as an index into the Record's data Array.
5319      */
5320     /**
5321      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5322      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5323      */
5324     /**
5325      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5326      * Defaults to the value of the {@link #defaultSortable} property.
5327      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5328      */
5329     /**
5330      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5331      */
5332     /**
5333      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5334      */
5335     /**
5336      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5337      */
5338     /**
5339      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5340      */
5341     /**
5342      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5343      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5344      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5345      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5346      */
5347        /**
5348      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5349      */
5350     /**
5351      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5352      */
5353     /**
5354      * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
5355      */
5356     /**
5357      * @cfg {String} cursor (Optional)
5358      */
5359     /**
5360      * @cfg {String} tooltip (Optional)
5361      */
5362     /**
5363      * @cfg {Number} xs (Optional)
5364      */
5365     /**
5366      * @cfg {Number} sm (Optional)
5367      */
5368     /**
5369      * @cfg {Number} md (Optional)
5370      */
5371     /**
5372      * @cfg {Number} lg (Optional)
5373      */
5374     /**
5375      * Returns the id of the column at the specified index.
5376      * @param {Number} index The column index
5377      * @return {String} the id
5378      */
5379     getColumnId : function(index){
5380         return this.config[index].id;
5381     },
5382
5383     /**
5384      * Returns the column for a specified id.
5385      * @param {String} id The column id
5386      * @return {Object} the column
5387      */
5388     getColumnById : function(id){
5389         return this.lookup[id];
5390     },
5391
5392     
5393     /**
5394      * Returns the column for a specified dataIndex.
5395      * @param {String} dataIndex The column dataIndex
5396      * @return {Object|Boolean} the column or false if not found
5397      */
5398     getColumnByDataIndex: function(dataIndex){
5399         var index = this.findColumnIndex(dataIndex);
5400         return index > -1 ? this.config[index] : false;
5401     },
5402     
5403     /**
5404      * Returns the index for a specified column id.
5405      * @param {String} id The column id
5406      * @return {Number} the index, or -1 if not found
5407      */
5408     getIndexById : function(id){
5409         for(var i = 0, len = this.config.length; i < len; i++){
5410             if(this.config[i].id == id){
5411                 return i;
5412             }
5413         }
5414         return -1;
5415     },
5416     
5417     /**
5418      * Returns the index for a specified column dataIndex.
5419      * @param {String} dataIndex The column dataIndex
5420      * @return {Number} the index, or -1 if not found
5421      */
5422     
5423     findColumnIndex : function(dataIndex){
5424         for(var i = 0, len = this.config.length; i < len; i++){
5425             if(this.config[i].dataIndex == dataIndex){
5426                 return i;
5427             }
5428         }
5429         return -1;
5430     },
5431     
5432     
5433     moveColumn : function(oldIndex, newIndex){
5434         var c = this.config[oldIndex];
5435         this.config.splice(oldIndex, 1);
5436         this.config.splice(newIndex, 0, c);
5437         this.dataMap = null;
5438         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5439     },
5440
5441     isLocked : function(colIndex){
5442         return this.config[colIndex].locked === true;
5443     },
5444
5445     setLocked : function(colIndex, value, suppressEvent){
5446         if(this.isLocked(colIndex) == value){
5447             return;
5448         }
5449         this.config[colIndex].locked = value;
5450         if(!suppressEvent){
5451             this.fireEvent("columnlockchange", this, colIndex, value);
5452         }
5453     },
5454
5455     getTotalLockedWidth : function(){
5456         var totalWidth = 0;
5457         for(var i = 0; i < this.config.length; i++){
5458             if(this.isLocked(i) && !this.isHidden(i)){
5459                 this.totalWidth += this.getColumnWidth(i);
5460             }
5461         }
5462         return totalWidth;
5463     },
5464
5465     getLockedCount : function(){
5466         for(var i = 0, len = this.config.length; i < len; i++){
5467             if(!this.isLocked(i)){
5468                 return i;
5469             }
5470         }
5471         
5472         return this.config.length;
5473     },
5474
5475     /**
5476      * Returns the number of columns.
5477      * @return {Number}
5478      */
5479     getColumnCount : function(visibleOnly){
5480         if(visibleOnly === true){
5481             var c = 0;
5482             for(var i = 0, len = this.config.length; i < len; i++){
5483                 if(!this.isHidden(i)){
5484                     c++;
5485                 }
5486             }
5487             return c;
5488         }
5489         return this.config.length;
5490     },
5491
5492     /**
5493      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5494      * @param {Function} fn
5495      * @param {Object} scope (optional)
5496      * @return {Array} result
5497      */
5498     getColumnsBy : function(fn, scope){
5499         var r = [];
5500         for(var i = 0, len = this.config.length; i < len; i++){
5501             var c = this.config[i];
5502             if(fn.call(scope||this, c, i) === true){
5503                 r[r.length] = c;
5504             }
5505         }
5506         return r;
5507     },
5508
5509     /**
5510      * Returns true if the specified column is sortable.
5511      * @param {Number} col The column index
5512      * @return {Boolean}
5513      */
5514     isSortable : function(col){
5515         if(typeof this.config[col].sortable == "undefined"){
5516             return this.defaultSortable;
5517         }
5518         return this.config[col].sortable;
5519     },
5520
5521     /**
5522      * Returns the rendering (formatting) function defined for the column.
5523      * @param {Number} col The column index.
5524      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5525      */
5526     getRenderer : function(col){
5527         if(!this.config[col].renderer){
5528             return Roo.grid.ColumnModel.defaultRenderer;
5529         }
5530         return this.config[col].renderer;
5531     },
5532
5533     /**
5534      * Sets the rendering (formatting) function for a column.
5535      * @param {Number} col The column index
5536      * @param {Function} fn The function to use to process the cell's raw data
5537      * to return HTML markup for the grid view. The render function is called with
5538      * the following parameters:<ul>
5539      * <li>Data value.</li>
5540      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5541      * <li>css A CSS style string to apply to the table cell.</li>
5542      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5543      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5544      * <li>Row index</li>
5545      * <li>Column index</li>
5546      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5547      */
5548     setRenderer : function(col, fn){
5549         this.config[col].renderer = fn;
5550     },
5551
5552     /**
5553      * Returns the width for the specified column.
5554      * @param {Number} col The column index
5555      * @return {Number}
5556      */
5557     getColumnWidth : function(col){
5558         return this.config[col].width * 1 || this.defaultWidth;
5559     },
5560
5561     /**
5562      * Sets the width for a column.
5563      * @param {Number} col The column index
5564      * @param {Number} width The new width
5565      */
5566     setColumnWidth : function(col, width, suppressEvent){
5567         this.config[col].width = width;
5568         this.totalWidth = null;
5569         if(!suppressEvent){
5570              this.fireEvent("widthchange", this, col, width);
5571         }
5572     },
5573
5574     /**
5575      * Returns the total width of all columns.
5576      * @param {Boolean} includeHidden True to include hidden column widths
5577      * @return {Number}
5578      */
5579     getTotalWidth : function(includeHidden){
5580         if(!this.totalWidth){
5581             this.totalWidth = 0;
5582             for(var i = 0, len = this.config.length; i < len; i++){
5583                 if(includeHidden || !this.isHidden(i)){
5584                     this.totalWidth += this.getColumnWidth(i);
5585                 }
5586             }
5587         }
5588         return this.totalWidth;
5589     },
5590
5591     /**
5592      * Returns the header for the specified column.
5593      * @param {Number} col The column index
5594      * @return {String}
5595      */
5596     getColumnHeader : function(col){
5597         return this.config[col].header;
5598     },
5599
5600     /**
5601      * Sets the header for a column.
5602      * @param {Number} col The column index
5603      * @param {String} header The new header
5604      */
5605     setColumnHeader : function(col, header){
5606         this.config[col].header = header;
5607         this.fireEvent("headerchange", this, col, header);
5608     },
5609
5610     /**
5611      * Returns the tooltip for the specified column.
5612      * @param {Number} col The column index
5613      * @return {String}
5614      */
5615     getColumnTooltip : function(col){
5616             return this.config[col].tooltip;
5617     },
5618     /**
5619      * Sets the tooltip for a column.
5620      * @param {Number} col The column index
5621      * @param {String} tooltip The new tooltip
5622      */
5623     setColumnTooltip : function(col, tooltip){
5624             this.config[col].tooltip = tooltip;
5625     },
5626
5627     /**
5628      * Returns the dataIndex for the specified column.
5629      * @param {Number} col The column index
5630      * @return {Number}
5631      */
5632     getDataIndex : function(col){
5633         return this.config[col].dataIndex;
5634     },
5635
5636     /**
5637      * Sets the dataIndex for a column.
5638      * @param {Number} col The column index
5639      * @param {Number} dataIndex The new dataIndex
5640      */
5641     setDataIndex : function(col, dataIndex){
5642         this.config[col].dataIndex = dataIndex;
5643     },
5644
5645     
5646     
5647     /**
5648      * Returns true if the cell is editable.
5649      * @param {Number} colIndex The column index
5650      * @param {Number} rowIndex The row index - this is nto actually used..?
5651      * @return {Boolean}
5652      */
5653     isCellEditable : function(colIndex, rowIndex){
5654         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5655     },
5656
5657     /**
5658      * Returns the editor defined for the cell/column.
5659      * return false or null to disable editing.
5660      * @param {Number} colIndex The column index
5661      * @param {Number} rowIndex The row index
5662      * @return {Object}
5663      */
5664     getCellEditor : function(colIndex, rowIndex){
5665         return this.config[colIndex].editor;
5666     },
5667
5668     /**
5669      * Sets if a column is editable.
5670      * @param {Number} col The column index
5671      * @param {Boolean} editable True if the column is editable
5672      */
5673     setEditable : function(col, editable){
5674         this.config[col].editable = editable;
5675     },
5676
5677
5678     /**
5679      * Returns true if the column is hidden.
5680      * @param {Number} colIndex The column index
5681      * @return {Boolean}
5682      */
5683     isHidden : function(colIndex){
5684         return this.config[colIndex].hidden;
5685     },
5686
5687
5688     /**
5689      * Returns true if the column width cannot be changed
5690      */
5691     isFixed : function(colIndex){
5692         return this.config[colIndex].fixed;
5693     },
5694
5695     /**
5696      * Returns true if the column can be resized
5697      * @return {Boolean}
5698      */
5699     isResizable : function(colIndex){
5700         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5701     },
5702     /**
5703      * Sets if a column is hidden.
5704      * @param {Number} colIndex The column index
5705      * @param {Boolean} hidden True if the column is hidden
5706      */
5707     setHidden : function(colIndex, hidden){
5708         this.config[colIndex].hidden = hidden;
5709         this.totalWidth = null;
5710         this.fireEvent("hiddenchange", this, colIndex, hidden);
5711     },
5712
5713     /**
5714      * Sets the editor for a column.
5715      * @param {Number} col The column index
5716      * @param {Object} editor The editor object
5717      */
5718     setEditor : function(col, editor){
5719         this.config[col].editor = editor;
5720     }
5721 });
5722
5723 Roo.grid.ColumnModel.defaultRenderer = function(value)
5724 {
5725     if(typeof value == "object") {
5726         return value;
5727     }
5728         if(typeof value == "string" && value.length < 1){
5729             return "&#160;";
5730         }
5731     
5732         return String.format("{0}", value);
5733 };
5734
5735 // Alias for backwards compatibility
5736 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5737 /*
5738  * Based on:
5739  * Ext JS Library 1.1.1
5740  * Copyright(c) 2006-2007, Ext JS, LLC.
5741  *
5742  * Originally Released Under LGPL - original licence link has changed is not relivant.
5743  *
5744  * Fork - LGPL
5745  * <script type="text/javascript">
5746  */
5747  
5748 /**
5749  * @class Roo.LoadMask
5750  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5751  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5752  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5753  * element's UpdateManager load indicator and will be destroyed after the initial load.
5754  * @constructor
5755  * Create a new LoadMask
5756  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5757  * @param {Object} config The config object
5758  */
5759 Roo.LoadMask = function(el, config){
5760     this.el = Roo.get(el);
5761     Roo.apply(this, config);
5762     if(this.store){
5763         this.store.on('beforeload', this.onBeforeLoad, this);
5764         this.store.on('load', this.onLoad, this);
5765         this.store.on('loadexception', this.onLoadException, this);
5766         this.removeMask = false;
5767     }else{
5768         var um = this.el.getUpdateManager();
5769         um.showLoadIndicator = false; // disable the default indicator
5770         um.on('beforeupdate', this.onBeforeLoad, this);
5771         um.on('update', this.onLoad, this);
5772         um.on('failure', this.onLoad, this);
5773         this.removeMask = true;
5774     }
5775 };
5776
5777 Roo.LoadMask.prototype = {
5778     /**
5779      * @cfg {Boolean} removeMask
5780      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5781      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5782      */
5783     /**
5784      * @cfg {String} msg
5785      * The text to display in a centered loading message box (defaults to 'Loading...')
5786      */
5787     msg : 'Loading...',
5788     /**
5789      * @cfg {String} msgCls
5790      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5791      */
5792     msgCls : 'x-mask-loading',
5793
5794     /**
5795      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5796      * @type Boolean
5797      */
5798     disabled: false,
5799
5800     /**
5801      * Disables the mask to prevent it from being displayed
5802      */
5803     disable : function(){
5804        this.disabled = true;
5805     },
5806
5807     /**
5808      * Enables the mask so that it can be displayed
5809      */
5810     enable : function(){
5811         this.disabled = false;
5812     },
5813     
5814     onLoadException : function()
5815     {
5816         Roo.log(arguments);
5817         
5818         if (typeof(arguments[3]) != 'undefined') {
5819             Roo.MessageBox.alert("Error loading",arguments[3]);
5820         } 
5821         /*
5822         try {
5823             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5824                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5825             }   
5826         } catch(e) {
5827             
5828         }
5829         */
5830     
5831         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5832     },
5833     // private
5834     onLoad : function()
5835     {
5836         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5837     },
5838
5839     // private
5840     onBeforeLoad : function(){
5841         if(!this.disabled){
5842             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5843         }
5844     },
5845
5846     // private
5847     destroy : function(){
5848         if(this.store){
5849             this.store.un('beforeload', this.onBeforeLoad, this);
5850             this.store.un('load', this.onLoad, this);
5851             this.store.un('loadexception', this.onLoadException, this);
5852         }else{
5853             var um = this.el.getUpdateManager();
5854             um.un('beforeupdate', this.onBeforeLoad, this);
5855             um.un('update', this.onLoad, this);
5856             um.un('failure', this.onLoad, this);
5857         }
5858     }
5859 };/*
5860  * - LGPL
5861  *
5862  * table
5863  * 
5864  */
5865
5866 /**
5867  * @class Roo.bootstrap.Table
5868  * @extends Roo.bootstrap.Component
5869  * Bootstrap Table class
5870  * @cfg {String} cls table class
5871  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5872  * @cfg {String} bgcolor Specifies the background color for a table
5873  * @cfg {Number} border Specifies whether the table cells should have borders or not
5874  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5875  * @cfg {Number} cellspacing Specifies the space between cells
5876  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5877  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5878  * @cfg {String} sortable Specifies that the table should be sortable
5879  * @cfg {String} summary Specifies a summary of the content of a table
5880  * @cfg {Number} width Specifies the width of a table
5881  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5882  * 
5883  * @cfg {boolean} striped Should the rows be alternative striped
5884  * @cfg {boolean} bordered Add borders to the table
5885  * @cfg {boolean} hover Add hover highlighting
5886  * @cfg {boolean} condensed Format condensed
5887  * @cfg {boolean} responsive Format condensed
5888  * @cfg {Boolean} loadMask (true|false) default false
5889  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5890  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5891  * @cfg {Boolean} rowSelection (true|false) default false
5892  * @cfg {Boolean} cellSelection (true|false) default false
5893  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5894  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5895  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5896  * @cfg {Boolean} auto_hide_footer  auto hide footer if only one page (default false)
5897  
5898  * 
5899  * @constructor
5900  * Create a new Table
5901  * @param {Object} config The config object
5902  */
5903
5904 Roo.bootstrap.Table = function(config){
5905     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5906     
5907   
5908     
5909     // BC...
5910     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5911     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5912     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5913     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5914     
5915     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5916     if (this.sm) {
5917         this.sm.grid = this;
5918         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5919         this.sm = this.selModel;
5920         this.sm.xmodule = this.xmodule || false;
5921     }
5922     
5923     if (this.cm && typeof(this.cm.config) == 'undefined') {
5924         this.colModel = new Roo.grid.ColumnModel(this.cm);
5925         this.cm = this.colModel;
5926         this.cm.xmodule = this.xmodule || false;
5927     }
5928     if (this.store) {
5929         this.store= Roo.factory(this.store, Roo.data);
5930         this.ds = this.store;
5931         this.ds.xmodule = this.xmodule || false;
5932          
5933     }
5934     if (this.footer && this.store) {
5935         this.footer.dataSource = this.ds;
5936         this.footer = Roo.factory(this.footer);
5937     }
5938     
5939     /** @private */
5940     this.addEvents({
5941         /**
5942          * @event cellclick
5943          * Fires when a cell is clicked
5944          * @param {Roo.bootstrap.Table} this
5945          * @param {Roo.Element} el
5946          * @param {Number} rowIndex
5947          * @param {Number} columnIndex
5948          * @param {Roo.EventObject} e
5949          */
5950         "cellclick" : true,
5951         /**
5952          * @event celldblclick
5953          * Fires when a cell is double clicked
5954          * @param {Roo.bootstrap.Table} this
5955          * @param {Roo.Element} el
5956          * @param {Number} rowIndex
5957          * @param {Number} columnIndex
5958          * @param {Roo.EventObject} e
5959          */
5960         "celldblclick" : true,
5961         /**
5962          * @event rowclick
5963          * Fires when a row is clicked
5964          * @param {Roo.bootstrap.Table} this
5965          * @param {Roo.Element} el
5966          * @param {Number} rowIndex
5967          * @param {Roo.EventObject} e
5968          */
5969         "rowclick" : true,
5970         /**
5971          * @event rowdblclick
5972          * Fires when a row is double clicked
5973          * @param {Roo.bootstrap.Table} this
5974          * @param {Roo.Element} el
5975          * @param {Number} rowIndex
5976          * @param {Roo.EventObject} e
5977          */
5978         "rowdblclick" : true,
5979         /**
5980          * @event mouseover
5981          * Fires when a mouseover occur
5982          * @param {Roo.bootstrap.Table} this
5983          * @param {Roo.Element} el
5984          * @param {Number} rowIndex
5985          * @param {Number} columnIndex
5986          * @param {Roo.EventObject} e
5987          */
5988         "mouseover" : true,
5989         /**
5990          * @event mouseout
5991          * Fires when a mouseout occur
5992          * @param {Roo.bootstrap.Table} this
5993          * @param {Roo.Element} el
5994          * @param {Number} rowIndex
5995          * @param {Number} columnIndex
5996          * @param {Roo.EventObject} e
5997          */
5998         "mouseout" : true,
5999         /**
6000          * @event rowclass
6001          * Fires when a row is rendered, so you can change add a style to it.
6002          * @param {Roo.bootstrap.Table} this
6003          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
6004          */
6005         'rowclass' : true,
6006           /**
6007          * @event rowsrendered
6008          * Fires when all the  rows have been rendered
6009          * @param {Roo.bootstrap.Table} this
6010          */
6011         'rowsrendered' : true,
6012         /**
6013          * @event contextmenu
6014          * The raw contextmenu event for the entire grid.
6015          * @param {Roo.EventObject} e
6016          */
6017         "contextmenu" : true,
6018         /**
6019          * @event rowcontextmenu
6020          * Fires when a row is right clicked
6021          * @param {Roo.bootstrap.Table} this
6022          * @param {Number} rowIndex
6023          * @param {Roo.EventObject} e
6024          */
6025         "rowcontextmenu" : true,
6026         /**
6027          * @event cellcontextmenu
6028          * Fires when a cell is right clicked
6029          * @param {Roo.bootstrap.Table} this
6030          * @param {Number} rowIndex
6031          * @param {Number} cellIndex
6032          * @param {Roo.EventObject} e
6033          */
6034          "cellcontextmenu" : true,
6035          /**
6036          * @event headercontextmenu
6037          * Fires when a header is right clicked
6038          * @param {Roo.bootstrap.Table} this
6039          * @param {Number} columnIndex
6040          * @param {Roo.EventObject} e
6041          */
6042         "headercontextmenu" : true
6043     });
6044 };
6045
6046 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6047     
6048     cls: false,
6049     align: false,
6050     bgcolor: false,
6051     border: false,
6052     cellpadding: false,
6053     cellspacing: false,
6054     frame: false,
6055     rules: false,
6056     sortable: false,
6057     summary: false,
6058     width: false,
6059     striped : false,
6060     scrollBody : false,
6061     bordered: false,
6062     hover:  false,
6063     condensed : false,
6064     responsive : false,
6065     sm : false,
6066     cm : false,
6067     store : false,
6068     loadMask : false,
6069     footerShow : true,
6070     headerShow : true,
6071   
6072     rowSelection : false,
6073     cellSelection : false,
6074     layout : false,
6075     
6076     // Roo.Element - the tbody
6077     mainBody: false,
6078     // Roo.Element - thead element
6079     mainHead: false,
6080     
6081     container: false, // used by gridpanel...
6082     
6083     lazyLoad : false,
6084     
6085     CSS : Roo.util.CSS,
6086     
6087     auto_hide_footer : false,
6088     
6089     getAutoCreate : function()
6090     {
6091         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6092         
6093         cfg = {
6094             tag: 'table',
6095             cls : 'table',
6096             cn : []
6097         };
6098         if (this.scrollBody) {
6099             cfg.cls += ' table-body-fixed';
6100         }    
6101         if (this.striped) {
6102             cfg.cls += ' table-striped';
6103         }
6104         
6105         if (this.hover) {
6106             cfg.cls += ' table-hover';
6107         }
6108         if (this.bordered) {
6109             cfg.cls += ' table-bordered';
6110         }
6111         if (this.condensed) {
6112             cfg.cls += ' table-condensed';
6113         }
6114         if (this.responsive) {
6115             cfg.cls += ' table-responsive';
6116         }
6117         
6118         if (this.cls) {
6119             cfg.cls+=  ' ' +this.cls;
6120         }
6121         
6122         // this lot should be simplifed...
6123         var _t = this;
6124         var cp = [
6125             'align',
6126             'bgcolor',
6127             'border',
6128             'cellpadding',
6129             'cellspacing',
6130             'frame',
6131             'rules',
6132             'sortable',
6133             'summary',
6134             'width'
6135         ].forEach(function(k) {
6136             if (_t[k]) {
6137                 cfg[k] = _t[k];
6138             }
6139         });
6140         
6141         
6142         if (this.layout) {
6143             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6144         }
6145         
6146         if(this.store || this.cm){
6147             if(this.headerShow){
6148                 cfg.cn.push(this.renderHeader());
6149             }
6150             
6151             cfg.cn.push(this.renderBody());
6152             
6153             if(this.footerShow){
6154                 cfg.cn.push(this.renderFooter());
6155             }
6156             // where does this come from?
6157             //cfg.cls+=  ' TableGrid';
6158         }
6159         
6160         return { cn : [ cfg ] };
6161     },
6162     
6163     initEvents : function()
6164     {   
6165         if(!this.store || !this.cm){
6166             return;
6167         }
6168         if (this.selModel) {
6169             this.selModel.initEvents();
6170         }
6171         
6172         
6173         //Roo.log('initEvents with ds!!!!');
6174         
6175         this.mainBody = this.el.select('tbody', true).first();
6176         this.mainHead = this.el.select('thead', true).first();
6177         this.mainFoot = this.el.select('tfoot', true).first();
6178         
6179         
6180         
6181         var _this = this;
6182         
6183         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6184             e.on('click', _this.sort, _this);
6185         });
6186         
6187         this.mainBody.on("click", this.onClick, this);
6188         this.mainBody.on("dblclick", this.onDblClick, this);
6189         
6190         // why is this done????? = it breaks dialogs??
6191         //this.parent().el.setStyle('position', 'relative');
6192         
6193         
6194         if (this.footer) {
6195             this.footer.parentId = this.id;
6196             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6197             
6198             if(this.lazyLoad){
6199                 this.el.select('tfoot tr td').first().addClass('hide');
6200             }
6201         } 
6202         
6203         if(this.loadMask) {
6204             this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6205         }
6206         
6207         this.store.on('load', this.onLoad, this);
6208         this.store.on('beforeload', this.onBeforeLoad, this);
6209         this.store.on('update', this.onUpdate, this);
6210         this.store.on('add', this.onAdd, this);
6211         this.store.on("clear", this.clear, this);
6212         
6213         this.el.on("contextmenu", this.onContextMenu, this);
6214         
6215         this.mainBody.on('scroll', this.onBodyScroll, this);
6216         
6217         this.cm.on("headerchange", this.onHeaderChange, this);
6218         
6219         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6220         
6221     },
6222     
6223     onContextMenu : function(e, t)
6224     {
6225         this.processEvent("contextmenu", e);
6226     },
6227     
6228     processEvent : function(name, e)
6229     {
6230         if (name != 'touchstart' ) {
6231             this.fireEvent(name, e);    
6232         }
6233         
6234         var t = e.getTarget();
6235         
6236         var cell = Roo.get(t);
6237         
6238         if(!cell){
6239             return;
6240         }
6241         
6242         if(cell.findParent('tfoot', false, true)){
6243             return;
6244         }
6245         
6246         if(cell.findParent('thead', false, true)){
6247             
6248             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6249                 cell = Roo.get(t).findParent('th', false, true);
6250                 if (!cell) {
6251                     Roo.log("failed to find th in thead?");
6252                     Roo.log(e.getTarget());
6253                     return;
6254                 }
6255             }
6256             
6257             var cellIndex = cell.dom.cellIndex;
6258             
6259             var ename = name == 'touchstart' ? 'click' : name;
6260             this.fireEvent("header" + ename, this, cellIndex, e);
6261             
6262             return;
6263         }
6264         
6265         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6266             cell = Roo.get(t).findParent('td', false, true);
6267             if (!cell) {
6268                 Roo.log("failed to find th in tbody?");
6269                 Roo.log(e.getTarget());
6270                 return;
6271             }
6272         }
6273         
6274         var row = cell.findParent('tr', false, true);
6275         var cellIndex = cell.dom.cellIndex;
6276         var rowIndex = row.dom.rowIndex - 1;
6277         
6278         if(row !== false){
6279             
6280             this.fireEvent("row" + name, this, rowIndex, e);
6281             
6282             if(cell !== false){
6283             
6284                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6285             }
6286         }
6287         
6288     },
6289     
6290     onMouseover : function(e, el)
6291     {
6292         var cell = Roo.get(el);
6293         
6294         if(!cell){
6295             return;
6296         }
6297         
6298         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6299             cell = cell.findParent('td', false, true);
6300         }
6301         
6302         var row = cell.findParent('tr', false, true);
6303         var cellIndex = cell.dom.cellIndex;
6304         var rowIndex = row.dom.rowIndex - 1; // start from 0
6305         
6306         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6307         
6308     },
6309     
6310     onMouseout : function(e, el)
6311     {
6312         var cell = Roo.get(el);
6313         
6314         if(!cell){
6315             return;
6316         }
6317         
6318         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6319             cell = cell.findParent('td', false, true);
6320         }
6321         
6322         var row = cell.findParent('tr', false, true);
6323         var cellIndex = cell.dom.cellIndex;
6324         var rowIndex = row.dom.rowIndex - 1; // start from 0
6325         
6326         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6327         
6328     },
6329     
6330     onClick : function(e, el)
6331     {
6332         var cell = Roo.get(el);
6333         
6334         if(!cell || (!this.cellSelection && !this.rowSelection)){
6335             return;
6336         }
6337         
6338         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6339             cell = cell.findParent('td', false, true);
6340         }
6341         
6342         if(!cell || typeof(cell) == 'undefined'){
6343             return;
6344         }
6345         
6346         var row = cell.findParent('tr', false, true);
6347         
6348         if(!row || typeof(row) == 'undefined'){
6349             return;
6350         }
6351         
6352         var cellIndex = cell.dom.cellIndex;
6353         var rowIndex = this.getRowIndex(row);
6354         
6355         // why??? - should these not be based on SelectionModel?
6356         if(this.cellSelection){
6357             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6358         }
6359         
6360         if(this.rowSelection){
6361             this.fireEvent('rowclick', this, row, rowIndex, e);
6362         }
6363         
6364         
6365     },
6366         
6367     onDblClick : function(e,el)
6368     {
6369         var cell = Roo.get(el);
6370         
6371         if(!cell || (!this.cellSelection && !this.rowSelection)){
6372             return;
6373         }
6374         
6375         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6376             cell = cell.findParent('td', false, true);
6377         }
6378         
6379         if(!cell || typeof(cell) == 'undefined'){
6380             return;
6381         }
6382         
6383         var row = cell.findParent('tr', false, true);
6384         
6385         if(!row || typeof(row) == 'undefined'){
6386             return;
6387         }
6388         
6389         var cellIndex = cell.dom.cellIndex;
6390         var rowIndex = this.getRowIndex(row);
6391         
6392         if(this.cellSelection){
6393             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6394         }
6395         
6396         if(this.rowSelection){
6397             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6398         }
6399     },
6400     
6401     sort : function(e,el)
6402     {
6403         var col = Roo.get(el);
6404         
6405         if(!col.hasClass('sortable')){
6406             return;
6407         }
6408         
6409         var sort = col.attr('sort');
6410         var dir = 'ASC';
6411         
6412         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6413             dir = 'DESC';
6414         }
6415         
6416         this.store.sortInfo = {field : sort, direction : dir};
6417         
6418         if (this.footer) {
6419             Roo.log("calling footer first");
6420             this.footer.onClick('first');
6421         } else {
6422         
6423             this.store.load({ params : { start : 0 } });
6424         }
6425     },
6426     
6427     renderHeader : function()
6428     {
6429         var header = {
6430             tag: 'thead',
6431             cn : []
6432         };
6433         
6434         var cm = this.cm;
6435         this.totalWidth = 0;
6436         
6437         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6438             
6439             var config = cm.config[i];
6440             
6441             var c = {
6442                 tag: 'th',
6443                 cls : 'x-hcol-' + i,
6444                 style : '',
6445                 html: cm.getColumnHeader(i)
6446             };
6447             
6448             var hh = '';
6449             
6450             if(typeof(config.sortable) != 'undefined' && config.sortable){
6451                 c.cls = 'sortable';
6452                 c.html = '<i class="glyphicon"></i>' + c.html;
6453             }
6454             
6455             if(typeof(config.lgHeader) != 'undefined'){
6456                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6457             }
6458             
6459             if(typeof(config.mdHeader) != 'undefined'){
6460                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6461             }
6462             
6463             if(typeof(config.smHeader) != 'undefined'){
6464                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6465             }
6466             
6467             if(typeof(config.xsHeader) != 'undefined'){
6468                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6469             }
6470             
6471             if(hh.length){
6472                 c.html = hh;
6473             }
6474             
6475             if(typeof(config.tooltip) != 'undefined'){
6476                 c.tooltip = config.tooltip;
6477             }
6478             
6479             if(typeof(config.colspan) != 'undefined'){
6480                 c.colspan = config.colspan;
6481             }
6482             
6483             if(typeof(config.hidden) != 'undefined' && config.hidden){
6484                 c.style += ' display:none;';
6485             }
6486             
6487             if(typeof(config.dataIndex) != 'undefined'){
6488                 c.sort = config.dataIndex;
6489             }
6490             
6491            
6492             
6493             if(typeof(config.align) != 'undefined' && config.align.length){
6494                 c.style += ' text-align:' + config.align + ';';
6495             }
6496             
6497             if(typeof(config.width) != 'undefined'){
6498                 c.style += ' width:' + config.width + 'px;';
6499                 this.totalWidth += config.width;
6500             } else {
6501                 this.totalWidth += 100; // assume minimum of 100 per column?
6502             }
6503             
6504             if(typeof(config.cls) != 'undefined'){
6505                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6506             }
6507             
6508             ['xs','sm','md','lg'].map(function(size){
6509                 
6510                 if(typeof(config[size]) == 'undefined'){
6511                     return;
6512                 }
6513                 
6514                 if (!config[size]) { // 0 = hidden
6515                     c.cls += ' hidden-' + size;
6516                     return;
6517                 }
6518                 
6519                 c.cls += ' col-' + size + '-' + config[size];
6520
6521             });
6522             
6523             header.cn.push(c)
6524         }
6525         
6526         return header;
6527     },
6528     
6529     renderBody : function()
6530     {
6531         var body = {
6532             tag: 'tbody',
6533             cn : [
6534                 {
6535                     tag: 'tr',
6536                     cn : [
6537                         {
6538                             tag : 'td',
6539                             colspan :  this.cm.getColumnCount()
6540                         }
6541                     ]
6542                 }
6543             ]
6544         };
6545         
6546         return body;
6547     },
6548     
6549     renderFooter : function()
6550     {
6551         var footer = {
6552             tag: 'tfoot',
6553             cn : [
6554                 {
6555                     tag: 'tr',
6556                     cn : [
6557                         {
6558                             tag : 'td',
6559                             colspan :  this.cm.getColumnCount()
6560                         }
6561                     ]
6562                 }
6563             ]
6564         };
6565         
6566         return footer;
6567     },
6568     
6569     
6570     
6571     onLoad : function()
6572     {
6573 //        Roo.log('ds onload');
6574         this.clear();
6575         
6576         var _this = this;
6577         var cm = this.cm;
6578         var ds = this.store;
6579         
6580         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6581             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6582             if (_this.store.sortInfo) {
6583                     
6584                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6585                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6586                 }
6587                 
6588                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6589                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6590                 }
6591             }
6592         });
6593         
6594         var tbody =  this.mainBody;
6595               
6596         if(ds.getCount() > 0){
6597             ds.data.each(function(d,rowIndex){
6598                 var row =  this.renderRow(cm, ds, rowIndex);
6599                 
6600                 tbody.createChild(row);
6601                 
6602                 var _this = this;
6603                 
6604                 if(row.cellObjects.length){
6605                     Roo.each(row.cellObjects, function(r){
6606                         _this.renderCellObject(r);
6607                     })
6608                 }
6609                 
6610             }, this);
6611         }
6612         
6613         var tfoot = this.el.select('tfoot', true).first();
6614         
6615         if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6616             
6617             this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6618             
6619             var total = this.ds.getTotalCount();
6620             
6621             if(this.footer.pageSize < total){
6622                 this.mainFoot.show();
6623             }
6624         }
6625         
6626         Roo.each(this.el.select('tbody td', true).elements, function(e){
6627             e.on('mouseover', _this.onMouseover, _this);
6628         });
6629         
6630         Roo.each(this.el.select('tbody td', true).elements, function(e){
6631             e.on('mouseout', _this.onMouseout, _this);
6632         });
6633         this.fireEvent('rowsrendered', this);
6634         
6635         this.autoSize();
6636     },
6637     
6638     
6639     onUpdate : function(ds,record)
6640     {
6641         this.refreshRow(record);
6642         this.autoSize();
6643     },
6644     
6645     onRemove : function(ds, record, index, isUpdate){
6646         if(isUpdate !== true){
6647             this.fireEvent("beforerowremoved", this, index, record);
6648         }
6649         var bt = this.mainBody.dom;
6650         
6651         var rows = this.el.select('tbody > tr', true).elements;
6652         
6653         if(typeof(rows[index]) != 'undefined'){
6654             bt.removeChild(rows[index].dom);
6655         }
6656         
6657 //        if(bt.rows[index]){
6658 //            bt.removeChild(bt.rows[index]);
6659 //        }
6660         
6661         if(isUpdate !== true){
6662             //this.stripeRows(index);
6663             //this.syncRowHeights(index, index);
6664             //this.layout();
6665             this.fireEvent("rowremoved", this, index, record);
6666         }
6667     },
6668     
6669     onAdd : function(ds, records, rowIndex)
6670     {
6671         //Roo.log('on Add called');
6672         // - note this does not handle multiple adding very well..
6673         var bt = this.mainBody.dom;
6674         for (var i =0 ; i < records.length;i++) {
6675             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6676             //Roo.log(records[i]);
6677             //Roo.log(this.store.getAt(rowIndex+i));
6678             this.insertRow(this.store, rowIndex + i, false);
6679             return;
6680         }
6681         
6682     },
6683     
6684     
6685     refreshRow : function(record){
6686         var ds = this.store, index;
6687         if(typeof record == 'number'){
6688             index = record;
6689             record = ds.getAt(index);
6690         }else{
6691             index = ds.indexOf(record);
6692         }
6693         this.insertRow(ds, index, true);
6694         this.autoSize();
6695         this.onRemove(ds, record, index+1, true);
6696         this.autoSize();
6697         //this.syncRowHeights(index, index);
6698         //this.layout();
6699         this.fireEvent("rowupdated", this, index, record);
6700     },
6701     
6702     insertRow : function(dm, rowIndex, isUpdate){
6703         
6704         if(!isUpdate){
6705             this.fireEvent("beforerowsinserted", this, rowIndex);
6706         }
6707             //var s = this.getScrollState();
6708         var row = this.renderRow(this.cm, this.store, rowIndex);
6709         // insert before rowIndex..
6710         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6711         
6712         var _this = this;
6713                 
6714         if(row.cellObjects.length){
6715             Roo.each(row.cellObjects, function(r){
6716                 _this.renderCellObject(r);
6717             })
6718         }
6719             
6720         if(!isUpdate){
6721             this.fireEvent("rowsinserted", this, rowIndex);
6722             //this.syncRowHeights(firstRow, lastRow);
6723             //this.stripeRows(firstRow);
6724             //this.layout();
6725         }
6726         
6727     },
6728     
6729     
6730     getRowDom : function(rowIndex)
6731     {
6732         var rows = this.el.select('tbody > tr', true).elements;
6733         
6734         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6735         
6736     },
6737     // returns the object tree for a tr..
6738   
6739     
6740     renderRow : function(cm, ds, rowIndex) 
6741     {
6742         var d = ds.getAt(rowIndex);
6743         
6744         var row = {
6745             tag : 'tr',
6746             cls : 'x-row-' + rowIndex,
6747             cn : []
6748         };
6749             
6750         var cellObjects = [];
6751         
6752         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6753             var config = cm.config[i];
6754             
6755             var renderer = cm.getRenderer(i);
6756             var value = '';
6757             var id = false;
6758             
6759             if(typeof(renderer) !== 'undefined'){
6760                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6761             }
6762             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6763             // and are rendered into the cells after the row is rendered - using the id for the element.
6764             
6765             if(typeof(value) === 'object'){
6766                 id = Roo.id();
6767                 cellObjects.push({
6768                     container : id,
6769                     cfg : value 
6770                 })
6771             }
6772             
6773             var rowcfg = {
6774                 record: d,
6775                 rowIndex : rowIndex,
6776                 colIndex : i,
6777                 rowClass : ''
6778             };
6779
6780             this.fireEvent('rowclass', this, rowcfg);
6781             
6782             var td = {
6783                 tag: 'td',
6784                 cls : rowcfg.rowClass + ' x-col-' + i,
6785                 style: '',
6786                 html: (typeof(value) === 'object') ? '' : value
6787             };
6788             
6789             if (id) {
6790                 td.id = id;
6791             }
6792             
6793             if(typeof(config.colspan) != 'undefined'){
6794                 td.colspan = config.colspan;
6795             }
6796             
6797             if(typeof(config.hidden) != 'undefined' && config.hidden){
6798                 td.style += ' display:none;';
6799             }
6800             
6801             if(typeof(config.align) != 'undefined' && config.align.length){
6802                 td.style += ' text-align:' + config.align + ';';
6803             }
6804             if(typeof(config.valign) != 'undefined' && config.valign.length){
6805                 td.style += ' vertical-align:' + config.valign + ';';
6806             }
6807             
6808             if(typeof(config.width) != 'undefined'){
6809                 td.style += ' width:' +  config.width + 'px;';
6810             }
6811             
6812             if(typeof(config.cursor) != 'undefined'){
6813                 td.style += ' cursor:' +  config.cursor + ';';
6814             }
6815             
6816             if(typeof(config.cls) != 'undefined'){
6817                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6818             }
6819             
6820             ['xs','sm','md','lg'].map(function(size){
6821                 
6822                 if(typeof(config[size]) == 'undefined'){
6823                     return;
6824                 }
6825                 
6826                 if (!config[size]) { // 0 = hidden
6827                     td.cls += ' hidden-' + size;
6828                     return;
6829                 }
6830                 
6831                 td.cls += ' col-' + size + '-' + config[size];
6832
6833             });
6834             
6835             row.cn.push(td);
6836            
6837         }
6838         
6839         row.cellObjects = cellObjects;
6840         
6841         return row;
6842           
6843     },
6844     
6845     
6846     
6847     onBeforeLoad : function()
6848     {
6849         
6850     },
6851      /**
6852      * Remove all rows
6853      */
6854     clear : function()
6855     {
6856         this.el.select('tbody', true).first().dom.innerHTML = '';
6857     },
6858     /**
6859      * Show or hide a row.
6860      * @param {Number} rowIndex to show or hide
6861      * @param {Boolean} state hide
6862      */
6863     setRowVisibility : function(rowIndex, state)
6864     {
6865         var bt = this.mainBody.dom;
6866         
6867         var rows = this.el.select('tbody > tr', true).elements;
6868         
6869         if(typeof(rows[rowIndex]) == 'undefined'){
6870             return;
6871         }
6872         rows[rowIndex].dom.style.display = state ? '' : 'none';
6873     },
6874     
6875     
6876     getSelectionModel : function(){
6877         if(!this.selModel){
6878             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6879         }
6880         return this.selModel;
6881     },
6882     /*
6883      * Render the Roo.bootstrap object from renderder
6884      */
6885     renderCellObject : function(r)
6886     {
6887         var _this = this;
6888         
6889         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6890         
6891         var t = r.cfg.render(r.container);
6892         
6893         if(r.cfg.cn){
6894             Roo.each(r.cfg.cn, function(c){
6895                 var child = {
6896                     container: t.getChildContainer(),
6897                     cfg: c
6898                 };
6899                 _this.renderCellObject(child);
6900             })
6901         }
6902     },
6903     
6904     getRowIndex : function(row)
6905     {
6906         var rowIndex = -1;
6907         
6908         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6909             if(el != row){
6910                 return;
6911             }
6912             
6913             rowIndex = index;
6914         });
6915         
6916         return rowIndex;
6917     },
6918      /**
6919      * Returns the grid's underlying element = used by panel.Grid
6920      * @return {Element} The element
6921      */
6922     getGridEl : function(){
6923         return this.el;
6924     },
6925      /**
6926      * Forces a resize - used by panel.Grid
6927      * @return {Element} The element
6928      */
6929     autoSize : function()
6930     {
6931         //var ctr = Roo.get(this.container.dom.parentElement);
6932         var ctr = Roo.get(this.el.dom);
6933         
6934         var thd = this.getGridEl().select('thead',true).first();
6935         var tbd = this.getGridEl().select('tbody', true).first();
6936         var tfd = this.getGridEl().select('tfoot', true).first();
6937         
6938         var cw = ctr.getWidth();
6939         
6940         if (tbd) {
6941             
6942             tbd.setSize(ctr.getWidth(),
6943                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6944             );
6945             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6946             cw -= barsize;
6947         }
6948         cw = Math.max(cw, this.totalWidth);
6949         this.getGridEl().select('tr',true).setWidth(cw);
6950         // resize 'expandable coloumn?
6951         
6952         return; // we doe not have a view in this design..
6953         
6954     },
6955     onBodyScroll: function()
6956     {
6957         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6958         if(this.mainHead){
6959             this.mainHead.setStyle({
6960                 'position' : 'relative',
6961                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6962             });
6963         }
6964         
6965         if(this.lazyLoad){
6966             
6967             var scrollHeight = this.mainBody.dom.scrollHeight;
6968             
6969             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6970             
6971             var height = this.mainBody.getHeight();
6972             
6973             if(scrollHeight - height == scrollTop) {
6974                 
6975                 var total = this.ds.getTotalCount();
6976                 
6977                 if(this.footer.cursor + this.footer.pageSize < total){
6978                     
6979                     this.footer.ds.load({
6980                         params : {
6981                             start : this.footer.cursor + this.footer.pageSize,
6982                             limit : this.footer.pageSize
6983                         },
6984                         add : true
6985                     });
6986                 }
6987             }
6988             
6989         }
6990     },
6991     
6992     onHeaderChange : function()
6993     {
6994         var header = this.renderHeader();
6995         var table = this.el.select('table', true).first();
6996         
6997         this.mainHead.remove();
6998         this.mainHead = table.createChild(header, this.mainBody, false);
6999     },
7000     
7001     onHiddenChange : function(colModel, colIndex, hidden)
7002     {
7003         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7004         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7005         
7006         this.CSS.updateRule(thSelector, "display", "");
7007         this.CSS.updateRule(tdSelector, "display", "");
7008         
7009         if(hidden){
7010             this.CSS.updateRule(thSelector, "display", "none");
7011             this.CSS.updateRule(tdSelector, "display", "none");
7012         }
7013         
7014         this.onHeaderChange();
7015         this.onLoad();
7016         
7017     }
7018     
7019 });
7020
7021  
7022
7023  /*
7024  * - LGPL
7025  *
7026  * table cell
7027  * 
7028  */
7029
7030 /**
7031  * @class Roo.bootstrap.TableCell
7032  * @extends Roo.bootstrap.Component
7033  * Bootstrap TableCell class
7034  * @cfg {String} html cell contain text
7035  * @cfg {String} cls cell class
7036  * @cfg {String} tag cell tag (td|th) default td
7037  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7038  * @cfg {String} align Aligns the content in a cell
7039  * @cfg {String} axis Categorizes cells
7040  * @cfg {String} bgcolor Specifies the background color of a cell
7041  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7042  * @cfg {Number} colspan Specifies the number of columns a cell should span
7043  * @cfg {String} headers Specifies one or more header cells a cell is related to
7044  * @cfg {Number} height Sets the height of a cell
7045  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7046  * @cfg {Number} rowspan Sets the number of rows a cell should span
7047  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7048  * @cfg {String} valign Vertical aligns the content in a cell
7049  * @cfg {Number} width Specifies the width of a cell
7050  * 
7051  * @constructor
7052  * Create a new TableCell
7053  * @param {Object} config The config object
7054  */
7055
7056 Roo.bootstrap.TableCell = function(config){
7057     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7058 };
7059
7060 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7061     
7062     html: false,
7063     cls: false,
7064     tag: false,
7065     abbr: false,
7066     align: false,
7067     axis: false,
7068     bgcolor: false,
7069     charoff: false,
7070     colspan: false,
7071     headers: false,
7072     height: false,
7073     nowrap: false,
7074     rowspan: false,
7075     scope: false,
7076     valign: false,
7077     width: false,
7078     
7079     
7080     getAutoCreate : function(){
7081         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7082         
7083         cfg = {
7084             tag: 'td'
7085         };
7086         
7087         if(this.tag){
7088             cfg.tag = this.tag;
7089         }
7090         
7091         if (this.html) {
7092             cfg.html=this.html
7093         }
7094         if (this.cls) {
7095             cfg.cls=this.cls
7096         }
7097         if (this.abbr) {
7098             cfg.abbr=this.abbr
7099         }
7100         if (this.align) {
7101             cfg.align=this.align
7102         }
7103         if (this.axis) {
7104             cfg.axis=this.axis
7105         }
7106         if (this.bgcolor) {
7107             cfg.bgcolor=this.bgcolor
7108         }
7109         if (this.charoff) {
7110             cfg.charoff=this.charoff
7111         }
7112         if (this.colspan) {
7113             cfg.colspan=this.colspan
7114         }
7115         if (this.headers) {
7116             cfg.headers=this.headers
7117         }
7118         if (this.height) {
7119             cfg.height=this.height
7120         }
7121         if (this.nowrap) {
7122             cfg.nowrap=this.nowrap
7123         }
7124         if (this.rowspan) {
7125             cfg.rowspan=this.rowspan
7126         }
7127         if (this.scope) {
7128             cfg.scope=this.scope
7129         }
7130         if (this.valign) {
7131             cfg.valign=this.valign
7132         }
7133         if (this.width) {
7134             cfg.width=this.width
7135         }
7136         
7137         
7138         return cfg;
7139     }
7140    
7141 });
7142
7143  
7144
7145  /*
7146  * - LGPL
7147  *
7148  * table row
7149  * 
7150  */
7151
7152 /**
7153  * @class Roo.bootstrap.TableRow
7154  * @extends Roo.bootstrap.Component
7155  * Bootstrap TableRow class
7156  * @cfg {String} cls row class
7157  * @cfg {String} align Aligns the content in a table row
7158  * @cfg {String} bgcolor Specifies a background color for a table row
7159  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7160  * @cfg {String} valign Vertical aligns the content in a table row
7161  * 
7162  * @constructor
7163  * Create a new TableRow
7164  * @param {Object} config The config object
7165  */
7166
7167 Roo.bootstrap.TableRow = function(config){
7168     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7169 };
7170
7171 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7172     
7173     cls: false,
7174     align: false,
7175     bgcolor: false,
7176     charoff: false,
7177     valign: false,
7178     
7179     getAutoCreate : function(){
7180         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7181         
7182         cfg = {
7183             tag: 'tr'
7184         };
7185             
7186         if(this.cls){
7187             cfg.cls = this.cls;
7188         }
7189         if(this.align){
7190             cfg.align = this.align;
7191         }
7192         if(this.bgcolor){
7193             cfg.bgcolor = this.bgcolor;
7194         }
7195         if(this.charoff){
7196             cfg.charoff = this.charoff;
7197         }
7198         if(this.valign){
7199             cfg.valign = this.valign;
7200         }
7201         
7202         return cfg;
7203     }
7204    
7205 });
7206
7207  
7208
7209  /*
7210  * - LGPL
7211  *
7212  * table body
7213  * 
7214  */
7215
7216 /**
7217  * @class Roo.bootstrap.TableBody
7218  * @extends Roo.bootstrap.Component
7219  * Bootstrap TableBody class
7220  * @cfg {String} cls element class
7221  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7222  * @cfg {String} align Aligns the content inside the element
7223  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7224  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7225  * 
7226  * @constructor
7227  * Create a new TableBody
7228  * @param {Object} config The config object
7229  */
7230
7231 Roo.bootstrap.TableBody = function(config){
7232     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7233 };
7234
7235 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7236     
7237     cls: false,
7238     tag: false,
7239     align: false,
7240     charoff: false,
7241     valign: false,
7242     
7243     getAutoCreate : function(){
7244         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7245         
7246         cfg = {
7247             tag: 'tbody'
7248         };
7249             
7250         if (this.cls) {
7251             cfg.cls=this.cls
7252         }
7253         if(this.tag){
7254             cfg.tag = this.tag;
7255         }
7256         
7257         if(this.align){
7258             cfg.align = this.align;
7259         }
7260         if(this.charoff){
7261             cfg.charoff = this.charoff;
7262         }
7263         if(this.valign){
7264             cfg.valign = this.valign;
7265         }
7266         
7267         return cfg;
7268     }
7269     
7270     
7271 //    initEvents : function()
7272 //    {
7273 //        
7274 //        if(!this.store){
7275 //            return;
7276 //        }
7277 //        
7278 //        this.store = Roo.factory(this.store, Roo.data);
7279 //        this.store.on('load', this.onLoad, this);
7280 //        
7281 //        this.store.load();
7282 //        
7283 //    },
7284 //    
7285 //    onLoad: function () 
7286 //    {   
7287 //        this.fireEvent('load', this);
7288 //    }
7289 //    
7290 //   
7291 });
7292
7293  
7294
7295  /*
7296  * Based on:
7297  * Ext JS Library 1.1.1
7298  * Copyright(c) 2006-2007, Ext JS, LLC.
7299  *
7300  * Originally Released Under LGPL - original licence link has changed is not relivant.
7301  *
7302  * Fork - LGPL
7303  * <script type="text/javascript">
7304  */
7305
7306 // as we use this in bootstrap.
7307 Roo.namespace('Roo.form');
7308  /**
7309  * @class Roo.form.Action
7310  * Internal Class used to handle form actions
7311  * @constructor
7312  * @param {Roo.form.BasicForm} el The form element or its id
7313  * @param {Object} config Configuration options
7314  */
7315
7316  
7317  
7318 // define the action interface
7319 Roo.form.Action = function(form, options){
7320     this.form = form;
7321     this.options = options || {};
7322 };
7323 /**
7324  * Client Validation Failed
7325  * @const 
7326  */
7327 Roo.form.Action.CLIENT_INVALID = 'client';
7328 /**
7329  * Server Validation Failed
7330  * @const 
7331  */
7332 Roo.form.Action.SERVER_INVALID = 'server';
7333  /**
7334  * Connect to Server Failed
7335  * @const 
7336  */
7337 Roo.form.Action.CONNECT_FAILURE = 'connect';
7338 /**
7339  * Reading Data from Server Failed
7340  * @const 
7341  */
7342 Roo.form.Action.LOAD_FAILURE = 'load';
7343
7344 Roo.form.Action.prototype = {
7345     type : 'default',
7346     failureType : undefined,
7347     response : undefined,
7348     result : undefined,
7349
7350     // interface method
7351     run : function(options){
7352
7353     },
7354
7355     // interface method
7356     success : function(response){
7357
7358     },
7359
7360     // interface method
7361     handleResponse : function(response){
7362
7363     },
7364
7365     // default connection failure
7366     failure : function(response){
7367         
7368         this.response = response;
7369         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7370         this.form.afterAction(this, false);
7371     },
7372
7373     processResponse : function(response){
7374         this.response = response;
7375         if(!response.responseText){
7376             return true;
7377         }
7378         this.result = this.handleResponse(response);
7379         return this.result;
7380     },
7381
7382     // utility functions used internally
7383     getUrl : function(appendParams){
7384         var url = this.options.url || this.form.url || this.form.el.dom.action;
7385         if(appendParams){
7386             var p = this.getParams();
7387             if(p){
7388                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7389             }
7390         }
7391         return url;
7392     },
7393
7394     getMethod : function(){
7395         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7396     },
7397
7398     getParams : function(){
7399         var bp = this.form.baseParams;
7400         var p = this.options.params;
7401         if(p){
7402             if(typeof p == "object"){
7403                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7404             }else if(typeof p == 'string' && bp){
7405                 p += '&' + Roo.urlEncode(bp);
7406             }
7407         }else if(bp){
7408             p = Roo.urlEncode(bp);
7409         }
7410         return p;
7411     },
7412
7413     createCallback : function(){
7414         return {
7415             success: this.success,
7416             failure: this.failure,
7417             scope: this,
7418             timeout: (this.form.timeout*1000),
7419             upload: this.form.fileUpload ? this.success : undefined
7420         };
7421     }
7422 };
7423
7424 Roo.form.Action.Submit = function(form, options){
7425     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7426 };
7427
7428 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7429     type : 'submit',
7430
7431     haveProgress : false,
7432     uploadComplete : false,
7433     
7434     // uploadProgress indicator.
7435     uploadProgress : function()
7436     {
7437         if (!this.form.progressUrl) {
7438             return;
7439         }
7440         
7441         if (!this.haveProgress) {
7442             Roo.MessageBox.progress("Uploading", "Uploading");
7443         }
7444         if (this.uploadComplete) {
7445            Roo.MessageBox.hide();
7446            return;
7447         }
7448         
7449         this.haveProgress = true;
7450    
7451         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7452         
7453         var c = new Roo.data.Connection();
7454         c.request({
7455             url : this.form.progressUrl,
7456             params: {
7457                 id : uid
7458             },
7459             method: 'GET',
7460             success : function(req){
7461                //console.log(data);
7462                 var rdata = false;
7463                 var edata;
7464                 try  {
7465                    rdata = Roo.decode(req.responseText)
7466                 } catch (e) {
7467                     Roo.log("Invalid data from server..");
7468                     Roo.log(edata);
7469                     return;
7470                 }
7471                 if (!rdata || !rdata.success) {
7472                     Roo.log(rdata);
7473                     Roo.MessageBox.alert(Roo.encode(rdata));
7474                     return;
7475                 }
7476                 var data = rdata.data;
7477                 
7478                 if (this.uploadComplete) {
7479                    Roo.MessageBox.hide();
7480                    return;
7481                 }
7482                    
7483                 if (data){
7484                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7485                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7486                     );
7487                 }
7488                 this.uploadProgress.defer(2000,this);
7489             },
7490        
7491             failure: function(data) {
7492                 Roo.log('progress url failed ');
7493                 Roo.log(data);
7494             },
7495             scope : this
7496         });
7497            
7498     },
7499     
7500     
7501     run : function()
7502     {
7503         // run get Values on the form, so it syncs any secondary forms.
7504         this.form.getValues();
7505         
7506         var o = this.options;
7507         var method = this.getMethod();
7508         var isPost = method == 'POST';
7509         if(o.clientValidation === false || this.form.isValid()){
7510             
7511             if (this.form.progressUrl) {
7512                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7513                     (new Date() * 1) + '' + Math.random());
7514                     
7515             } 
7516             
7517             
7518             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7519                 form:this.form.el.dom,
7520                 url:this.getUrl(!isPost),
7521                 method: method,
7522                 params:isPost ? this.getParams() : null,
7523                 isUpload: this.form.fileUpload
7524             }));
7525             
7526             this.uploadProgress();
7527
7528         }else if (o.clientValidation !== false){ // client validation failed
7529             this.failureType = Roo.form.Action.CLIENT_INVALID;
7530             this.form.afterAction(this, false);
7531         }
7532     },
7533
7534     success : function(response)
7535     {
7536         this.uploadComplete= true;
7537         if (this.haveProgress) {
7538             Roo.MessageBox.hide();
7539         }
7540         
7541         
7542         var result = this.processResponse(response);
7543         if(result === true || result.success){
7544             this.form.afterAction(this, true);
7545             return;
7546         }
7547         if(result.errors){
7548             this.form.markInvalid(result.errors);
7549             this.failureType = Roo.form.Action.SERVER_INVALID;
7550         }
7551         this.form.afterAction(this, false);
7552     },
7553     failure : function(response)
7554     {
7555         this.uploadComplete= true;
7556         if (this.haveProgress) {
7557             Roo.MessageBox.hide();
7558         }
7559         
7560         this.response = response;
7561         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7562         this.form.afterAction(this, false);
7563     },
7564     
7565     handleResponse : function(response){
7566         if(this.form.errorReader){
7567             var rs = this.form.errorReader.read(response);
7568             var errors = [];
7569             if(rs.records){
7570                 for(var i = 0, len = rs.records.length; i < len; i++) {
7571                     var r = rs.records[i];
7572                     errors[i] = r.data;
7573                 }
7574             }
7575             if(errors.length < 1){
7576                 errors = null;
7577             }
7578             return {
7579                 success : rs.success,
7580                 errors : errors
7581             };
7582         }
7583         var ret = false;
7584         try {
7585             ret = Roo.decode(response.responseText);
7586         } catch (e) {
7587             ret = {
7588                 success: false,
7589                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7590                 errors : []
7591             };
7592         }
7593         return ret;
7594         
7595     }
7596 });
7597
7598
7599 Roo.form.Action.Load = function(form, options){
7600     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7601     this.reader = this.form.reader;
7602 };
7603
7604 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7605     type : 'load',
7606
7607     run : function(){
7608         
7609         Roo.Ajax.request(Roo.apply(
7610                 this.createCallback(), {
7611                     method:this.getMethod(),
7612                     url:this.getUrl(false),
7613                     params:this.getParams()
7614         }));
7615     },
7616
7617     success : function(response){
7618         
7619         var result = this.processResponse(response);
7620         if(result === true || !result.success || !result.data){
7621             this.failureType = Roo.form.Action.LOAD_FAILURE;
7622             this.form.afterAction(this, false);
7623             return;
7624         }
7625         this.form.clearInvalid();
7626         this.form.setValues(result.data);
7627         this.form.afterAction(this, true);
7628     },
7629
7630     handleResponse : function(response){
7631         if(this.form.reader){
7632             var rs = this.form.reader.read(response);
7633             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7634             return {
7635                 success : rs.success,
7636                 data : data
7637             };
7638         }
7639         return Roo.decode(response.responseText);
7640     }
7641 });
7642
7643 Roo.form.Action.ACTION_TYPES = {
7644     'load' : Roo.form.Action.Load,
7645     'submit' : Roo.form.Action.Submit
7646 };/*
7647  * - LGPL
7648  *
7649  * form
7650  *
7651  */
7652
7653 /**
7654  * @class Roo.bootstrap.Form
7655  * @extends Roo.bootstrap.Component
7656  * Bootstrap Form class
7657  * @cfg {String} method  GET | POST (default POST)
7658  * @cfg {String} labelAlign top | left (default top)
7659  * @cfg {String} align left  | right - for navbars
7660  * @cfg {Boolean} loadMask load mask when submit (default true)
7661
7662  *
7663  * @constructor
7664  * Create a new Form
7665  * @param {Object} config The config object
7666  */
7667
7668
7669 Roo.bootstrap.Form = function(config){
7670     
7671     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7672     
7673     Roo.bootstrap.Form.popover.apply();
7674     
7675     this.addEvents({
7676         /**
7677          * @event clientvalidation
7678          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7679          * @param {Form} this
7680          * @param {Boolean} valid true if the form has passed client-side validation
7681          */
7682         clientvalidation: true,
7683         /**
7684          * @event beforeaction
7685          * Fires before any action is performed. Return false to cancel the action.
7686          * @param {Form} this
7687          * @param {Action} action The action to be performed
7688          */
7689         beforeaction: true,
7690         /**
7691          * @event actionfailed
7692          * Fires when an action fails.
7693          * @param {Form} this
7694          * @param {Action} action The action that failed
7695          */
7696         actionfailed : true,
7697         /**
7698          * @event actioncomplete
7699          * Fires when an action is completed.
7700          * @param {Form} this
7701          * @param {Action} action The action that completed
7702          */
7703         actioncomplete : true
7704     });
7705 };
7706
7707 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7708
7709      /**
7710      * @cfg {String} method
7711      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7712      */
7713     method : 'POST',
7714     /**
7715      * @cfg {String} url
7716      * The URL to use for form actions if one isn't supplied in the action options.
7717      */
7718     /**
7719      * @cfg {Boolean} fileUpload
7720      * Set to true if this form is a file upload.
7721      */
7722
7723     /**
7724      * @cfg {Object} baseParams
7725      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7726      */
7727
7728     /**
7729      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7730      */
7731     timeout: 30,
7732     /**
7733      * @cfg {Sting} align (left|right) for navbar forms
7734      */
7735     align : 'left',
7736
7737     // private
7738     activeAction : null,
7739
7740     /**
7741      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7742      * element by passing it or its id or mask the form itself by passing in true.
7743      * @type Mixed
7744      */
7745     waitMsgTarget : false,
7746
7747     loadMask : true,
7748     
7749     /**
7750      * @cfg {Boolean} errorMask (true|false) default false
7751      */
7752     errorMask : false,
7753     
7754     /**
7755      * @cfg {Number} maskOffset Default 100
7756      */
7757     maskOffset : 100,
7758     
7759     /**
7760      * @cfg {Boolean} maskBody
7761      */
7762     maskBody : false,
7763
7764     getAutoCreate : function(){
7765
7766         var cfg = {
7767             tag: 'form',
7768             method : this.method || 'POST',
7769             id : this.id || Roo.id(),
7770             cls : ''
7771         };
7772         if (this.parent().xtype.match(/^Nav/)) {
7773             cfg.cls = 'navbar-form navbar-' + this.align;
7774
7775         }
7776
7777         if (this.labelAlign == 'left' ) {
7778             cfg.cls += ' form-horizontal';
7779         }
7780
7781
7782         return cfg;
7783     },
7784     initEvents : function()
7785     {
7786         this.el.on('submit', this.onSubmit, this);
7787         // this was added as random key presses on the form where triggering form submit.
7788         this.el.on('keypress', function(e) {
7789             if (e.getCharCode() != 13) {
7790                 return true;
7791             }
7792             // we might need to allow it for textareas.. and some other items.
7793             // check e.getTarget().
7794
7795             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7796                 return true;
7797             }
7798
7799             Roo.log("keypress blocked");
7800
7801             e.preventDefault();
7802             return false;
7803         });
7804         
7805     },
7806     // private
7807     onSubmit : function(e){
7808         e.stopEvent();
7809     },
7810
7811      /**
7812      * Returns true if client-side validation on the form is successful.
7813      * @return Boolean
7814      */
7815     isValid : function(){
7816         var items = this.getItems();
7817         var valid = true;
7818         var target = false;
7819         
7820         items.each(function(f){
7821             
7822             if(f.validate()){
7823                 return;
7824             }
7825             
7826             valid = false;
7827
7828             if(!target && f.el.isVisible(true)){
7829                 target = f;
7830             }
7831            
7832         });
7833         
7834         if(this.errorMask && !valid){
7835             Roo.bootstrap.Form.popover.mask(this, target);
7836         }
7837         
7838         return valid;
7839     },
7840     
7841     /**
7842      * Returns true if any fields in this form have changed since their original load.
7843      * @return Boolean
7844      */
7845     isDirty : function(){
7846         var dirty = false;
7847         var items = this.getItems();
7848         items.each(function(f){
7849            if(f.isDirty()){
7850                dirty = true;
7851                return false;
7852            }
7853            return true;
7854         });
7855         return dirty;
7856     },
7857      /**
7858      * Performs a predefined action (submit or load) or custom actions you define on this form.
7859      * @param {String} actionName The name of the action type
7860      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7861      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7862      * accept other config options):
7863      * <pre>
7864 Property          Type             Description
7865 ----------------  ---------------  ----------------------------------------------------------------------------------
7866 url               String           The url for the action (defaults to the form's url)
7867 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7868 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7869 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7870                                    validate the form on the client (defaults to false)
7871      * </pre>
7872      * @return {BasicForm} this
7873      */
7874     doAction : function(action, options){
7875         if(typeof action == 'string'){
7876             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7877         }
7878         if(this.fireEvent('beforeaction', this, action) !== false){
7879             this.beforeAction(action);
7880             action.run.defer(100, action);
7881         }
7882         return this;
7883     },
7884
7885     // private
7886     beforeAction : function(action){
7887         var o = action.options;
7888         
7889         if(this.loadMask){
7890             
7891             if(this.maskBody){
7892                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7893             } else {
7894                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7895             }
7896         }
7897         // not really supported yet.. ??
7898
7899         //if(this.waitMsgTarget === true){
7900         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7901         //}else if(this.waitMsgTarget){
7902         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7903         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7904         //}else {
7905         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7906        // }
7907
7908     },
7909
7910     // private
7911     afterAction : function(action, success){
7912         this.activeAction = null;
7913         var o = action.options;
7914
7915         if(this.loadMask){
7916             
7917             if(this.maskBody){
7918                 Roo.get(document.body).unmask();
7919             } else {
7920                 this.el.unmask();
7921             }
7922         }
7923         
7924         //if(this.waitMsgTarget === true){
7925 //            this.el.unmask();
7926         //}else if(this.waitMsgTarget){
7927         //    this.waitMsgTarget.unmask();
7928         //}else{
7929         //    Roo.MessageBox.updateProgress(1);
7930         //    Roo.MessageBox.hide();
7931        // }
7932         //
7933         if(success){
7934             if(o.reset){
7935                 this.reset();
7936             }
7937             Roo.callback(o.success, o.scope, [this, action]);
7938             this.fireEvent('actioncomplete', this, action);
7939
7940         }else{
7941
7942             // failure condition..
7943             // we have a scenario where updates need confirming.
7944             // eg. if a locking scenario exists..
7945             // we look for { errors : { needs_confirm : true }} in the response.
7946             if (
7947                 (typeof(action.result) != 'undefined')  &&
7948                 (typeof(action.result.errors) != 'undefined')  &&
7949                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7950            ){
7951                 var _t = this;
7952                 Roo.log("not supported yet");
7953                  /*
7954
7955                 Roo.MessageBox.confirm(
7956                     "Change requires confirmation",
7957                     action.result.errorMsg,
7958                     function(r) {
7959                         if (r != 'yes') {
7960                             return;
7961                         }
7962                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7963                     }
7964
7965                 );
7966                 */
7967
7968
7969                 return;
7970             }
7971
7972             Roo.callback(o.failure, o.scope, [this, action]);
7973             // show an error message if no failed handler is set..
7974             if (!this.hasListener('actionfailed')) {
7975                 Roo.log("need to add dialog support");
7976                 /*
7977                 Roo.MessageBox.alert("Error",
7978                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7979                         action.result.errorMsg :
7980                         "Saving Failed, please check your entries or try again"
7981                 );
7982                 */
7983             }
7984
7985             this.fireEvent('actionfailed', this, action);
7986         }
7987
7988     },
7989     /**
7990      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7991      * @param {String} id The value to search for
7992      * @return Field
7993      */
7994     findField : function(id){
7995         var items = this.getItems();
7996         var field = items.get(id);
7997         if(!field){
7998              items.each(function(f){
7999                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8000                     field = f;
8001                     return false;
8002                 }
8003                 return true;
8004             });
8005         }
8006         return field || null;
8007     },
8008      /**
8009      * Mark fields in this form invalid in bulk.
8010      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8011      * @return {BasicForm} this
8012      */
8013     markInvalid : function(errors){
8014         if(errors instanceof Array){
8015             for(var i = 0, len = errors.length; i < len; i++){
8016                 var fieldError = errors[i];
8017                 var f = this.findField(fieldError.id);
8018                 if(f){
8019                     f.markInvalid(fieldError.msg);
8020                 }
8021             }
8022         }else{
8023             var field, id;
8024             for(id in errors){
8025                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8026                     field.markInvalid(errors[id]);
8027                 }
8028             }
8029         }
8030         //Roo.each(this.childForms || [], function (f) {
8031         //    f.markInvalid(errors);
8032         //});
8033
8034         return this;
8035     },
8036
8037     /**
8038      * Set values for fields in this form in bulk.
8039      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8040      * @return {BasicForm} this
8041      */
8042     setValues : function(values){
8043         if(values instanceof Array){ // array of objects
8044             for(var i = 0, len = values.length; i < len; i++){
8045                 var v = values[i];
8046                 var f = this.findField(v.id);
8047                 if(f){
8048                     f.setValue(v.value);
8049                     if(this.trackResetOnLoad){
8050                         f.originalValue = f.getValue();
8051                     }
8052                 }
8053             }
8054         }else{ // object hash
8055             var field, id;
8056             for(id in values){
8057                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8058
8059                     if (field.setFromData &&
8060                         field.valueField &&
8061                         field.displayField &&
8062                         // combos' with local stores can
8063                         // be queried via setValue()
8064                         // to set their value..
8065                         (field.store && !field.store.isLocal)
8066                         ) {
8067                         // it's a combo
8068                         var sd = { };
8069                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8070                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8071                         field.setFromData(sd);
8072
8073                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8074                         
8075                         field.setFromData(values);
8076                         
8077                     } else {
8078                         field.setValue(values[id]);
8079                     }
8080
8081
8082                     if(this.trackResetOnLoad){
8083                         field.originalValue = field.getValue();
8084                     }
8085                 }
8086             }
8087         }
8088
8089         //Roo.each(this.childForms || [], function (f) {
8090         //    f.setValues(values);
8091         //});
8092
8093         return this;
8094     },
8095
8096     /**
8097      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8098      * they are returned as an array.
8099      * @param {Boolean} asString
8100      * @return {Object}
8101      */
8102     getValues : function(asString){
8103         //if (this.childForms) {
8104             // copy values from the child forms
8105         //    Roo.each(this.childForms, function (f) {
8106         //        this.setValues(f.getValues());
8107         //    }, this);
8108         //}
8109
8110
8111
8112         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8113         if(asString === true){
8114             return fs;
8115         }
8116         return Roo.urlDecode(fs);
8117     },
8118
8119     /**
8120      * Returns the fields in this form as an object with key/value pairs.
8121      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8122      * @return {Object}
8123      */
8124     getFieldValues : function(with_hidden)
8125     {
8126         var items = this.getItems();
8127         var ret = {};
8128         items.each(function(f){
8129             
8130             if (!f.getName()) {
8131                 return;
8132             }
8133             
8134             var v = f.getValue();
8135             
8136             if (f.inputType =='radio') {
8137                 if (typeof(ret[f.getName()]) == 'undefined') {
8138                     ret[f.getName()] = ''; // empty..
8139                 }
8140
8141                 if (!f.el.dom.checked) {
8142                     return;
8143
8144                 }
8145                 v = f.el.dom.value;
8146
8147             }
8148             
8149             if(f.xtype == 'MoneyField'){
8150                 ret[f.currencyName] = f.getCurrency();
8151             }
8152
8153             // not sure if this supported any more..
8154             if ((typeof(v) == 'object') && f.getRawValue) {
8155                 v = f.getRawValue() ; // dates..
8156             }
8157             // combo boxes where name != hiddenName...
8158             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8159                 ret[f.name] = f.getRawValue();
8160             }
8161             ret[f.getName()] = v;
8162         });
8163
8164         return ret;
8165     },
8166
8167     /**
8168      * Clears all invalid messages in this form.
8169      * @return {BasicForm} this
8170      */
8171     clearInvalid : function(){
8172         var items = this.getItems();
8173
8174         items.each(function(f){
8175            f.clearInvalid();
8176         });
8177
8178         return this;
8179     },
8180
8181     /**
8182      * Resets this form.
8183      * @return {BasicForm} this
8184      */
8185     reset : function(){
8186         var items = this.getItems();
8187         items.each(function(f){
8188             f.reset();
8189         });
8190
8191         Roo.each(this.childForms || [], function (f) {
8192             f.reset();
8193         });
8194
8195
8196         return this;
8197     },
8198     
8199     getItems : function()
8200     {
8201         var r=new Roo.util.MixedCollection(false, function(o){
8202             return o.id || (o.id = Roo.id());
8203         });
8204         var iter = function(el) {
8205             if (el.inputEl) {
8206                 r.add(el);
8207             }
8208             if (!el.items) {
8209                 return;
8210             }
8211             Roo.each(el.items,function(e) {
8212                 iter(e);
8213             });
8214         };
8215
8216         iter(this);
8217         return r;
8218     },
8219     
8220     hideFields : function(items)
8221     {
8222         Roo.each(items, function(i){
8223             
8224             var f = this.findField(i);
8225             
8226             if(!f){
8227                 return;
8228             }
8229             
8230             if(f.xtype == 'DateField'){
8231                 f.setVisible(false);
8232                 return;
8233             }
8234             
8235             f.hide();
8236             
8237         }, this);
8238     },
8239     
8240     showFields : function(items)
8241     {
8242         Roo.each(items, function(i){
8243             
8244             var f = this.findField(i);
8245             
8246             if(!f){
8247                 return;
8248             }
8249             
8250             if(f.xtype == 'DateField'){
8251                 f.setVisible(true);
8252                 return;
8253             }
8254             
8255             f.show();
8256             
8257         }, this);
8258     }
8259
8260 });
8261
8262 Roo.apply(Roo.bootstrap.Form, {
8263     
8264     popover : {
8265         
8266         padding : 5,
8267         
8268         isApplied : false,
8269         
8270         isMasked : false,
8271         
8272         form : false,
8273         
8274         target : false,
8275         
8276         toolTip : false,
8277         
8278         intervalID : false,
8279         
8280         maskEl : false,
8281         
8282         apply : function()
8283         {
8284             if(this.isApplied){
8285                 return;
8286             }
8287             
8288             this.maskEl = {
8289                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8290                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8291                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8292                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8293             };
8294             
8295             this.maskEl.top.enableDisplayMode("block");
8296             this.maskEl.left.enableDisplayMode("block");
8297             this.maskEl.bottom.enableDisplayMode("block");
8298             this.maskEl.right.enableDisplayMode("block");
8299             
8300             this.toolTip = new Roo.bootstrap.Tooltip({
8301                 cls : 'roo-form-error-popover',
8302                 alignment : {
8303                     'left' : ['r-l', [-2,0], 'right'],
8304                     'right' : ['l-r', [2,0], 'left'],
8305                     'bottom' : ['tl-bl', [0,2], 'top'],
8306                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8307                 }
8308             });
8309             
8310             this.toolTip.render(Roo.get(document.body));
8311
8312             this.toolTip.el.enableDisplayMode("block");
8313             
8314             Roo.get(document.body).on('click', function(){
8315                 this.unmask();
8316             }, this);
8317             
8318             Roo.get(document.body).on('touchstart', function(){
8319                 this.unmask();
8320             }, this);
8321             
8322             this.isApplied = true
8323         },
8324         
8325         mask : function(form, target)
8326         {
8327             this.form = form;
8328             
8329             this.target = target;
8330             
8331             if(!this.form.errorMask || !target.el){
8332                 return;
8333             }
8334             
8335             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8336             
8337             Roo.log(scrollable);
8338             
8339             var ot = this.target.el.calcOffsetsTo(scrollable);
8340             
8341             var scrollTo = ot[1] - this.form.maskOffset;
8342             
8343             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8344             
8345             scrollable.scrollTo('top', scrollTo);
8346             
8347             var box = this.target.el.getBox();
8348             Roo.log(box);
8349             var zIndex = Roo.bootstrap.Modal.zIndex++;
8350
8351             
8352             this.maskEl.top.setStyle('position', 'absolute');
8353             this.maskEl.top.setStyle('z-index', zIndex);
8354             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8355             this.maskEl.top.setLeft(0);
8356             this.maskEl.top.setTop(0);
8357             this.maskEl.top.show();
8358             
8359             this.maskEl.left.setStyle('position', 'absolute');
8360             this.maskEl.left.setStyle('z-index', zIndex);
8361             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8362             this.maskEl.left.setLeft(0);
8363             this.maskEl.left.setTop(box.y - this.padding);
8364             this.maskEl.left.show();
8365
8366             this.maskEl.bottom.setStyle('position', 'absolute');
8367             this.maskEl.bottom.setStyle('z-index', zIndex);
8368             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8369             this.maskEl.bottom.setLeft(0);
8370             this.maskEl.bottom.setTop(box.bottom + this.padding);
8371             this.maskEl.bottom.show();
8372
8373             this.maskEl.right.setStyle('position', 'absolute');
8374             this.maskEl.right.setStyle('z-index', zIndex);
8375             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8376             this.maskEl.right.setLeft(box.right + this.padding);
8377             this.maskEl.right.setTop(box.y - this.padding);
8378             this.maskEl.right.show();
8379
8380             this.toolTip.bindEl = this.target.el;
8381
8382             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8383
8384             var tip = this.target.blankText;
8385
8386             if(this.target.getValue() !== '' ) {
8387                 
8388                 if (this.target.invalidText.length) {
8389                     tip = this.target.invalidText;
8390                 } else if (this.target.regexText.length){
8391                     tip = this.target.regexText;
8392                 }
8393             }
8394
8395             this.toolTip.show(tip);
8396
8397             this.intervalID = window.setInterval(function() {
8398                 Roo.bootstrap.Form.popover.unmask();
8399             }, 10000);
8400
8401             window.onwheel = function(){ return false;};
8402             
8403             (function(){ this.isMasked = true; }).defer(500, this);
8404             
8405         },
8406         
8407         unmask : function()
8408         {
8409             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8410                 return;
8411             }
8412             
8413             this.maskEl.top.setStyle('position', 'absolute');
8414             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8415             this.maskEl.top.hide();
8416
8417             this.maskEl.left.setStyle('position', 'absolute');
8418             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8419             this.maskEl.left.hide();
8420
8421             this.maskEl.bottom.setStyle('position', 'absolute');
8422             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8423             this.maskEl.bottom.hide();
8424
8425             this.maskEl.right.setStyle('position', 'absolute');
8426             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8427             this.maskEl.right.hide();
8428             
8429             this.toolTip.hide();
8430             
8431             this.toolTip.el.hide();
8432             
8433             window.onwheel = function(){ return true;};
8434             
8435             if(this.intervalID){
8436                 window.clearInterval(this.intervalID);
8437                 this.intervalID = false;
8438             }
8439             
8440             this.isMasked = false;
8441             
8442         }
8443         
8444     }
8445     
8446 });
8447
8448 /*
8449  * Based on:
8450  * Ext JS Library 1.1.1
8451  * Copyright(c) 2006-2007, Ext JS, LLC.
8452  *
8453  * Originally Released Under LGPL - original licence link has changed is not relivant.
8454  *
8455  * Fork - LGPL
8456  * <script type="text/javascript">
8457  */
8458 /**
8459  * @class Roo.form.VTypes
8460  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8461  * @singleton
8462  */
8463 Roo.form.VTypes = function(){
8464     // closure these in so they are only created once.
8465     var alpha = /^[a-zA-Z_]+$/;
8466     var alphanum = /^[a-zA-Z0-9_]+$/;
8467     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8468     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8469
8470     // All these messages and functions are configurable
8471     return {
8472         /**
8473          * The function used to validate email addresses
8474          * @param {String} value The email address
8475          */
8476         'email' : function(v){
8477             return email.test(v);
8478         },
8479         /**
8480          * The error text to display when the email validation function returns false
8481          * @type String
8482          */
8483         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8484         /**
8485          * The keystroke filter mask to be applied on email input
8486          * @type RegExp
8487          */
8488         'emailMask' : /[a-z0-9_\.\-@]/i,
8489
8490         /**
8491          * The function used to validate URLs
8492          * @param {String} value The URL
8493          */
8494         'url' : function(v){
8495             return url.test(v);
8496         },
8497         /**
8498          * The error text to display when the url validation function returns false
8499          * @type String
8500          */
8501         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8502         
8503         /**
8504          * The function used to validate alpha values
8505          * @param {String} value The value
8506          */
8507         'alpha' : function(v){
8508             return alpha.test(v);
8509         },
8510         /**
8511          * The error text to display when the alpha validation function returns false
8512          * @type String
8513          */
8514         'alphaText' : 'This field should only contain letters and _',
8515         /**
8516          * The keystroke filter mask to be applied on alpha input
8517          * @type RegExp
8518          */
8519         'alphaMask' : /[a-z_]/i,
8520
8521         /**
8522          * The function used to validate alphanumeric values
8523          * @param {String} value The value
8524          */
8525         'alphanum' : function(v){
8526             return alphanum.test(v);
8527         },
8528         /**
8529          * The error text to display when the alphanumeric validation function returns false
8530          * @type String
8531          */
8532         'alphanumText' : 'This field should only contain letters, numbers and _',
8533         /**
8534          * The keystroke filter mask to be applied on alphanumeric input
8535          * @type RegExp
8536          */
8537         'alphanumMask' : /[a-z0-9_]/i
8538     };
8539 }();/*
8540  * - LGPL
8541  *
8542  * Input
8543  * 
8544  */
8545
8546 /**
8547  * @class Roo.bootstrap.Input
8548  * @extends Roo.bootstrap.Component
8549  * Bootstrap Input class
8550  * @cfg {Boolean} disabled is it disabled
8551  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8552  * @cfg {String} name name of the input
8553  * @cfg {string} fieldLabel - the label associated
8554  * @cfg {string} placeholder - placeholder to put in text.
8555  * @cfg {string}  before - input group add on before
8556  * @cfg {string} after - input group add on after
8557  * @cfg {string} size - (lg|sm) or leave empty..
8558  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8559  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8560  * @cfg {Number} md colspan out of 12 for computer-sized screens
8561  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8562  * @cfg {string} value default value of the input
8563  * @cfg {Number} labelWidth set the width of label 
8564  * @cfg {Number} labellg set the width of label (1-12)
8565  * @cfg {Number} labelmd set the width of label (1-12)
8566  * @cfg {Number} labelsm set the width of label (1-12)
8567  * @cfg {Number} labelxs set the width of label (1-12)
8568  * @cfg {String} labelAlign (top|left)
8569  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8570  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8571  * @cfg {String} indicatorpos (left|right) default left
8572  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8573  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8574
8575  * @cfg {String} align (left|center|right) Default left
8576  * @cfg {Boolean} forceFeedback (true|false) Default false
8577  * 
8578  * @constructor
8579  * Create a new Input
8580  * @param {Object} config The config object
8581  */
8582
8583 Roo.bootstrap.Input = function(config){
8584     
8585     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8586     
8587     this.addEvents({
8588         /**
8589          * @event focus
8590          * Fires when this field receives input focus.
8591          * @param {Roo.form.Field} this
8592          */
8593         focus : true,
8594         /**
8595          * @event blur
8596          * Fires when this field loses input focus.
8597          * @param {Roo.form.Field} this
8598          */
8599         blur : true,
8600         /**
8601          * @event specialkey
8602          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8603          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8604          * @param {Roo.form.Field} this
8605          * @param {Roo.EventObject} e The event object
8606          */
8607         specialkey : true,
8608         /**
8609          * @event change
8610          * Fires just before the field blurs if the field value has changed.
8611          * @param {Roo.form.Field} this
8612          * @param {Mixed} newValue The new value
8613          * @param {Mixed} oldValue The original value
8614          */
8615         change : true,
8616         /**
8617          * @event invalid
8618          * Fires after the field has been marked as invalid.
8619          * @param {Roo.form.Field} this
8620          * @param {String} msg The validation message
8621          */
8622         invalid : true,
8623         /**
8624          * @event valid
8625          * Fires after the field has been validated with no errors.
8626          * @param {Roo.form.Field} this
8627          */
8628         valid : true,
8629          /**
8630          * @event keyup
8631          * Fires after the key up
8632          * @param {Roo.form.Field} this
8633          * @param {Roo.EventObject}  e The event Object
8634          */
8635         keyup : true
8636     });
8637 };
8638
8639 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8640      /**
8641      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8642       automatic validation (defaults to "keyup").
8643      */
8644     validationEvent : "keyup",
8645      /**
8646      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8647      */
8648     validateOnBlur : true,
8649     /**
8650      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8651      */
8652     validationDelay : 250,
8653      /**
8654      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8655      */
8656     focusClass : "x-form-focus",  // not needed???
8657     
8658        
8659     /**
8660      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8661      */
8662     invalidClass : "has-warning",
8663     
8664     /**
8665      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8666      */
8667     validClass : "has-success",
8668     
8669     /**
8670      * @cfg {Boolean} hasFeedback (true|false) default true
8671      */
8672     hasFeedback : true,
8673     
8674     /**
8675      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8676      */
8677     invalidFeedbackClass : "glyphicon-warning-sign",
8678     
8679     /**
8680      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8681      */
8682     validFeedbackClass : "glyphicon-ok",
8683     
8684     /**
8685      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8686      */
8687     selectOnFocus : false,
8688     
8689      /**
8690      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8691      */
8692     maskRe : null,
8693        /**
8694      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8695      */
8696     vtype : null,
8697     
8698       /**
8699      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8700      */
8701     disableKeyFilter : false,
8702     
8703        /**
8704      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8705      */
8706     disabled : false,
8707      /**
8708      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8709      */
8710     allowBlank : true,
8711     /**
8712      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8713      */
8714     blankText : "Please complete this mandatory field",
8715     
8716      /**
8717      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8718      */
8719     minLength : 0,
8720     /**
8721      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8722      */
8723     maxLength : Number.MAX_VALUE,
8724     /**
8725      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8726      */
8727     minLengthText : "The minimum length for this field is {0}",
8728     /**
8729      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8730      */
8731     maxLengthText : "The maximum length for this field is {0}",
8732   
8733     
8734     /**
8735      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8736      * If available, this function will be called only after the basic validators all return true, and will be passed the
8737      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8738      */
8739     validator : null,
8740     /**
8741      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8742      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8743      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8744      */
8745     regex : null,
8746     /**
8747      * @cfg {String} regexText -- Depricated - use Invalid Text
8748      */
8749     regexText : "",
8750     
8751     /**
8752      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8753      */
8754     invalidText : "",
8755     
8756     
8757     
8758     autocomplete: false,
8759     
8760     
8761     fieldLabel : '',
8762     inputType : 'text',
8763     
8764     name : false,
8765     placeholder: false,
8766     before : false,
8767     after : false,
8768     size : false,
8769     hasFocus : false,
8770     preventMark: false,
8771     isFormField : true,
8772     value : '',
8773     labelWidth : 2,
8774     labelAlign : false,
8775     readOnly : false,
8776     align : false,
8777     formatedValue : false,
8778     forceFeedback : false,
8779     
8780     indicatorpos : 'left',
8781     
8782     labellg : 0,
8783     labelmd : 0,
8784     labelsm : 0,
8785     labelxs : 0,
8786     
8787     capture : '',
8788     accept : '',
8789     
8790     parentLabelAlign : function()
8791     {
8792         var parent = this;
8793         while (parent.parent()) {
8794             parent = parent.parent();
8795             if (typeof(parent.labelAlign) !='undefined') {
8796                 return parent.labelAlign;
8797             }
8798         }
8799         return 'left';
8800         
8801     },
8802     
8803     getAutoCreate : function()
8804     {
8805         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8806         
8807         var id = Roo.id();
8808         
8809         var cfg = {};
8810         
8811         if(this.inputType != 'hidden'){
8812             cfg.cls = 'form-group' //input-group
8813         }
8814         
8815         var input =  {
8816             tag: 'input',
8817             id : id,
8818             type : this.inputType,
8819             value : this.value,
8820             cls : 'form-control',
8821             placeholder : this.placeholder || '',
8822             autocomplete : this.autocomplete || 'new-password'
8823         };
8824         
8825         if(this.capture.length){
8826             input.capture = this.capture;
8827         }
8828         
8829         if(this.accept.length){
8830             input.accept = this.accept + "/*";
8831         }
8832         
8833         if(this.align){
8834             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8835         }
8836         
8837         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8838             input.maxLength = this.maxLength;
8839         }
8840         
8841         if (this.disabled) {
8842             input.disabled=true;
8843         }
8844         
8845         if (this.readOnly) {
8846             input.readonly=true;
8847         }
8848         
8849         if (this.name) {
8850             input.name = this.name;
8851         }
8852         
8853         if (this.size) {
8854             input.cls += ' input-' + this.size;
8855         }
8856         
8857         var settings=this;
8858         ['xs','sm','md','lg'].map(function(size){
8859             if (settings[size]) {
8860                 cfg.cls += ' col-' + size + '-' + settings[size];
8861             }
8862         });
8863         
8864         var inputblock = input;
8865         
8866         var feedback = {
8867             tag: 'span',
8868             cls: 'glyphicon form-control-feedback'
8869         };
8870             
8871         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8872             
8873             inputblock = {
8874                 cls : 'has-feedback',
8875                 cn :  [
8876                     input,
8877                     feedback
8878                 ] 
8879             };  
8880         }
8881         
8882         if (this.before || this.after) {
8883             
8884             inputblock = {
8885                 cls : 'input-group',
8886                 cn :  [] 
8887             };
8888             
8889             if (this.before && typeof(this.before) == 'string') {
8890                 
8891                 inputblock.cn.push({
8892                     tag :'span',
8893                     cls : 'roo-input-before input-group-addon',
8894                     html : this.before
8895                 });
8896             }
8897             if (this.before && typeof(this.before) == 'object') {
8898                 this.before = Roo.factory(this.before);
8899                 
8900                 inputblock.cn.push({
8901                     tag :'span',
8902                     cls : 'roo-input-before input-group-' +
8903                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8904                 });
8905             }
8906             
8907             inputblock.cn.push(input);
8908             
8909             if (this.after && typeof(this.after) == 'string') {
8910                 inputblock.cn.push({
8911                     tag :'span',
8912                     cls : 'roo-input-after input-group-addon',
8913                     html : this.after
8914                 });
8915             }
8916             if (this.after && typeof(this.after) == 'object') {
8917                 this.after = Roo.factory(this.after);
8918                 
8919                 inputblock.cn.push({
8920                     tag :'span',
8921                     cls : 'roo-input-after input-group-' +
8922                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8923                 });
8924             }
8925             
8926             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8927                 inputblock.cls += ' has-feedback';
8928                 inputblock.cn.push(feedback);
8929             }
8930         };
8931         
8932         if (align ==='left' && this.fieldLabel.length) {
8933             
8934             cfg.cls += ' roo-form-group-label-left';
8935             
8936             cfg.cn = [
8937                 {
8938                     tag : 'i',
8939                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8940                     tooltip : 'This field is required'
8941                 },
8942                 {
8943                     tag: 'label',
8944                     'for' :  id,
8945                     cls : 'control-label',
8946                     html : this.fieldLabel
8947
8948                 },
8949                 {
8950                     cls : "", 
8951                     cn: [
8952                         inputblock
8953                     ]
8954                 }
8955             ];
8956             
8957             var labelCfg = cfg.cn[1];
8958             var contentCfg = cfg.cn[2];
8959             
8960             if(this.indicatorpos == 'right'){
8961                 cfg.cn = [
8962                     {
8963                         tag: 'label',
8964                         'for' :  id,
8965                         cls : 'control-label',
8966                         cn : [
8967                             {
8968                                 tag : 'span',
8969                                 html : this.fieldLabel
8970                             },
8971                             {
8972                                 tag : 'i',
8973                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8974                                 tooltip : 'This field is required'
8975                             }
8976                         ]
8977                     },
8978                     {
8979                         cls : "",
8980                         cn: [
8981                             inputblock
8982                         ]
8983                     }
8984
8985                 ];
8986                 
8987                 labelCfg = cfg.cn[0];
8988                 contentCfg = cfg.cn[1];
8989             
8990             }
8991             
8992             if(this.labelWidth > 12){
8993                 labelCfg.style = "width: " + this.labelWidth + 'px';
8994             }
8995             
8996             if(this.labelWidth < 13 && this.labelmd == 0){
8997                 this.labelmd = this.labelWidth;
8998             }
8999             
9000             if(this.labellg > 0){
9001                 labelCfg.cls += ' col-lg-' + this.labellg;
9002                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9003             }
9004             
9005             if(this.labelmd > 0){
9006                 labelCfg.cls += ' col-md-' + this.labelmd;
9007                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9008             }
9009             
9010             if(this.labelsm > 0){
9011                 labelCfg.cls += ' col-sm-' + this.labelsm;
9012                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9013             }
9014             
9015             if(this.labelxs > 0){
9016                 labelCfg.cls += ' col-xs-' + this.labelxs;
9017                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9018             }
9019             
9020             
9021         } else if ( this.fieldLabel.length) {
9022                 
9023             cfg.cn = [
9024                 {
9025                     tag : 'i',
9026                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9027                     tooltip : 'This field is required'
9028                 },
9029                 {
9030                     tag: 'label',
9031                    //cls : 'input-group-addon',
9032                     html : this.fieldLabel
9033
9034                 },
9035
9036                inputblock
9037
9038            ];
9039            
9040            if(this.indicatorpos == 'right'){
9041                 
9042                 cfg.cn = [
9043                     {
9044                         tag: 'label',
9045                        //cls : 'input-group-addon',
9046                         html : this.fieldLabel
9047
9048                     },
9049                     {
9050                         tag : 'i',
9051                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9052                         tooltip : 'This field is required'
9053                     },
9054
9055                    inputblock
9056
9057                ];
9058
9059             }
9060
9061         } else {
9062             
9063             cfg.cn = [
9064
9065                     inputblock
9066
9067             ];
9068                 
9069                 
9070         };
9071         
9072         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9073            cfg.cls += ' navbar-form';
9074         }
9075         
9076         if (this.parentType === 'NavGroup') {
9077            cfg.cls += ' navbar-form';
9078            cfg.tag = 'li';
9079         }
9080         
9081         return cfg;
9082         
9083     },
9084     /**
9085      * return the real input element.
9086      */
9087     inputEl: function ()
9088     {
9089         return this.el.select('input.form-control',true).first();
9090     },
9091     
9092     tooltipEl : function()
9093     {
9094         return this.inputEl();
9095     },
9096     
9097     indicatorEl : function()
9098     {
9099         var indicator = this.el.select('i.roo-required-indicator',true).first();
9100         
9101         if(!indicator){
9102             return false;
9103         }
9104         
9105         return indicator;
9106         
9107     },
9108     
9109     setDisabled : function(v)
9110     {
9111         var i  = this.inputEl().dom;
9112         if (!v) {
9113             i.removeAttribute('disabled');
9114             return;
9115             
9116         }
9117         i.setAttribute('disabled','true');
9118     },
9119     initEvents : function()
9120     {
9121           
9122         this.inputEl().on("keydown" , this.fireKey,  this);
9123         this.inputEl().on("focus", this.onFocus,  this);
9124         this.inputEl().on("blur", this.onBlur,  this);
9125         
9126         this.inputEl().relayEvent('keyup', this);
9127         
9128         this.indicator = this.indicatorEl();
9129         
9130         if(this.indicator){
9131             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
9132         }
9133  
9134         // reference to original value for reset
9135         this.originalValue = this.getValue();
9136         //Roo.form.TextField.superclass.initEvents.call(this);
9137         if(this.validationEvent == 'keyup'){
9138             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9139             this.inputEl().on('keyup', this.filterValidation, this);
9140         }
9141         else if(this.validationEvent !== false){
9142             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9143         }
9144         
9145         if(this.selectOnFocus){
9146             this.on("focus", this.preFocus, this);
9147             
9148         }
9149         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9150             this.inputEl().on("keypress", this.filterKeys, this);
9151         } else {
9152             this.inputEl().relayEvent('keypress', this);
9153         }
9154        /* if(this.grow){
9155             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9156             this.el.on("click", this.autoSize,  this);
9157         }
9158         */
9159         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9160             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9161         }
9162         
9163         if (typeof(this.before) == 'object') {
9164             this.before.render(this.el.select('.roo-input-before',true).first());
9165         }
9166         if (typeof(this.after) == 'object') {
9167             this.after.render(this.el.select('.roo-input-after',true).first());
9168         }
9169         
9170         this.inputEl().on('change', this.onChange, this);
9171         
9172     },
9173     filterValidation : function(e){
9174         if(!e.isNavKeyPress()){
9175             this.validationTask.delay(this.validationDelay);
9176         }
9177     },
9178      /**
9179      * Validates the field value
9180      * @return {Boolean} True if the value is valid, else false
9181      */
9182     validate : function(){
9183         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9184         if(this.disabled || this.validateValue(this.getRawValue())){
9185             this.markValid();
9186             return true;
9187         }
9188         
9189         this.markInvalid();
9190         return false;
9191     },
9192     
9193     
9194     /**
9195      * Validates a value according to the field's validation rules and marks the field as invalid
9196      * if the validation fails
9197      * @param {Mixed} value The value to validate
9198      * @return {Boolean} True if the value is valid, else false
9199      */
9200     validateValue : function(value)
9201     {
9202         if(this.getVisibilityEl().hasClass('hidden')){
9203             return true;
9204         }
9205         
9206         if(value.length < 1)  { // if it's blank
9207             if(this.allowBlank){
9208                 return true;
9209             }
9210             return false;
9211         }
9212         
9213         if(value.length < this.minLength){
9214             return false;
9215         }
9216         if(value.length > this.maxLength){
9217             return false;
9218         }
9219         if(this.vtype){
9220             var vt = Roo.form.VTypes;
9221             if(!vt[this.vtype](value, this)){
9222                 return false;
9223             }
9224         }
9225         if(typeof this.validator == "function"){
9226             var msg = this.validator(value);
9227             if(msg !== true){
9228                 return false;
9229             }
9230             if (typeof(msg) == 'string') {
9231                 this.invalidText = msg;
9232             }
9233         }
9234         
9235         if(this.regex && !this.regex.test(value)){
9236             return false;
9237         }
9238         
9239         return true;
9240     },
9241     
9242      // private
9243     fireKey : function(e){
9244         //Roo.log('field ' + e.getKey());
9245         if(e.isNavKeyPress()){
9246             this.fireEvent("specialkey", this, e);
9247         }
9248     },
9249     focus : function (selectText){
9250         if(this.rendered){
9251             this.inputEl().focus();
9252             if(selectText === true){
9253                 this.inputEl().dom.select();
9254             }
9255         }
9256         return this;
9257     } ,
9258     
9259     onFocus : function(){
9260         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9261            // this.el.addClass(this.focusClass);
9262         }
9263         if(!this.hasFocus){
9264             this.hasFocus = true;
9265             this.startValue = this.getValue();
9266             this.fireEvent("focus", this);
9267         }
9268     },
9269     
9270     beforeBlur : Roo.emptyFn,
9271
9272     
9273     // private
9274     onBlur : function(){
9275         this.beforeBlur();
9276         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9277             //this.el.removeClass(this.focusClass);
9278         }
9279         this.hasFocus = false;
9280         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9281             this.validate();
9282         }
9283         var v = this.getValue();
9284         if(String(v) !== String(this.startValue)){
9285             this.fireEvent('change', this, v, this.startValue);
9286         }
9287         this.fireEvent("blur", this);
9288     },
9289     
9290     onChange : function(e)
9291     {
9292         var v = this.getValue();
9293         if(String(v) !== String(this.startValue)){
9294             this.fireEvent('change', this, v, this.startValue);
9295         }
9296         
9297     },
9298     
9299     /**
9300      * Resets the current field value to the originally loaded value and clears any validation messages
9301      */
9302     reset : function(){
9303         this.setValue(this.originalValue);
9304         this.validate();
9305     },
9306      /**
9307      * Returns the name of the field
9308      * @return {Mixed} name The name field
9309      */
9310     getName: function(){
9311         return this.name;
9312     },
9313      /**
9314      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9315      * @return {Mixed} value The field value
9316      */
9317     getValue : function(){
9318         
9319         var v = this.inputEl().getValue();
9320         
9321         return v;
9322     },
9323     /**
9324      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9325      * @return {Mixed} value The field value
9326      */
9327     getRawValue : function(){
9328         var v = this.inputEl().getValue();
9329         
9330         return v;
9331     },
9332     
9333     /**
9334      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9335      * @param {Mixed} value The value to set
9336      */
9337     setRawValue : function(v){
9338         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9339     },
9340     
9341     selectText : function(start, end){
9342         var v = this.getRawValue();
9343         if(v.length > 0){
9344             start = start === undefined ? 0 : start;
9345             end = end === undefined ? v.length : end;
9346             var d = this.inputEl().dom;
9347             if(d.setSelectionRange){
9348                 d.setSelectionRange(start, end);
9349             }else if(d.createTextRange){
9350                 var range = d.createTextRange();
9351                 range.moveStart("character", start);
9352                 range.moveEnd("character", v.length-end);
9353                 range.select();
9354             }
9355         }
9356     },
9357     
9358     /**
9359      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9360      * @param {Mixed} value The value to set
9361      */
9362     setValue : function(v){
9363         this.value = v;
9364         if(this.rendered){
9365             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9366             this.validate();
9367         }
9368     },
9369     
9370     /*
9371     processValue : function(value){
9372         if(this.stripCharsRe){
9373             var newValue = value.replace(this.stripCharsRe, '');
9374             if(newValue !== value){
9375                 this.setRawValue(newValue);
9376                 return newValue;
9377             }
9378         }
9379         return value;
9380     },
9381   */
9382     preFocus : function(){
9383         
9384         if(this.selectOnFocus){
9385             this.inputEl().dom.select();
9386         }
9387     },
9388     filterKeys : function(e){
9389         var k = e.getKey();
9390         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9391             return;
9392         }
9393         var c = e.getCharCode(), cc = String.fromCharCode(c);
9394         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9395             return;
9396         }
9397         if(!this.maskRe.test(cc)){
9398             e.stopEvent();
9399         }
9400     },
9401      /**
9402      * Clear any invalid styles/messages for this field
9403      */
9404     clearInvalid : function(){
9405         
9406         if(!this.el || this.preventMark){ // not rendered
9407             return;
9408         }
9409         
9410      
9411         this.el.removeClass(this.invalidClass);
9412         
9413         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9414             
9415             var feedback = this.el.select('.form-control-feedback', true).first();
9416             
9417             if(feedback){
9418                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9419             }
9420             
9421         }
9422         
9423         if(this.indicator){
9424             this.indicator.removeClass('visible');
9425             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9426         }
9427         
9428         this.fireEvent('valid', this);
9429     },
9430     
9431      /**
9432      * Mark this field as valid
9433      */
9434     markValid : function()
9435     {
9436         if(!this.el  || this.preventMark){ // not rendered...
9437             return;
9438         }
9439         
9440         this.el.removeClass([this.invalidClass, this.validClass]);
9441         
9442         var feedback = this.el.select('.form-control-feedback', true).first();
9443             
9444         if(feedback){
9445             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9446         }
9447         
9448         if(this.indicator){
9449             this.indicator.removeClass('visible');
9450             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9451         }
9452         
9453         if(this.disabled){
9454             return;
9455         }
9456         
9457         if(this.allowBlank && !this.getRawValue().length){
9458             return;
9459         }
9460         
9461         this.el.addClass(this.validClass);
9462         
9463         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9464             
9465             var feedback = this.el.select('.form-control-feedback', true).first();
9466             
9467             if(feedback){
9468                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9469                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9470             }
9471             
9472         }
9473         
9474         this.fireEvent('valid', this);
9475     },
9476     
9477      /**
9478      * Mark this field as invalid
9479      * @param {String} msg The validation message
9480      */
9481     markInvalid : function(msg)
9482     {
9483         if(!this.el  || this.preventMark){ // not rendered
9484             return;
9485         }
9486         
9487         this.el.removeClass([this.invalidClass, this.validClass]);
9488         
9489         var feedback = this.el.select('.form-control-feedback', true).first();
9490             
9491         if(feedback){
9492             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9493         }
9494
9495         if(this.disabled){
9496             return;
9497         }
9498         
9499         if(this.allowBlank && !this.getRawValue().length){
9500             return;
9501         }
9502         
9503         if(this.indicator){
9504             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9505             this.indicator.addClass('visible');
9506         }
9507         
9508         this.el.addClass(this.invalidClass);
9509         
9510         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9511             
9512             var feedback = this.el.select('.form-control-feedback', true).first();
9513             
9514             if(feedback){
9515                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9516                 
9517                 if(this.getValue().length || this.forceFeedback){
9518                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9519                 }
9520                 
9521             }
9522             
9523         }
9524         
9525         this.fireEvent('invalid', this, msg);
9526     },
9527     // private
9528     SafariOnKeyDown : function(event)
9529     {
9530         // this is a workaround for a password hang bug on chrome/ webkit.
9531         if (this.inputEl().dom.type != 'password') {
9532             return;
9533         }
9534         
9535         var isSelectAll = false;
9536         
9537         if(this.inputEl().dom.selectionEnd > 0){
9538             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9539         }
9540         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9541             event.preventDefault();
9542             this.setValue('');
9543             return;
9544         }
9545         
9546         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9547             
9548             event.preventDefault();
9549             // this is very hacky as keydown always get's upper case.
9550             //
9551             var cc = String.fromCharCode(event.getCharCode());
9552             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9553             
9554         }
9555     },
9556     adjustWidth : function(tag, w){
9557         tag = tag.toLowerCase();
9558         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9559             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9560                 if(tag == 'input'){
9561                     return w + 2;
9562                 }
9563                 if(tag == 'textarea'){
9564                     return w-2;
9565                 }
9566             }else if(Roo.isOpera){
9567                 if(tag == 'input'){
9568                     return w + 2;
9569                 }
9570                 if(tag == 'textarea'){
9571                     return w-2;
9572                 }
9573             }
9574         }
9575         return w;
9576     },
9577     
9578     setFieldLabel : function(v)
9579     {
9580         if(!this.rendered){
9581             return;
9582         }
9583         
9584         if(this.indicator){
9585             var ar = this.el.select('label > span',true);
9586             
9587             if (ar.elements.length) {
9588                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9589                 this.fieldLabel = v;
9590                 return;
9591             }
9592             
9593             var br = this.el.select('label',true);
9594             
9595             if(br.elements.length) {
9596                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9597                 this.fieldLabel = v;
9598                 return;
9599             }
9600             
9601             Roo.log('Cannot Found any of label > span || label in input');
9602             return;
9603         }
9604         
9605         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9606         this.fieldLabel = v;
9607         
9608         
9609     }
9610 });
9611
9612  
9613 /*
9614  * - LGPL
9615  *
9616  * Input
9617  * 
9618  */
9619
9620 /**
9621  * @class Roo.bootstrap.TextArea
9622  * @extends Roo.bootstrap.Input
9623  * Bootstrap TextArea class
9624  * @cfg {Number} cols Specifies the visible width of a text area
9625  * @cfg {Number} rows Specifies the visible number of lines in a text area
9626  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9627  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9628  * @cfg {string} html text
9629  * 
9630  * @constructor
9631  * Create a new TextArea
9632  * @param {Object} config The config object
9633  */
9634
9635 Roo.bootstrap.TextArea = function(config){
9636     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9637    
9638 };
9639
9640 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9641      
9642     cols : false,
9643     rows : 5,
9644     readOnly : false,
9645     warp : 'soft',
9646     resize : false,
9647     value: false,
9648     html: false,
9649     
9650     getAutoCreate : function(){
9651         
9652         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9653         
9654         var id = Roo.id();
9655         
9656         var cfg = {};
9657         
9658         if(this.inputType != 'hidden'){
9659             cfg.cls = 'form-group' //input-group
9660         }
9661         
9662         var input =  {
9663             tag: 'textarea',
9664             id : id,
9665             warp : this.warp,
9666             rows : this.rows,
9667             value : this.value || '',
9668             html: this.html || '',
9669             cls : 'form-control',
9670             placeholder : this.placeholder || '' 
9671             
9672         };
9673         
9674         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9675             input.maxLength = this.maxLength;
9676         }
9677         
9678         if(this.resize){
9679             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9680         }
9681         
9682         if(this.cols){
9683             input.cols = this.cols;
9684         }
9685         
9686         if (this.readOnly) {
9687             input.readonly = true;
9688         }
9689         
9690         if (this.name) {
9691             input.name = this.name;
9692         }
9693         
9694         if (this.size) {
9695             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9696         }
9697         
9698         var settings=this;
9699         ['xs','sm','md','lg'].map(function(size){
9700             if (settings[size]) {
9701                 cfg.cls += ' col-' + size + '-' + settings[size];
9702             }
9703         });
9704         
9705         var inputblock = input;
9706         
9707         if(this.hasFeedback && !this.allowBlank){
9708             
9709             var feedback = {
9710                 tag: 'span',
9711                 cls: 'glyphicon form-control-feedback'
9712             };
9713
9714             inputblock = {
9715                 cls : 'has-feedback',
9716                 cn :  [
9717                     input,
9718                     feedback
9719                 ] 
9720             };  
9721         }
9722         
9723         
9724         if (this.before || this.after) {
9725             
9726             inputblock = {
9727                 cls : 'input-group',
9728                 cn :  [] 
9729             };
9730             if (this.before) {
9731                 inputblock.cn.push({
9732                     tag :'span',
9733                     cls : 'input-group-addon',
9734                     html : this.before
9735                 });
9736             }
9737             
9738             inputblock.cn.push(input);
9739             
9740             if(this.hasFeedback && !this.allowBlank){
9741                 inputblock.cls += ' has-feedback';
9742                 inputblock.cn.push(feedback);
9743             }
9744             
9745             if (this.after) {
9746                 inputblock.cn.push({
9747                     tag :'span',
9748                     cls : 'input-group-addon',
9749                     html : this.after
9750                 });
9751             }
9752             
9753         }
9754         
9755         if (align ==='left' && this.fieldLabel.length) {
9756             cfg.cn = [
9757                 {
9758                     tag: 'label',
9759                     'for' :  id,
9760                     cls : 'control-label',
9761                     html : this.fieldLabel
9762                 },
9763                 {
9764                     cls : "",
9765                     cn: [
9766                         inputblock
9767                     ]
9768                 }
9769
9770             ];
9771             
9772             if(this.labelWidth > 12){
9773                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9774             }
9775
9776             if(this.labelWidth < 13 && this.labelmd == 0){
9777                 this.labelmd = this.labelWidth;
9778             }
9779
9780             if(this.labellg > 0){
9781                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9782                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9783             }
9784
9785             if(this.labelmd > 0){
9786                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9787                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9788             }
9789
9790             if(this.labelsm > 0){
9791                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9792                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9793             }
9794
9795             if(this.labelxs > 0){
9796                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9797                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9798             }
9799             
9800         } else if ( this.fieldLabel.length) {
9801             cfg.cn = [
9802
9803                {
9804                    tag: 'label',
9805                    //cls : 'input-group-addon',
9806                    html : this.fieldLabel
9807
9808                },
9809
9810                inputblock
9811
9812            ];
9813
9814         } else {
9815
9816             cfg.cn = [
9817
9818                 inputblock
9819
9820             ];
9821                 
9822         }
9823         
9824         if (this.disabled) {
9825             input.disabled=true;
9826         }
9827         
9828         return cfg;
9829         
9830     },
9831     /**
9832      * return the real textarea element.
9833      */
9834     inputEl: function ()
9835     {
9836         return this.el.select('textarea.form-control',true).first();
9837     },
9838     
9839     /**
9840      * Clear any invalid styles/messages for this field
9841      */
9842     clearInvalid : function()
9843     {
9844         
9845         if(!this.el || this.preventMark){ // not rendered
9846             return;
9847         }
9848         
9849         var label = this.el.select('label', true).first();
9850         var icon = this.el.select('i.fa-star', true).first();
9851         
9852         if(label && icon){
9853             icon.remove();
9854         }
9855         
9856         this.el.removeClass(this.invalidClass);
9857         
9858         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9859             
9860             var feedback = this.el.select('.form-control-feedback', true).first();
9861             
9862             if(feedback){
9863                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9864             }
9865             
9866         }
9867         
9868         this.fireEvent('valid', this);
9869     },
9870     
9871      /**
9872      * Mark this field as valid
9873      */
9874     markValid : function()
9875     {
9876         if(!this.el  || this.preventMark){ // not rendered
9877             return;
9878         }
9879         
9880         this.el.removeClass([this.invalidClass, this.validClass]);
9881         
9882         var feedback = this.el.select('.form-control-feedback', true).first();
9883             
9884         if(feedback){
9885             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9886         }
9887
9888         if(this.disabled || this.allowBlank){
9889             return;
9890         }
9891         
9892         var label = this.el.select('label', true).first();
9893         var icon = this.el.select('i.fa-star', true).first();
9894         
9895         if(label && icon){
9896             icon.remove();
9897         }
9898         
9899         this.el.addClass(this.validClass);
9900         
9901         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9902             
9903             var feedback = this.el.select('.form-control-feedback', true).first();
9904             
9905             if(feedback){
9906                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9907                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9908             }
9909             
9910         }
9911         
9912         this.fireEvent('valid', this);
9913     },
9914     
9915      /**
9916      * Mark this field as invalid
9917      * @param {String} msg The validation message
9918      */
9919     markInvalid : function(msg)
9920     {
9921         if(!this.el  || this.preventMark){ // not rendered
9922             return;
9923         }
9924         
9925         this.el.removeClass([this.invalidClass, this.validClass]);
9926         
9927         var feedback = this.el.select('.form-control-feedback', true).first();
9928             
9929         if(feedback){
9930             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9931         }
9932
9933         if(this.disabled || this.allowBlank){
9934             return;
9935         }
9936         
9937         var label = this.el.select('label', true).first();
9938         var icon = this.el.select('i.fa-star', true).first();
9939         
9940         if(!this.getValue().length && label && !icon){
9941             this.el.createChild({
9942                 tag : 'i',
9943                 cls : 'text-danger fa fa-lg fa-star',
9944                 tooltip : 'This field is required',
9945                 style : 'margin-right:5px;'
9946             }, label, true);
9947         }
9948
9949         this.el.addClass(this.invalidClass);
9950         
9951         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9952             
9953             var feedback = this.el.select('.form-control-feedback', true).first();
9954             
9955             if(feedback){
9956                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9957                 
9958                 if(this.getValue().length || this.forceFeedback){
9959                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9960                 }
9961                 
9962             }
9963             
9964         }
9965         
9966         this.fireEvent('invalid', this, msg);
9967     }
9968 });
9969
9970  
9971 /*
9972  * - LGPL
9973  *
9974  * trigger field - base class for combo..
9975  * 
9976  */
9977  
9978 /**
9979  * @class Roo.bootstrap.TriggerField
9980  * @extends Roo.bootstrap.Input
9981  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9982  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9983  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9984  * for which you can provide a custom implementation.  For example:
9985  * <pre><code>
9986 var trigger = new Roo.bootstrap.TriggerField();
9987 trigger.onTriggerClick = myTriggerFn;
9988 trigger.applyTo('my-field');
9989 </code></pre>
9990  *
9991  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9992  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9993  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9994  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9995  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9996
9997  * @constructor
9998  * Create a new TriggerField.
9999  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10000  * to the base TextField)
10001  */
10002 Roo.bootstrap.TriggerField = function(config){
10003     this.mimicing = false;
10004     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10005 };
10006
10007 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
10008     /**
10009      * @cfg {String} triggerClass A CSS class to apply to the trigger
10010      */
10011      /**
10012      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10013      */
10014     hideTrigger:false,
10015
10016     /**
10017      * @cfg {Boolean} removable (true|false) special filter default false
10018      */
10019     removable : false,
10020     
10021     /** @cfg {Boolean} grow @hide */
10022     /** @cfg {Number} growMin @hide */
10023     /** @cfg {Number} growMax @hide */
10024
10025     /**
10026      * @hide 
10027      * @method
10028      */
10029     autoSize: Roo.emptyFn,
10030     // private
10031     monitorTab : true,
10032     // private
10033     deferHeight : true,
10034
10035     
10036     actionMode : 'wrap',
10037     
10038     caret : false,
10039     
10040     
10041     getAutoCreate : function(){
10042        
10043         var align = this.labelAlign || this.parentLabelAlign();
10044         
10045         var id = Roo.id();
10046         
10047         var cfg = {
10048             cls: 'form-group' //input-group
10049         };
10050         
10051         
10052         var input =  {
10053             tag: 'input',
10054             id : id,
10055             type : this.inputType,
10056             cls : 'form-control',
10057             autocomplete: 'new-password',
10058             placeholder : this.placeholder || '' 
10059             
10060         };
10061         if (this.name) {
10062             input.name = this.name;
10063         }
10064         if (this.size) {
10065             input.cls += ' input-' + this.size;
10066         }
10067         
10068         if (this.disabled) {
10069             input.disabled=true;
10070         }
10071         
10072         var inputblock = input;
10073         
10074         if(this.hasFeedback && !this.allowBlank){
10075             
10076             var feedback = {
10077                 tag: 'span',
10078                 cls: 'glyphicon form-control-feedback'
10079             };
10080             
10081             if(this.removable && !this.editable && !this.tickable){
10082                 inputblock = {
10083                     cls : 'has-feedback',
10084                     cn :  [
10085                         inputblock,
10086                         {
10087                             tag: 'button',
10088                             html : 'x',
10089                             cls : 'roo-combo-removable-btn close'
10090                         },
10091                         feedback
10092                     ] 
10093                 };
10094             } else {
10095                 inputblock = {
10096                     cls : 'has-feedback',
10097                     cn :  [
10098                         inputblock,
10099                         feedback
10100                     ] 
10101                 };
10102             }
10103
10104         } else {
10105             if(this.removable && !this.editable && !this.tickable){
10106                 inputblock = {
10107                     cls : 'roo-removable',
10108                     cn :  [
10109                         inputblock,
10110                         {
10111                             tag: 'button',
10112                             html : 'x',
10113                             cls : 'roo-combo-removable-btn close'
10114                         }
10115                     ] 
10116                 };
10117             }
10118         }
10119         
10120         if (this.before || this.after) {
10121             
10122             inputblock = {
10123                 cls : 'input-group',
10124                 cn :  [] 
10125             };
10126             if (this.before) {
10127                 inputblock.cn.push({
10128                     tag :'span',
10129                     cls : 'input-group-addon',
10130                     html : this.before
10131                 });
10132             }
10133             
10134             inputblock.cn.push(input);
10135             
10136             if(this.hasFeedback && !this.allowBlank){
10137                 inputblock.cls += ' has-feedback';
10138                 inputblock.cn.push(feedback);
10139             }
10140             
10141             if (this.after) {
10142                 inputblock.cn.push({
10143                     tag :'span',
10144                     cls : 'input-group-addon',
10145                     html : this.after
10146                 });
10147             }
10148             
10149         };
10150         
10151         var box = {
10152             tag: 'div',
10153             cn: [
10154                 {
10155                     tag: 'input',
10156                     type : 'hidden',
10157                     cls: 'form-hidden-field'
10158                 },
10159                 inputblock
10160             ]
10161             
10162         };
10163         
10164         if(this.multiple){
10165             box = {
10166                 tag: 'div',
10167                 cn: [
10168                     {
10169                         tag: 'input',
10170                         type : 'hidden',
10171                         cls: 'form-hidden-field'
10172                     },
10173                     {
10174                         tag: 'ul',
10175                         cls: 'roo-select2-choices',
10176                         cn:[
10177                             {
10178                                 tag: 'li',
10179                                 cls: 'roo-select2-search-field',
10180                                 cn: [
10181
10182                                     inputblock
10183                                 ]
10184                             }
10185                         ]
10186                     }
10187                 ]
10188             }
10189         };
10190         
10191         var combobox = {
10192             cls: 'roo-select2-container input-group',
10193             cn: [
10194                 box
10195 //                {
10196 //                    tag: 'ul',
10197 //                    cls: 'typeahead typeahead-long dropdown-menu',
10198 //                    style: 'display:none'
10199 //                }
10200             ]
10201         };
10202         
10203         if(!this.multiple && this.showToggleBtn){
10204             
10205             var caret = {
10206                         tag: 'span',
10207                         cls: 'caret'
10208              };
10209             if (this.caret != false) {
10210                 caret = {
10211                      tag: 'i',
10212                      cls: 'fa fa-' + this.caret
10213                 };
10214                 
10215             }
10216             
10217             combobox.cn.push({
10218                 tag :'span',
10219                 cls : 'input-group-addon btn dropdown-toggle',
10220                 cn : [
10221                     caret,
10222                     {
10223                         tag: 'span',
10224                         cls: 'combobox-clear',
10225                         cn  : [
10226                             {
10227                                 tag : 'i',
10228                                 cls: 'icon-remove'
10229                             }
10230                         ]
10231                     }
10232                 ]
10233
10234             })
10235         }
10236         
10237         if(this.multiple){
10238             combobox.cls += ' roo-select2-container-multi';
10239         }
10240         
10241         if (align ==='left' && this.fieldLabel.length) {
10242             
10243             cfg.cls += ' roo-form-group-label-left';
10244
10245             cfg.cn = [
10246                 {
10247                     tag : 'i',
10248                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10249                     tooltip : 'This field is required'
10250                 },
10251                 {
10252                     tag: 'label',
10253                     'for' :  id,
10254                     cls : 'control-label',
10255                     html : this.fieldLabel
10256
10257                 },
10258                 {
10259                     cls : "", 
10260                     cn: [
10261                         combobox
10262                     ]
10263                 }
10264
10265             ];
10266             
10267             var labelCfg = cfg.cn[1];
10268             var contentCfg = cfg.cn[2];
10269             
10270             if(this.indicatorpos == 'right'){
10271                 cfg.cn = [
10272                     {
10273                         tag: 'label',
10274                         'for' :  id,
10275                         cls : 'control-label',
10276                         cn : [
10277                             {
10278                                 tag : 'span',
10279                                 html : this.fieldLabel
10280                             },
10281                             {
10282                                 tag : 'i',
10283                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10284                                 tooltip : 'This field is required'
10285                             }
10286                         ]
10287                     },
10288                     {
10289                         cls : "", 
10290                         cn: [
10291                             combobox
10292                         ]
10293                     }
10294
10295                 ];
10296                 
10297                 labelCfg = cfg.cn[0];
10298                 contentCfg = cfg.cn[1];
10299             }
10300             
10301             if(this.labelWidth > 12){
10302                 labelCfg.style = "width: " + this.labelWidth + 'px';
10303             }
10304             
10305             if(this.labelWidth < 13 && this.labelmd == 0){
10306                 this.labelmd = this.labelWidth;
10307             }
10308             
10309             if(this.labellg > 0){
10310                 labelCfg.cls += ' col-lg-' + this.labellg;
10311                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10312             }
10313             
10314             if(this.labelmd > 0){
10315                 labelCfg.cls += ' col-md-' + this.labelmd;
10316                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10317             }
10318             
10319             if(this.labelsm > 0){
10320                 labelCfg.cls += ' col-sm-' + this.labelsm;
10321                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10322             }
10323             
10324             if(this.labelxs > 0){
10325                 labelCfg.cls += ' col-xs-' + this.labelxs;
10326                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10327             }
10328             
10329         } else if ( this.fieldLabel.length) {
10330 //                Roo.log(" label");
10331             cfg.cn = [
10332                 {
10333                    tag : 'i',
10334                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10335                    tooltip : 'This field is required'
10336                },
10337                {
10338                    tag: 'label',
10339                    //cls : 'input-group-addon',
10340                    html : this.fieldLabel
10341
10342                },
10343
10344                combobox
10345
10346             ];
10347             
10348             if(this.indicatorpos == 'right'){
10349                 
10350                 cfg.cn = [
10351                     {
10352                        tag: 'label',
10353                        cn : [
10354                            {
10355                                tag : 'span',
10356                                html : this.fieldLabel
10357                            },
10358                            {
10359                               tag : 'i',
10360                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10361                               tooltip : 'This field is required'
10362                            }
10363                        ]
10364
10365                     },
10366                     combobox
10367
10368                 ];
10369
10370             }
10371
10372         } else {
10373             
10374 //                Roo.log(" no label && no align");
10375                 cfg = combobox
10376                      
10377                 
10378         }
10379         
10380         var settings=this;
10381         ['xs','sm','md','lg'].map(function(size){
10382             if (settings[size]) {
10383                 cfg.cls += ' col-' + size + '-' + settings[size];
10384             }
10385         });
10386         
10387         return cfg;
10388         
10389     },
10390     
10391     
10392     
10393     // private
10394     onResize : function(w, h){
10395 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10396 //        if(typeof w == 'number'){
10397 //            var x = w - this.trigger.getWidth();
10398 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10399 //            this.trigger.setStyle('left', x+'px');
10400 //        }
10401     },
10402
10403     // private
10404     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10405
10406     // private
10407     getResizeEl : function(){
10408         return this.inputEl();
10409     },
10410
10411     // private
10412     getPositionEl : function(){
10413         return this.inputEl();
10414     },
10415
10416     // private
10417     alignErrorIcon : function(){
10418         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10419     },
10420
10421     // private
10422     initEvents : function(){
10423         
10424         this.createList();
10425         
10426         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10427         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10428         if(!this.multiple && this.showToggleBtn){
10429             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10430             if(this.hideTrigger){
10431                 this.trigger.setDisplayed(false);
10432             }
10433             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10434         }
10435         
10436         if(this.multiple){
10437             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10438         }
10439         
10440         if(this.removable && !this.editable && !this.tickable){
10441             var close = this.closeTriggerEl();
10442             
10443             if(close){
10444                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10445                 close.on('click', this.removeBtnClick, this, close);
10446             }
10447         }
10448         
10449         //this.trigger.addClassOnOver('x-form-trigger-over');
10450         //this.trigger.addClassOnClick('x-form-trigger-click');
10451         
10452         //if(!this.width){
10453         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10454         //}
10455     },
10456     
10457     closeTriggerEl : function()
10458     {
10459         var close = this.el.select('.roo-combo-removable-btn', true).first();
10460         return close ? close : false;
10461     },
10462     
10463     removeBtnClick : function(e, h, el)
10464     {
10465         e.preventDefault();
10466         
10467         if(this.fireEvent("remove", this) !== false){
10468             this.reset();
10469             this.fireEvent("afterremove", this)
10470         }
10471     },
10472     
10473     createList : function()
10474     {
10475         this.list = Roo.get(document.body).createChild({
10476             tag: 'ul',
10477             cls: 'typeahead typeahead-long dropdown-menu',
10478             style: 'display:none'
10479         });
10480         
10481         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10482         
10483     },
10484
10485     // private
10486     initTrigger : function(){
10487        
10488     },
10489
10490     // private
10491     onDestroy : function(){
10492         if(this.trigger){
10493             this.trigger.removeAllListeners();
10494           //  this.trigger.remove();
10495         }
10496         //if(this.wrap){
10497         //    this.wrap.remove();
10498         //}
10499         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10500     },
10501
10502     // private
10503     onFocus : function(){
10504         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10505         /*
10506         if(!this.mimicing){
10507             this.wrap.addClass('x-trigger-wrap-focus');
10508             this.mimicing = true;
10509             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10510             if(this.monitorTab){
10511                 this.el.on("keydown", this.checkTab, this);
10512             }
10513         }
10514         */
10515     },
10516
10517     // private
10518     checkTab : function(e){
10519         if(e.getKey() == e.TAB){
10520             this.triggerBlur();
10521         }
10522     },
10523
10524     // private
10525     onBlur : function(){
10526         // do nothing
10527     },
10528
10529     // private
10530     mimicBlur : function(e, t){
10531         /*
10532         if(!this.wrap.contains(t) && this.validateBlur()){
10533             this.triggerBlur();
10534         }
10535         */
10536     },
10537
10538     // private
10539     triggerBlur : function(){
10540         this.mimicing = false;
10541         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10542         if(this.monitorTab){
10543             this.el.un("keydown", this.checkTab, this);
10544         }
10545         //this.wrap.removeClass('x-trigger-wrap-focus');
10546         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10547     },
10548
10549     // private
10550     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10551     validateBlur : function(e, t){
10552         return true;
10553     },
10554
10555     // private
10556     onDisable : function(){
10557         this.inputEl().dom.disabled = true;
10558         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10559         //if(this.wrap){
10560         //    this.wrap.addClass('x-item-disabled');
10561         //}
10562     },
10563
10564     // private
10565     onEnable : function(){
10566         this.inputEl().dom.disabled = false;
10567         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10568         //if(this.wrap){
10569         //    this.el.removeClass('x-item-disabled');
10570         //}
10571     },
10572
10573     // private
10574     onShow : function(){
10575         var ae = this.getActionEl();
10576         
10577         if(ae){
10578             ae.dom.style.display = '';
10579             ae.dom.style.visibility = 'visible';
10580         }
10581     },
10582
10583     // private
10584     
10585     onHide : function(){
10586         var ae = this.getActionEl();
10587         ae.dom.style.display = 'none';
10588     },
10589
10590     /**
10591      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10592      * by an implementing function.
10593      * @method
10594      * @param {EventObject} e
10595      */
10596     onTriggerClick : Roo.emptyFn
10597 });
10598  /*
10599  * Based on:
10600  * Ext JS Library 1.1.1
10601  * Copyright(c) 2006-2007, Ext JS, LLC.
10602  *
10603  * Originally Released Under LGPL - original licence link has changed is not relivant.
10604  *
10605  * Fork - LGPL
10606  * <script type="text/javascript">
10607  */
10608
10609
10610 /**
10611  * @class Roo.data.SortTypes
10612  * @singleton
10613  * Defines the default sorting (casting?) comparison functions used when sorting data.
10614  */
10615 Roo.data.SortTypes = {
10616     /**
10617      * Default sort that does nothing
10618      * @param {Mixed} s The value being converted
10619      * @return {Mixed} The comparison value
10620      */
10621     none : function(s){
10622         return s;
10623     },
10624     
10625     /**
10626      * The regular expression used to strip tags
10627      * @type {RegExp}
10628      * @property
10629      */
10630     stripTagsRE : /<\/?[^>]+>/gi,
10631     
10632     /**
10633      * Strips all HTML tags to sort on text only
10634      * @param {Mixed} s The value being converted
10635      * @return {String} The comparison value
10636      */
10637     asText : function(s){
10638         return String(s).replace(this.stripTagsRE, "");
10639     },
10640     
10641     /**
10642      * Strips all HTML tags to sort on text only - Case insensitive
10643      * @param {Mixed} s The value being converted
10644      * @return {String} The comparison value
10645      */
10646     asUCText : function(s){
10647         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10648     },
10649     
10650     /**
10651      * Case insensitive string
10652      * @param {Mixed} s The value being converted
10653      * @return {String} The comparison value
10654      */
10655     asUCString : function(s) {
10656         return String(s).toUpperCase();
10657     },
10658     
10659     /**
10660      * Date sorting
10661      * @param {Mixed} s The value being converted
10662      * @return {Number} The comparison value
10663      */
10664     asDate : function(s) {
10665         if(!s){
10666             return 0;
10667         }
10668         if(s instanceof Date){
10669             return s.getTime();
10670         }
10671         return Date.parse(String(s));
10672     },
10673     
10674     /**
10675      * Float sorting
10676      * @param {Mixed} s The value being converted
10677      * @return {Float} The comparison value
10678      */
10679     asFloat : function(s) {
10680         var val = parseFloat(String(s).replace(/,/g, ""));
10681         if(isNaN(val)) {
10682             val = 0;
10683         }
10684         return val;
10685     },
10686     
10687     /**
10688      * Integer sorting
10689      * @param {Mixed} s The value being converted
10690      * @return {Number} The comparison value
10691      */
10692     asInt : function(s) {
10693         var val = parseInt(String(s).replace(/,/g, ""));
10694         if(isNaN(val)) {
10695             val = 0;
10696         }
10697         return val;
10698     }
10699 };/*
10700  * Based on:
10701  * Ext JS Library 1.1.1
10702  * Copyright(c) 2006-2007, Ext JS, LLC.
10703  *
10704  * Originally Released Under LGPL - original licence link has changed is not relivant.
10705  *
10706  * Fork - LGPL
10707  * <script type="text/javascript">
10708  */
10709
10710 /**
10711 * @class Roo.data.Record
10712  * Instances of this class encapsulate both record <em>definition</em> information, and record
10713  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10714  * to access Records cached in an {@link Roo.data.Store} object.<br>
10715  * <p>
10716  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10717  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10718  * objects.<br>
10719  * <p>
10720  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10721  * @constructor
10722  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10723  * {@link #create}. The parameters are the same.
10724  * @param {Array} data An associative Array of data values keyed by the field name.
10725  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10726  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10727  * not specified an integer id is generated.
10728  */
10729 Roo.data.Record = function(data, id){
10730     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10731     this.data = data;
10732 };
10733
10734 /**
10735  * Generate a constructor for a specific record layout.
10736  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10737  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10738  * Each field definition object may contain the following properties: <ul>
10739  * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
10740  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10741  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10742  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10743  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10744  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10745  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10746  * this may be omitted.</p></li>
10747  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10748  * <ul><li>auto (Default, implies no conversion)</li>
10749  * <li>string</li>
10750  * <li>int</li>
10751  * <li>float</li>
10752  * <li>boolean</li>
10753  * <li>date</li></ul></p></li>
10754  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10755  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10756  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10757  * by the Reader into an object that will be stored in the Record. It is passed the
10758  * following parameters:<ul>
10759  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10760  * </ul></p></li>
10761  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10762  * </ul>
10763  * <br>usage:<br><pre><code>
10764 var TopicRecord = Roo.data.Record.create(
10765     {name: 'title', mapping: 'topic_title'},
10766     {name: 'author', mapping: 'username'},
10767     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10768     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10769     {name: 'lastPoster', mapping: 'user2'},
10770     {name: 'excerpt', mapping: 'post_text'}
10771 );
10772
10773 var myNewRecord = new TopicRecord({
10774     title: 'Do my job please',
10775     author: 'noobie',
10776     totalPosts: 1,
10777     lastPost: new Date(),
10778     lastPoster: 'Animal',
10779     excerpt: 'No way dude!'
10780 });
10781 myStore.add(myNewRecord);
10782 </code></pre>
10783  * @method create
10784  * @static
10785  */
10786 Roo.data.Record.create = function(o){
10787     var f = function(){
10788         f.superclass.constructor.apply(this, arguments);
10789     };
10790     Roo.extend(f, Roo.data.Record);
10791     var p = f.prototype;
10792     p.fields = new Roo.util.MixedCollection(false, function(field){
10793         return field.name;
10794     });
10795     for(var i = 0, len = o.length; i < len; i++){
10796         p.fields.add(new Roo.data.Field(o[i]));
10797     }
10798     f.getField = function(name){
10799         return p.fields.get(name);  
10800     };
10801     return f;
10802 };
10803
10804 Roo.data.Record.AUTO_ID = 1000;
10805 Roo.data.Record.EDIT = 'edit';
10806 Roo.data.Record.REJECT = 'reject';
10807 Roo.data.Record.COMMIT = 'commit';
10808
10809 Roo.data.Record.prototype = {
10810     /**
10811      * Readonly flag - true if this record has been modified.
10812      * @type Boolean
10813      */
10814     dirty : false,
10815     editing : false,
10816     error: null,
10817     modified: null,
10818
10819     // private
10820     join : function(store){
10821         this.store = store;
10822     },
10823
10824     /**
10825      * Set the named field to the specified value.
10826      * @param {String} name The name of the field to set.
10827      * @param {Object} value The value to set the field to.
10828      */
10829     set : function(name, value){
10830         if(this.data[name] == value){
10831             return;
10832         }
10833         this.dirty = true;
10834         if(!this.modified){
10835             this.modified = {};
10836         }
10837         if(typeof this.modified[name] == 'undefined'){
10838             this.modified[name] = this.data[name];
10839         }
10840         this.data[name] = value;
10841         if(!this.editing && this.store){
10842             this.store.afterEdit(this);
10843         }       
10844     },
10845
10846     /**
10847      * Get the value of the named field.
10848      * @param {String} name The name of the field to get the value of.
10849      * @return {Object} The value of the field.
10850      */
10851     get : function(name){
10852         return this.data[name]; 
10853     },
10854
10855     // private
10856     beginEdit : function(){
10857         this.editing = true;
10858         this.modified = {}; 
10859     },
10860
10861     // private
10862     cancelEdit : function(){
10863         this.editing = false;
10864         delete this.modified;
10865     },
10866
10867     // private
10868     endEdit : function(){
10869         this.editing = false;
10870         if(this.dirty && this.store){
10871             this.store.afterEdit(this);
10872         }
10873     },
10874
10875     /**
10876      * Usually called by the {@link Roo.data.Store} which owns the Record.
10877      * Rejects all changes made to the Record since either creation, or the last commit operation.
10878      * Modified fields are reverted to their original values.
10879      * <p>
10880      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10881      * of reject operations.
10882      */
10883     reject : function(){
10884         var m = this.modified;
10885         for(var n in m){
10886             if(typeof m[n] != "function"){
10887                 this.data[n] = m[n];
10888             }
10889         }
10890         this.dirty = false;
10891         delete this.modified;
10892         this.editing = false;
10893         if(this.store){
10894             this.store.afterReject(this);
10895         }
10896     },
10897
10898     /**
10899      * Usually called by the {@link Roo.data.Store} which owns the Record.
10900      * Commits all changes made to the Record since either creation, or the last commit operation.
10901      * <p>
10902      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10903      * of commit operations.
10904      */
10905     commit : function(){
10906         this.dirty = false;
10907         delete this.modified;
10908         this.editing = false;
10909         if(this.store){
10910             this.store.afterCommit(this);
10911         }
10912     },
10913
10914     // private
10915     hasError : function(){
10916         return this.error != null;
10917     },
10918
10919     // private
10920     clearError : function(){
10921         this.error = null;
10922     },
10923
10924     /**
10925      * Creates a copy of this record.
10926      * @param {String} id (optional) A new record id if you don't want to use this record's id
10927      * @return {Record}
10928      */
10929     copy : function(newId) {
10930         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10931     }
10932 };/*
10933  * Based on:
10934  * Ext JS Library 1.1.1
10935  * Copyright(c) 2006-2007, Ext JS, LLC.
10936  *
10937  * Originally Released Under LGPL - original licence link has changed is not relivant.
10938  *
10939  * Fork - LGPL
10940  * <script type="text/javascript">
10941  */
10942
10943
10944
10945 /**
10946  * @class Roo.data.Store
10947  * @extends Roo.util.Observable
10948  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10949  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10950  * <p>
10951  * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
10952  * has no knowledge of the format of the data returned by the Proxy.<br>
10953  * <p>
10954  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10955  * instances from the data object. These records are cached and made available through accessor functions.
10956  * @constructor
10957  * Creates a new Store.
10958  * @param {Object} config A config object containing the objects needed for the Store to access data,
10959  * and read the data into Records.
10960  */
10961 Roo.data.Store = function(config){
10962     this.data = new Roo.util.MixedCollection(false);
10963     this.data.getKey = function(o){
10964         return o.id;
10965     };
10966     this.baseParams = {};
10967     // private
10968     this.paramNames = {
10969         "start" : "start",
10970         "limit" : "limit",
10971         "sort" : "sort",
10972         "dir" : "dir",
10973         "multisort" : "_multisort"
10974     };
10975
10976     if(config && config.data){
10977         this.inlineData = config.data;
10978         delete config.data;
10979     }
10980
10981     Roo.apply(this, config);
10982     
10983     if(this.reader){ // reader passed
10984         this.reader = Roo.factory(this.reader, Roo.data);
10985         this.reader.xmodule = this.xmodule || false;
10986         if(!this.recordType){
10987             this.recordType = this.reader.recordType;
10988         }
10989         if(this.reader.onMetaChange){
10990             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10991         }
10992     }
10993
10994     if(this.recordType){
10995         this.fields = this.recordType.prototype.fields;
10996     }
10997     this.modified = [];
10998
10999     this.addEvents({
11000         /**
11001          * @event datachanged
11002          * Fires when the data cache has changed, and a widget which is using this Store
11003          * as a Record cache should refresh its view.
11004          * @param {Store} this
11005          */
11006         datachanged : true,
11007         /**
11008          * @event metachange
11009          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11010          * @param {Store} this
11011          * @param {Object} meta The JSON metadata
11012          */
11013         metachange : true,
11014         /**
11015          * @event add
11016          * Fires when Records have been added to the Store
11017          * @param {Store} this
11018          * @param {Roo.data.Record[]} records The array of Records added
11019          * @param {Number} index The index at which the record(s) were added
11020          */
11021         add : true,
11022         /**
11023          * @event remove
11024          * Fires when a Record has been removed from the Store
11025          * @param {Store} this
11026          * @param {Roo.data.Record} record The Record that was removed
11027          * @param {Number} index The index at which the record was removed
11028          */
11029         remove : true,
11030         /**
11031          * @event update
11032          * Fires when a Record has been updated
11033          * @param {Store} this
11034          * @param {Roo.data.Record} record The Record that was updated
11035          * @param {String} operation The update operation being performed.  Value may be one of:
11036          * <pre><code>
11037  Roo.data.Record.EDIT
11038  Roo.data.Record.REJECT
11039  Roo.data.Record.COMMIT
11040          * </code></pre>
11041          */
11042         update : true,
11043         /**
11044          * @event clear
11045          * Fires when the data cache has been cleared.
11046          * @param {Store} this
11047          */
11048         clear : true,
11049         /**
11050          * @event beforeload
11051          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11052          * the load action will be canceled.
11053          * @param {Store} this
11054          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11055          */
11056         beforeload : true,
11057         /**
11058          * @event beforeloadadd
11059          * Fires after a new set of Records has been loaded.
11060          * @param {Store} this
11061          * @param {Roo.data.Record[]} records The Records that were loaded
11062          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11063          */
11064         beforeloadadd : true,
11065         /**
11066          * @event load
11067          * Fires after a new set of Records has been loaded, before they are added to the store.
11068          * @param {Store} this
11069          * @param {Roo.data.Record[]} records The Records that were loaded
11070          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11071          * @params {Object} return from reader
11072          */
11073         load : true,
11074         /**
11075          * @event loadexception
11076          * Fires if an exception occurs in the Proxy during loading.
11077          * Called with the signature of the Proxy's "loadexception" event.
11078          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11079          * 
11080          * @param {Proxy} 
11081          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11082          * @param {Object} load options 
11083          * @param {Object} jsonData from your request (normally this contains the Exception)
11084          */
11085         loadexception : true
11086     });
11087     
11088     if(this.proxy){
11089         this.proxy = Roo.factory(this.proxy, Roo.data);
11090         this.proxy.xmodule = this.xmodule || false;
11091         this.relayEvents(this.proxy,  ["loadexception"]);
11092     }
11093     this.sortToggle = {};
11094     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11095
11096     Roo.data.Store.superclass.constructor.call(this);
11097
11098     if(this.inlineData){
11099         this.loadData(this.inlineData);
11100         delete this.inlineData;
11101     }
11102 };
11103
11104 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11105      /**
11106     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11107     * without a remote query - used by combo/forms at present.
11108     */
11109     
11110     /**
11111     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11112     */
11113     /**
11114     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11115     */
11116     /**
11117     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11118     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11119     */
11120     /**
11121     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11122     * on any HTTP request
11123     */
11124     /**
11125     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11126     */
11127     /**
11128     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11129     */
11130     multiSort: false,
11131     /**
11132     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11133     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11134     */
11135     remoteSort : false,
11136
11137     /**
11138     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11139      * loaded or when a record is removed. (defaults to false).
11140     */
11141     pruneModifiedRecords : false,
11142
11143     // private
11144     lastOptions : null,
11145
11146     /**
11147      * Add Records to the Store and fires the add event.
11148      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11149      */
11150     add : function(records){
11151         records = [].concat(records);
11152         for(var i = 0, len = records.length; i < len; i++){
11153             records[i].join(this);
11154         }
11155         var index = this.data.length;
11156         this.data.addAll(records);
11157         this.fireEvent("add", this, records, index);
11158     },
11159
11160     /**
11161      * Remove a Record from the Store and fires the remove event.
11162      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11163      */
11164     remove : function(record){
11165         var index = this.data.indexOf(record);
11166         this.data.removeAt(index);
11167  
11168         if(this.pruneModifiedRecords){
11169             this.modified.remove(record);
11170         }
11171         this.fireEvent("remove", this, record, index);
11172     },
11173
11174     /**
11175      * Remove all Records from the Store and fires the clear event.
11176      */
11177     removeAll : function(){
11178         this.data.clear();
11179         if(this.pruneModifiedRecords){
11180             this.modified = [];
11181         }
11182         this.fireEvent("clear", this);
11183     },
11184
11185     /**
11186      * Inserts Records to the Store at the given index and fires the add event.
11187      * @param {Number} index The start index at which to insert the passed Records.
11188      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11189      */
11190     insert : function(index, records){
11191         records = [].concat(records);
11192         for(var i = 0, len = records.length; i < len; i++){
11193             this.data.insert(index, records[i]);
11194             records[i].join(this);
11195         }
11196         this.fireEvent("add", this, records, index);
11197     },
11198
11199     /**
11200      * Get the index within the cache of the passed Record.
11201      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11202      * @return {Number} The index of the passed Record. Returns -1 if not found.
11203      */
11204     indexOf : function(record){
11205         return this.data.indexOf(record);
11206     },
11207
11208     /**
11209      * Get the index within the cache of the Record with the passed id.
11210      * @param {String} id The id of the Record to find.
11211      * @return {Number} The index of the Record. Returns -1 if not found.
11212      */
11213     indexOfId : function(id){
11214         return this.data.indexOfKey(id);
11215     },
11216
11217     /**
11218      * Get the Record with the specified id.
11219      * @param {String} id The id of the Record to find.
11220      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11221      */
11222     getById : function(id){
11223         return this.data.key(id);
11224     },
11225
11226     /**
11227      * Get the Record at the specified index.
11228      * @param {Number} index The index of the Record to find.
11229      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11230      */
11231     getAt : function(index){
11232         return this.data.itemAt(index);
11233     },
11234
11235     /**
11236      * Returns a range of Records between specified indices.
11237      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11238      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11239      * @return {Roo.data.Record[]} An array of Records
11240      */
11241     getRange : function(start, end){
11242         return this.data.getRange(start, end);
11243     },
11244
11245     // private
11246     storeOptions : function(o){
11247         o = Roo.apply({}, o);
11248         delete o.callback;
11249         delete o.scope;
11250         this.lastOptions = o;
11251     },
11252
11253     /**
11254      * Loads the Record cache from the configured Proxy using the configured Reader.
11255      * <p>
11256      * If using remote paging, then the first load call must specify the <em>start</em>
11257      * and <em>limit</em> properties in the options.params property to establish the initial
11258      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11259      * <p>
11260      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11261      * and this call will return before the new data has been loaded. Perform any post-processing
11262      * in a callback function, or in a "load" event handler.</strong>
11263      * <p>
11264      * @param {Object} options An object containing properties which control loading options:<ul>
11265      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11266      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11267      * passed the following arguments:<ul>
11268      * <li>r : Roo.data.Record[]</li>
11269      * <li>options: Options object from the load call</li>
11270      * <li>success: Boolean success indicator</li></ul></li>
11271      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11272      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11273      * </ul>
11274      */
11275     load : function(options){
11276         options = options || {};
11277         if(this.fireEvent("beforeload", this, options) !== false){
11278             this.storeOptions(options);
11279             var p = Roo.apply(options.params || {}, this.baseParams);
11280             // if meta was not loaded from remote source.. try requesting it.
11281             if (!this.reader.metaFromRemote) {
11282                 p._requestMeta = 1;
11283             }
11284             if(this.sortInfo && this.remoteSort){
11285                 var pn = this.paramNames;
11286                 p[pn["sort"]] = this.sortInfo.field;
11287                 p[pn["dir"]] = this.sortInfo.direction;
11288             }
11289             if (this.multiSort) {
11290                 var pn = this.paramNames;
11291                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11292             }
11293             
11294             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11295         }
11296     },
11297
11298     /**
11299      * Reloads the Record cache from the configured Proxy using the configured Reader and
11300      * the options from the last load operation performed.
11301      * @param {Object} options (optional) An object containing properties which may override the options
11302      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11303      * the most recently used options are reused).
11304      */
11305     reload : function(options){
11306         this.load(Roo.applyIf(options||{}, this.lastOptions));
11307     },
11308
11309     // private
11310     // Called as a callback by the Reader during a load operation.
11311     loadRecords : function(o, options, success){
11312         if(!o || success === false){
11313             if(success !== false){
11314                 this.fireEvent("load", this, [], options, o);
11315             }
11316             if(options.callback){
11317                 options.callback.call(options.scope || this, [], options, false);
11318             }
11319             return;
11320         }
11321         // if data returned failure - throw an exception.
11322         if (o.success === false) {
11323             // show a message if no listener is registered.
11324             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11325                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11326             }
11327             // loadmask wil be hooked into this..
11328             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11329             return;
11330         }
11331         var r = o.records, t = o.totalRecords || r.length;
11332         
11333         this.fireEvent("beforeloadadd", this, r, options, o);
11334         
11335         if(!options || options.add !== true){
11336             if(this.pruneModifiedRecords){
11337                 this.modified = [];
11338             }
11339             for(var i = 0, len = r.length; i < len; i++){
11340                 r[i].join(this);
11341             }
11342             if(this.snapshot){
11343                 this.data = this.snapshot;
11344                 delete this.snapshot;
11345             }
11346             this.data.clear();
11347             this.data.addAll(r);
11348             this.totalLength = t;
11349             this.applySort();
11350             this.fireEvent("datachanged", this);
11351         }else{
11352             this.totalLength = Math.max(t, this.data.length+r.length);
11353             this.add(r);
11354         }
11355         
11356         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11357                 
11358             var e = new Roo.data.Record({});
11359
11360             e.set(this.parent.displayField, this.parent.emptyTitle);
11361             e.set(this.parent.valueField, '');
11362
11363             this.insert(0, e);
11364         }
11365             
11366         this.fireEvent("load", this, r, options, o);
11367         if(options.callback){
11368             options.callback.call(options.scope || this, r, options, true);
11369         }
11370     },
11371
11372
11373     /**
11374      * Loads data from a passed data block. A Reader which understands the format of the data
11375      * must have been configured in the constructor.
11376      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11377      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11378      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11379      */
11380     loadData : function(o, append){
11381         var r = this.reader.readRecords(o);
11382         this.loadRecords(r, {add: append}, true);
11383     },
11384
11385     /**
11386      * Gets the number of cached records.
11387      * <p>
11388      * <em>If using paging, this may not be the total size of the dataset. If the data object
11389      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11390      * the data set size</em>
11391      */
11392     getCount : function(){
11393         return this.data.length || 0;
11394     },
11395
11396     /**
11397      * Gets the total number of records in the dataset as returned by the server.
11398      * <p>
11399      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11400      * the dataset size</em>
11401      */
11402     getTotalCount : function(){
11403         return this.totalLength || 0;
11404     },
11405
11406     /**
11407      * Returns the sort state of the Store as an object with two properties:
11408      * <pre><code>
11409  field {String} The name of the field by which the Records are sorted
11410  direction {String} The sort order, "ASC" or "DESC"
11411      * </code></pre>
11412      */
11413     getSortState : function(){
11414         return this.sortInfo;
11415     },
11416
11417     // private
11418     applySort : function(){
11419         if(this.sortInfo && !this.remoteSort){
11420             var s = this.sortInfo, f = s.field;
11421             var st = this.fields.get(f).sortType;
11422             var fn = function(r1, r2){
11423                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11424                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11425             };
11426             this.data.sort(s.direction, fn);
11427             if(this.snapshot && this.snapshot != this.data){
11428                 this.snapshot.sort(s.direction, fn);
11429             }
11430         }
11431     },
11432
11433     /**
11434      * Sets the default sort column and order to be used by the next load operation.
11435      * @param {String} fieldName The name of the field to sort by.
11436      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11437      */
11438     setDefaultSort : function(field, dir){
11439         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11440     },
11441
11442     /**
11443      * Sort the Records.
11444      * If remote sorting is used, the sort is performed on the server, and the cache is
11445      * reloaded. If local sorting is used, the cache is sorted internally.
11446      * @param {String} fieldName The name of the field to sort by.
11447      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11448      */
11449     sort : function(fieldName, dir){
11450         var f = this.fields.get(fieldName);
11451         if(!dir){
11452             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11453             
11454             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11455                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11456             }else{
11457                 dir = f.sortDir;
11458             }
11459         }
11460         this.sortToggle[f.name] = dir;
11461         this.sortInfo = {field: f.name, direction: dir};
11462         if(!this.remoteSort){
11463             this.applySort();
11464             this.fireEvent("datachanged", this);
11465         }else{
11466             this.load(this.lastOptions);
11467         }
11468     },
11469
11470     /**
11471      * Calls the specified function for each of the Records in the cache.
11472      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11473      * Returning <em>false</em> aborts and exits the iteration.
11474      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11475      */
11476     each : function(fn, scope){
11477         this.data.each(fn, scope);
11478     },
11479
11480     /**
11481      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11482      * (e.g., during paging).
11483      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11484      */
11485     getModifiedRecords : function(){
11486         return this.modified;
11487     },
11488
11489     // private
11490     createFilterFn : function(property, value, anyMatch){
11491         if(!value.exec){ // not a regex
11492             value = String(value);
11493             if(value.length == 0){
11494                 return false;
11495             }
11496             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11497         }
11498         return function(r){
11499             return value.test(r.data[property]);
11500         };
11501     },
11502
11503     /**
11504      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11505      * @param {String} property A field on your records
11506      * @param {Number} start The record index to start at (defaults to 0)
11507      * @param {Number} end The last record index to include (defaults to length - 1)
11508      * @return {Number} The sum
11509      */
11510     sum : function(property, start, end){
11511         var rs = this.data.items, v = 0;
11512         start = start || 0;
11513         end = (end || end === 0) ? end : rs.length-1;
11514
11515         for(var i = start; i <= end; i++){
11516             v += (rs[i].data[property] || 0);
11517         }
11518         return v;
11519     },
11520
11521     /**
11522      * Filter the records by a specified property.
11523      * @param {String} field A field on your records
11524      * @param {String/RegExp} value Either a string that the field
11525      * should start with or a RegExp to test against the field
11526      * @param {Boolean} anyMatch True to match any part not just the beginning
11527      */
11528     filter : function(property, value, anyMatch){
11529         var fn = this.createFilterFn(property, value, anyMatch);
11530         return fn ? this.filterBy(fn) : this.clearFilter();
11531     },
11532
11533     /**
11534      * Filter by a function. The specified function will be called with each
11535      * record in this data source. If the function returns true the record is included,
11536      * otherwise it is filtered.
11537      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11538      * @param {Object} scope (optional) The scope of the function (defaults to this)
11539      */
11540     filterBy : function(fn, scope){
11541         this.snapshot = this.snapshot || this.data;
11542         this.data = this.queryBy(fn, scope||this);
11543         this.fireEvent("datachanged", this);
11544     },
11545
11546     /**
11547      * Query the records by a specified property.
11548      * @param {String} field A field on your records
11549      * @param {String/RegExp} value Either a string that the field
11550      * should start with or a RegExp to test against the field
11551      * @param {Boolean} anyMatch True to match any part not just the beginning
11552      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11553      */
11554     query : function(property, value, anyMatch){
11555         var fn = this.createFilterFn(property, value, anyMatch);
11556         return fn ? this.queryBy(fn) : this.data.clone();
11557     },
11558
11559     /**
11560      * Query by a function. The specified function will be called with each
11561      * record in this data source. If the function returns true the record is included
11562      * in the results.
11563      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11564      * @param {Object} scope (optional) The scope of the function (defaults to this)
11565       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11566      **/
11567     queryBy : function(fn, scope){
11568         var data = this.snapshot || this.data;
11569         return data.filterBy(fn, scope||this);
11570     },
11571
11572     /**
11573      * Collects unique values for a particular dataIndex from this store.
11574      * @param {String} dataIndex The property to collect
11575      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11576      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11577      * @return {Array} An array of the unique values
11578      **/
11579     collect : function(dataIndex, allowNull, bypassFilter){
11580         var d = (bypassFilter === true && this.snapshot) ?
11581                 this.snapshot.items : this.data.items;
11582         var v, sv, r = [], l = {};
11583         for(var i = 0, len = d.length; i < len; i++){
11584             v = d[i].data[dataIndex];
11585             sv = String(v);
11586             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11587                 l[sv] = true;
11588                 r[r.length] = v;
11589             }
11590         }
11591         return r;
11592     },
11593
11594     /**
11595      * Revert to a view of the Record cache with no filtering applied.
11596      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11597      */
11598     clearFilter : function(suppressEvent){
11599         if(this.snapshot && this.snapshot != this.data){
11600             this.data = this.snapshot;
11601             delete this.snapshot;
11602             if(suppressEvent !== true){
11603                 this.fireEvent("datachanged", this);
11604             }
11605         }
11606     },
11607
11608     // private
11609     afterEdit : function(record){
11610         if(this.modified.indexOf(record) == -1){
11611             this.modified.push(record);
11612         }
11613         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11614     },
11615     
11616     // private
11617     afterReject : function(record){
11618         this.modified.remove(record);
11619         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11620     },
11621
11622     // private
11623     afterCommit : function(record){
11624         this.modified.remove(record);
11625         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11626     },
11627
11628     /**
11629      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11630      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11631      */
11632     commitChanges : function(){
11633         var m = this.modified.slice(0);
11634         this.modified = [];
11635         for(var i = 0, len = m.length; i < len; i++){
11636             m[i].commit();
11637         }
11638     },
11639
11640     /**
11641      * Cancel outstanding changes on all changed records.
11642      */
11643     rejectChanges : function(){
11644         var m = this.modified.slice(0);
11645         this.modified = [];
11646         for(var i = 0, len = m.length; i < len; i++){
11647             m[i].reject();
11648         }
11649     },
11650
11651     onMetaChange : function(meta, rtype, o){
11652         this.recordType = rtype;
11653         this.fields = rtype.prototype.fields;
11654         delete this.snapshot;
11655         this.sortInfo = meta.sortInfo || this.sortInfo;
11656         this.modified = [];
11657         this.fireEvent('metachange', this, this.reader.meta);
11658     },
11659     
11660     moveIndex : function(data, type)
11661     {
11662         var index = this.indexOf(data);
11663         
11664         var newIndex = index + type;
11665         
11666         this.remove(data);
11667         
11668         this.insert(newIndex, data);
11669         
11670     }
11671 });/*
11672  * Based on:
11673  * Ext JS Library 1.1.1
11674  * Copyright(c) 2006-2007, Ext JS, LLC.
11675  *
11676  * Originally Released Under LGPL - original licence link has changed is not relivant.
11677  *
11678  * Fork - LGPL
11679  * <script type="text/javascript">
11680  */
11681
11682 /**
11683  * @class Roo.data.SimpleStore
11684  * @extends Roo.data.Store
11685  * Small helper class to make creating Stores from Array data easier.
11686  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11687  * @cfg {Array} fields An array of field definition objects, or field name strings.
11688  * @cfg {Array} data The multi-dimensional array of data
11689  * @constructor
11690  * @param {Object} config
11691  */
11692 Roo.data.SimpleStore = function(config){
11693     Roo.data.SimpleStore.superclass.constructor.call(this, {
11694         isLocal : true,
11695         reader: new Roo.data.ArrayReader({
11696                 id: config.id
11697             },
11698             Roo.data.Record.create(config.fields)
11699         ),
11700         proxy : new Roo.data.MemoryProxy(config.data)
11701     });
11702     this.load();
11703 };
11704 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11705  * Based on:
11706  * Ext JS Library 1.1.1
11707  * Copyright(c) 2006-2007, Ext JS, LLC.
11708  *
11709  * Originally Released Under LGPL - original licence link has changed is not relivant.
11710  *
11711  * Fork - LGPL
11712  * <script type="text/javascript">
11713  */
11714
11715 /**
11716 /**
11717  * @extends Roo.data.Store
11718  * @class Roo.data.JsonStore
11719  * Small helper class to make creating Stores for JSON data easier. <br/>
11720 <pre><code>
11721 var store = new Roo.data.JsonStore({
11722     url: 'get-images.php',
11723     root: 'images',
11724     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11725 });
11726 </code></pre>
11727  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11728  * JsonReader and HttpProxy (unless inline data is provided).</b>
11729  * @cfg {Array} fields An array of field definition objects, or field name strings.
11730  * @constructor
11731  * @param {Object} config
11732  */
11733 Roo.data.JsonStore = function(c){
11734     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11735         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11736         reader: new Roo.data.JsonReader(c, c.fields)
11737     }));
11738 };
11739 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11740  * Based on:
11741  * Ext JS Library 1.1.1
11742  * Copyright(c) 2006-2007, Ext JS, LLC.
11743  *
11744  * Originally Released Under LGPL - original licence link has changed is not relivant.
11745  *
11746  * Fork - LGPL
11747  * <script type="text/javascript">
11748  */
11749
11750  
11751 Roo.data.Field = function(config){
11752     if(typeof config == "string"){
11753         config = {name: config};
11754     }
11755     Roo.apply(this, config);
11756     
11757     if(!this.type){
11758         this.type = "auto";
11759     }
11760     
11761     var st = Roo.data.SortTypes;
11762     // named sortTypes are supported, here we look them up
11763     if(typeof this.sortType == "string"){
11764         this.sortType = st[this.sortType];
11765     }
11766     
11767     // set default sortType for strings and dates
11768     if(!this.sortType){
11769         switch(this.type){
11770             case "string":
11771                 this.sortType = st.asUCString;
11772                 break;
11773             case "date":
11774                 this.sortType = st.asDate;
11775                 break;
11776             default:
11777                 this.sortType = st.none;
11778         }
11779     }
11780
11781     // define once
11782     var stripRe = /[\$,%]/g;
11783
11784     // prebuilt conversion function for this field, instead of
11785     // switching every time we're reading a value
11786     if(!this.convert){
11787         var cv, dateFormat = this.dateFormat;
11788         switch(this.type){
11789             case "":
11790             case "auto":
11791             case undefined:
11792                 cv = function(v){ return v; };
11793                 break;
11794             case "string":
11795                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11796                 break;
11797             case "int":
11798                 cv = function(v){
11799                     return v !== undefined && v !== null && v !== '' ?
11800                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11801                     };
11802                 break;
11803             case "float":
11804                 cv = function(v){
11805                     return v !== undefined && v !== null && v !== '' ?
11806                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11807                     };
11808                 break;
11809             case "bool":
11810             case "boolean":
11811                 cv = function(v){ return v === true || v === "true" || v == 1; };
11812                 break;
11813             case "date":
11814                 cv = function(v){
11815                     if(!v){
11816                         return '';
11817                     }
11818                     if(v instanceof Date){
11819                         return v;
11820                     }
11821                     if(dateFormat){
11822                         if(dateFormat == "timestamp"){
11823                             return new Date(v*1000);
11824                         }
11825                         return Date.parseDate(v, dateFormat);
11826                     }
11827                     var parsed = Date.parse(v);
11828                     return parsed ? new Date(parsed) : null;
11829                 };
11830              break;
11831             
11832         }
11833         this.convert = cv;
11834     }
11835 };
11836
11837 Roo.data.Field.prototype = {
11838     dateFormat: null,
11839     defaultValue: "",
11840     mapping: null,
11841     sortType : null,
11842     sortDir : "ASC"
11843 };/*
11844  * Based on:
11845  * Ext JS Library 1.1.1
11846  * Copyright(c) 2006-2007, Ext JS, LLC.
11847  *
11848  * Originally Released Under LGPL - original licence link has changed is not relivant.
11849  *
11850  * Fork - LGPL
11851  * <script type="text/javascript">
11852  */
11853  
11854 // Base class for reading structured data from a data source.  This class is intended to be
11855 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11856
11857 /**
11858  * @class Roo.data.DataReader
11859  * Base class for reading structured data from a data source.  This class is intended to be
11860  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11861  */
11862
11863 Roo.data.DataReader = function(meta, recordType){
11864     
11865     this.meta = meta;
11866     
11867     this.recordType = recordType instanceof Array ? 
11868         Roo.data.Record.create(recordType) : recordType;
11869 };
11870
11871 Roo.data.DataReader.prototype = {
11872      /**
11873      * Create an empty record
11874      * @param {Object} data (optional) - overlay some values
11875      * @return {Roo.data.Record} record created.
11876      */
11877     newRow :  function(d) {
11878         var da =  {};
11879         this.recordType.prototype.fields.each(function(c) {
11880             switch( c.type) {
11881                 case 'int' : da[c.name] = 0; break;
11882                 case 'date' : da[c.name] = new Date(); break;
11883                 case 'float' : da[c.name] = 0.0; break;
11884                 case 'boolean' : da[c.name] = false; break;
11885                 default : da[c.name] = ""; break;
11886             }
11887             
11888         });
11889         return new this.recordType(Roo.apply(da, d));
11890     }
11891     
11892 };/*
11893  * Based on:
11894  * Ext JS Library 1.1.1
11895  * Copyright(c) 2006-2007, Ext JS, LLC.
11896  *
11897  * Originally Released Under LGPL - original licence link has changed is not relivant.
11898  *
11899  * Fork - LGPL
11900  * <script type="text/javascript">
11901  */
11902
11903 /**
11904  * @class Roo.data.DataProxy
11905  * @extends Roo.data.Observable
11906  * This class is an abstract base class for implementations which provide retrieval of
11907  * unformatted data objects.<br>
11908  * <p>
11909  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11910  * (of the appropriate type which knows how to parse the data object) to provide a block of
11911  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11912  * <p>
11913  * Custom implementations must implement the load method as described in
11914  * {@link Roo.data.HttpProxy#load}.
11915  */
11916 Roo.data.DataProxy = function(){
11917     this.addEvents({
11918         /**
11919          * @event beforeload
11920          * Fires before a network request is made to retrieve a data object.
11921          * @param {Object} This DataProxy object.
11922          * @param {Object} params The params parameter to the load function.
11923          */
11924         beforeload : true,
11925         /**
11926          * @event load
11927          * Fires before the load method's callback is called.
11928          * @param {Object} This DataProxy object.
11929          * @param {Object} o The data object.
11930          * @param {Object} arg The callback argument object passed to the load function.
11931          */
11932         load : true,
11933         /**
11934          * @event loadexception
11935          * Fires if an Exception occurs during data retrieval.
11936          * @param {Object} This DataProxy object.
11937          * @param {Object} o The data object.
11938          * @param {Object} arg The callback argument object passed to the load function.
11939          * @param {Object} e The Exception.
11940          */
11941         loadexception : true
11942     });
11943     Roo.data.DataProxy.superclass.constructor.call(this);
11944 };
11945
11946 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11947
11948     /**
11949      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11950      */
11951 /*
11952  * Based on:
11953  * Ext JS Library 1.1.1
11954  * Copyright(c) 2006-2007, Ext JS, LLC.
11955  *
11956  * Originally Released Under LGPL - original licence link has changed is not relivant.
11957  *
11958  * Fork - LGPL
11959  * <script type="text/javascript">
11960  */
11961 /**
11962  * @class Roo.data.MemoryProxy
11963  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11964  * to the Reader when its load method is called.
11965  * @constructor
11966  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11967  */
11968 Roo.data.MemoryProxy = function(data){
11969     if (data.data) {
11970         data = data.data;
11971     }
11972     Roo.data.MemoryProxy.superclass.constructor.call(this);
11973     this.data = data;
11974 };
11975
11976 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11977     
11978     /**
11979      * Load data from the requested source (in this case an in-memory
11980      * data object passed to the constructor), read the data object into
11981      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11982      * process that block using the passed callback.
11983      * @param {Object} params This parameter is not used by the MemoryProxy class.
11984      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11985      * object into a block of Roo.data.Records.
11986      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11987      * The function must be passed <ul>
11988      * <li>The Record block object</li>
11989      * <li>The "arg" argument from the load function</li>
11990      * <li>A boolean success indicator</li>
11991      * </ul>
11992      * @param {Object} scope The scope in which to call the callback
11993      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11994      */
11995     load : function(params, reader, callback, scope, arg){
11996         params = params || {};
11997         var result;
11998         try {
11999             result = reader.readRecords(this.data);
12000         }catch(e){
12001             this.fireEvent("loadexception", this, arg, null, e);
12002             callback.call(scope, null, arg, false);
12003             return;
12004         }
12005         callback.call(scope, result, arg, true);
12006     },
12007     
12008     // private
12009     update : function(params, records){
12010         
12011     }
12012 });/*
12013  * Based on:
12014  * Ext JS Library 1.1.1
12015  * Copyright(c) 2006-2007, Ext JS, LLC.
12016  *
12017  * Originally Released Under LGPL - original licence link has changed is not relivant.
12018  *
12019  * Fork - LGPL
12020  * <script type="text/javascript">
12021  */
12022 /**
12023  * @class Roo.data.HttpProxy
12024  * @extends Roo.data.DataProxy
12025  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12026  * configured to reference a certain URL.<br><br>
12027  * <p>
12028  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12029  * from which the running page was served.<br><br>
12030  * <p>
12031  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12032  * <p>
12033  * Be aware that to enable the browser to parse an XML document, the server must set
12034  * the Content-Type header in the HTTP response to "text/xml".
12035  * @constructor
12036  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12037  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12038  * will be used to make the request.
12039  */
12040 Roo.data.HttpProxy = function(conn){
12041     Roo.data.HttpProxy.superclass.constructor.call(this);
12042     // is conn a conn config or a real conn?
12043     this.conn = conn;
12044     this.useAjax = !conn || !conn.events;
12045   
12046 };
12047
12048 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12049     // thse are take from connection...
12050     
12051     /**
12052      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12053      */
12054     /**
12055      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12056      * extra parameters to each request made by this object. (defaults to undefined)
12057      */
12058     /**
12059      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12060      *  to each request made by this object. (defaults to undefined)
12061      */
12062     /**
12063      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
12064      */
12065     /**
12066      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12067      */
12068      /**
12069      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12070      * @type Boolean
12071      */
12072   
12073
12074     /**
12075      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12076      * @type Boolean
12077      */
12078     /**
12079      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12080      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12081      * a finer-grained basis than the DataProxy events.
12082      */
12083     getConnection : function(){
12084         return this.useAjax ? Roo.Ajax : this.conn;
12085     },
12086
12087     /**
12088      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12089      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12090      * process that block using the passed callback.
12091      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12092      * for the request to the remote server.
12093      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12094      * object into a block of Roo.data.Records.
12095      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12096      * The function must be passed <ul>
12097      * <li>The Record block object</li>
12098      * <li>The "arg" argument from the load function</li>
12099      * <li>A boolean success indicator</li>
12100      * </ul>
12101      * @param {Object} scope The scope in which to call the callback
12102      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12103      */
12104     load : function(params, reader, callback, scope, arg){
12105         if(this.fireEvent("beforeload", this, params) !== false){
12106             var  o = {
12107                 params : params || {},
12108                 request: {
12109                     callback : callback,
12110                     scope : scope,
12111                     arg : arg
12112                 },
12113                 reader: reader,
12114                 callback : this.loadResponse,
12115                 scope: this
12116             };
12117             if(this.useAjax){
12118                 Roo.applyIf(o, this.conn);
12119                 if(this.activeRequest){
12120                     Roo.Ajax.abort(this.activeRequest);
12121                 }
12122                 this.activeRequest = Roo.Ajax.request(o);
12123             }else{
12124                 this.conn.request(o);
12125             }
12126         }else{
12127             callback.call(scope||this, null, arg, false);
12128         }
12129     },
12130
12131     // private
12132     loadResponse : function(o, success, response){
12133         delete this.activeRequest;
12134         if(!success){
12135             this.fireEvent("loadexception", this, o, response);
12136             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12137             return;
12138         }
12139         var result;
12140         try {
12141             result = o.reader.read(response);
12142         }catch(e){
12143             this.fireEvent("loadexception", this, o, response, e);
12144             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12145             return;
12146         }
12147         
12148         this.fireEvent("load", this, o, o.request.arg);
12149         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12150     },
12151
12152     // private
12153     update : function(dataSet){
12154
12155     },
12156
12157     // private
12158     updateResponse : function(dataSet){
12159
12160     }
12161 });/*
12162  * Based on:
12163  * Ext JS Library 1.1.1
12164  * Copyright(c) 2006-2007, Ext JS, LLC.
12165  *
12166  * Originally Released Under LGPL - original licence link has changed is not relivant.
12167  *
12168  * Fork - LGPL
12169  * <script type="text/javascript">
12170  */
12171
12172 /**
12173  * @class Roo.data.ScriptTagProxy
12174  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12175  * other than the originating domain of the running page.<br><br>
12176  * <p>
12177  * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
12178  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12179  * <p>
12180  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12181  * source code that is used as the source inside a &lt;script> tag.<br><br>
12182  * <p>
12183  * In order for the browser to process the returned data, the server must wrap the data object
12184  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12185  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12186  * depending on whether the callback name was passed:
12187  * <p>
12188  * <pre><code>
12189 boolean scriptTag = false;
12190 String cb = request.getParameter("callback");
12191 if (cb != null) {
12192     scriptTag = true;
12193     response.setContentType("text/javascript");
12194 } else {
12195     response.setContentType("application/x-json");
12196 }
12197 Writer out = response.getWriter();
12198 if (scriptTag) {
12199     out.write(cb + "(");
12200 }
12201 out.print(dataBlock.toJsonString());
12202 if (scriptTag) {
12203     out.write(");");
12204 }
12205 </pre></code>
12206  *
12207  * @constructor
12208  * @param {Object} config A configuration object.
12209  */
12210 Roo.data.ScriptTagProxy = function(config){
12211     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12212     Roo.apply(this, config);
12213     this.head = document.getElementsByTagName("head")[0];
12214 };
12215
12216 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12217
12218 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12219     /**
12220      * @cfg {String} url The URL from which to request the data object.
12221      */
12222     /**
12223      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12224      */
12225     timeout : 30000,
12226     /**
12227      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12228      * the server the name of the callback function set up by the load call to process the returned data object.
12229      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12230      * javascript output which calls this named function passing the data object as its only parameter.
12231      */
12232     callbackParam : "callback",
12233     /**
12234      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12235      * name to the request.
12236      */
12237     nocache : true,
12238
12239     /**
12240      * Load data from the configured URL, read the data object into
12241      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12242      * process that block using the passed callback.
12243      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12244      * for the request to the remote server.
12245      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12246      * object into a block of Roo.data.Records.
12247      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12248      * The function must be passed <ul>
12249      * <li>The Record block object</li>
12250      * <li>The "arg" argument from the load function</li>
12251      * <li>A boolean success indicator</li>
12252      * </ul>
12253      * @param {Object} scope The scope in which to call the callback
12254      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12255      */
12256     load : function(params, reader, callback, scope, arg){
12257         if(this.fireEvent("beforeload", this, params) !== false){
12258
12259             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12260
12261             var url = this.url;
12262             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12263             if(this.nocache){
12264                 url += "&_dc=" + (new Date().getTime());
12265             }
12266             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12267             var trans = {
12268                 id : transId,
12269                 cb : "stcCallback"+transId,
12270                 scriptId : "stcScript"+transId,
12271                 params : params,
12272                 arg : arg,
12273                 url : url,
12274                 callback : callback,
12275                 scope : scope,
12276                 reader : reader
12277             };
12278             var conn = this;
12279
12280             window[trans.cb] = function(o){
12281                 conn.handleResponse(o, trans);
12282             };
12283
12284             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12285
12286             if(this.autoAbort !== false){
12287                 this.abort();
12288             }
12289
12290             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12291
12292             var script = document.createElement("script");
12293             script.setAttribute("src", url);
12294             script.setAttribute("type", "text/javascript");
12295             script.setAttribute("id", trans.scriptId);
12296             this.head.appendChild(script);
12297
12298             this.trans = trans;
12299         }else{
12300             callback.call(scope||this, null, arg, false);
12301         }
12302     },
12303
12304     // private
12305     isLoading : function(){
12306         return this.trans ? true : false;
12307     },
12308
12309     /**
12310      * Abort the current server request.
12311      */
12312     abort : function(){
12313         if(this.isLoading()){
12314             this.destroyTrans(this.trans);
12315         }
12316     },
12317
12318     // private
12319     destroyTrans : function(trans, isLoaded){
12320         this.head.removeChild(document.getElementById(trans.scriptId));
12321         clearTimeout(trans.timeoutId);
12322         if(isLoaded){
12323             window[trans.cb] = undefined;
12324             try{
12325                 delete window[trans.cb];
12326             }catch(e){}
12327         }else{
12328             // if hasn't been loaded, wait for load to remove it to prevent script error
12329             window[trans.cb] = function(){
12330                 window[trans.cb] = undefined;
12331                 try{
12332                     delete window[trans.cb];
12333                 }catch(e){}
12334             };
12335         }
12336     },
12337
12338     // private
12339     handleResponse : function(o, trans){
12340         this.trans = false;
12341         this.destroyTrans(trans, true);
12342         var result;
12343         try {
12344             result = trans.reader.readRecords(o);
12345         }catch(e){
12346             this.fireEvent("loadexception", this, o, trans.arg, e);
12347             trans.callback.call(trans.scope||window, null, trans.arg, false);
12348             return;
12349         }
12350         this.fireEvent("load", this, o, trans.arg);
12351         trans.callback.call(trans.scope||window, result, trans.arg, true);
12352     },
12353
12354     // private
12355     handleFailure : function(trans){
12356         this.trans = false;
12357         this.destroyTrans(trans, false);
12358         this.fireEvent("loadexception", this, null, trans.arg);
12359         trans.callback.call(trans.scope||window, null, trans.arg, false);
12360     }
12361 });/*
12362  * Based on:
12363  * Ext JS Library 1.1.1
12364  * Copyright(c) 2006-2007, Ext JS, LLC.
12365  *
12366  * Originally Released Under LGPL - original licence link has changed is not relivant.
12367  *
12368  * Fork - LGPL
12369  * <script type="text/javascript">
12370  */
12371
12372 /**
12373  * @class Roo.data.JsonReader
12374  * @extends Roo.data.DataReader
12375  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12376  * based on mappings in a provided Roo.data.Record constructor.
12377  * 
12378  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12379  * in the reply previously. 
12380  * 
12381  * <p>
12382  * Example code:
12383  * <pre><code>
12384 var RecordDef = Roo.data.Record.create([
12385     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12386     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12387 ]);
12388 var myReader = new Roo.data.JsonReader({
12389     totalProperty: "results",    // The property which contains the total dataset size (optional)
12390     root: "rows",                // The property which contains an Array of row objects
12391     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12392 }, RecordDef);
12393 </code></pre>
12394  * <p>
12395  * This would consume a JSON file like this:
12396  * <pre><code>
12397 { 'results': 2, 'rows': [
12398     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12399     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12400 }
12401 </code></pre>
12402  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12403  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12404  * paged from the remote server.
12405  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12406  * @cfg {String} root name of the property which contains the Array of row objects.
12407  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12408  * @cfg {Array} fields Array of field definition objects
12409  * @constructor
12410  * Create a new JsonReader
12411  * @param {Object} meta Metadata configuration options
12412  * @param {Object} recordType Either an Array of field definition objects,
12413  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12414  */
12415 Roo.data.JsonReader = function(meta, recordType){
12416     
12417     meta = meta || {};
12418     // set some defaults:
12419     Roo.applyIf(meta, {
12420         totalProperty: 'total',
12421         successProperty : 'success',
12422         root : 'data',
12423         id : 'id'
12424     });
12425     
12426     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12427 };
12428 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12429     
12430     /**
12431      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12432      * Used by Store query builder to append _requestMeta to params.
12433      * 
12434      */
12435     metaFromRemote : false,
12436     /**
12437      * This method is only used by a DataProxy which has retrieved data from a remote server.
12438      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12439      * @return {Object} data A data block which is used by an Roo.data.Store object as
12440      * a cache of Roo.data.Records.
12441      */
12442     read : function(response){
12443         var json = response.responseText;
12444        
12445         var o = /* eval:var:o */ eval("("+json+")");
12446         if(!o) {
12447             throw {message: "JsonReader.read: Json object not found"};
12448         }
12449         
12450         if(o.metaData){
12451             
12452             delete this.ef;
12453             this.metaFromRemote = true;
12454             this.meta = o.metaData;
12455             this.recordType = Roo.data.Record.create(o.metaData.fields);
12456             this.onMetaChange(this.meta, this.recordType, o);
12457         }
12458         return this.readRecords(o);
12459     },
12460
12461     // private function a store will implement
12462     onMetaChange : function(meta, recordType, o){
12463
12464     },
12465
12466     /**
12467          * @ignore
12468          */
12469     simpleAccess: function(obj, subsc) {
12470         return obj[subsc];
12471     },
12472
12473         /**
12474          * @ignore
12475          */
12476     getJsonAccessor: function(){
12477         var re = /[\[\.]/;
12478         return function(expr) {
12479             try {
12480                 return(re.test(expr))
12481                     ? new Function("obj", "return obj." + expr)
12482                     : function(obj){
12483                         return obj[expr];
12484                     };
12485             } catch(e){}
12486             return Roo.emptyFn;
12487         };
12488     }(),
12489
12490     /**
12491      * Create a data block containing Roo.data.Records from an XML document.
12492      * @param {Object} o An object which contains an Array of row objects in the property specified
12493      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12494      * which contains the total size of the dataset.
12495      * @return {Object} data A data block which is used by an Roo.data.Store object as
12496      * a cache of Roo.data.Records.
12497      */
12498     readRecords : function(o){
12499         /**
12500          * After any data loads, the raw JSON data is available for further custom processing.
12501          * @type Object
12502          */
12503         this.o = o;
12504         var s = this.meta, Record = this.recordType,
12505             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12506
12507 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12508         if (!this.ef) {
12509             if(s.totalProperty) {
12510                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12511                 }
12512                 if(s.successProperty) {
12513                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12514                 }
12515                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12516                 if (s.id) {
12517                         var g = this.getJsonAccessor(s.id);
12518                         this.getId = function(rec) {
12519                                 var r = g(rec);  
12520                                 return (r === undefined || r === "") ? null : r;
12521                         };
12522                 } else {
12523                         this.getId = function(){return null;};
12524                 }
12525             this.ef = [];
12526             for(var jj = 0; jj < fl; jj++){
12527                 f = fi[jj];
12528                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12529                 this.ef[jj] = this.getJsonAccessor(map);
12530             }
12531         }
12532
12533         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12534         if(s.totalProperty){
12535             var vt = parseInt(this.getTotal(o), 10);
12536             if(!isNaN(vt)){
12537                 totalRecords = vt;
12538             }
12539         }
12540         if(s.successProperty){
12541             var vs = this.getSuccess(o);
12542             if(vs === false || vs === 'false'){
12543                 success = false;
12544             }
12545         }
12546         var records = [];
12547         for(var i = 0; i < c; i++){
12548                 var n = root[i];
12549             var values = {};
12550             var id = this.getId(n);
12551             for(var j = 0; j < fl; j++){
12552                 f = fi[j];
12553             var v = this.ef[j](n);
12554             if (!f.convert) {
12555                 Roo.log('missing convert for ' + f.name);
12556                 Roo.log(f);
12557                 continue;
12558             }
12559             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12560             }
12561             var record = new Record(values, id);
12562             record.json = n;
12563             records[i] = record;
12564         }
12565         return {
12566             raw : o,
12567             success : success,
12568             records : records,
12569             totalRecords : totalRecords
12570         };
12571     }
12572 });/*
12573  * Based on:
12574  * Ext JS Library 1.1.1
12575  * Copyright(c) 2006-2007, Ext JS, LLC.
12576  *
12577  * Originally Released Under LGPL - original licence link has changed is not relivant.
12578  *
12579  * Fork - LGPL
12580  * <script type="text/javascript">
12581  */
12582
12583 /**
12584  * @class Roo.data.ArrayReader
12585  * @extends Roo.data.DataReader
12586  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12587  * Each element of that Array represents a row of data fields. The
12588  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12589  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12590  * <p>
12591  * Example code:.
12592  * <pre><code>
12593 var RecordDef = Roo.data.Record.create([
12594     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12595     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12596 ]);
12597 var myReader = new Roo.data.ArrayReader({
12598     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12599 }, RecordDef);
12600 </code></pre>
12601  * <p>
12602  * This would consume an Array like this:
12603  * <pre><code>
12604 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12605   </code></pre>
12606  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12607  * @constructor
12608  * Create a new JsonReader
12609  * @param {Object} meta Metadata configuration options.
12610  * @param {Object} recordType Either an Array of field definition objects
12611  * as specified to {@link Roo.data.Record#create},
12612  * or an {@link Roo.data.Record} object
12613  * created using {@link Roo.data.Record#create}.
12614  */
12615 Roo.data.ArrayReader = function(meta, recordType){
12616     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12617 };
12618
12619 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12620     /**
12621      * Create a data block containing Roo.data.Records from an XML document.
12622      * @param {Object} o An Array of row objects which represents the dataset.
12623      * @return {Object} data A data block which is used by an Roo.data.Store object as
12624      * a cache of Roo.data.Records.
12625      */
12626     readRecords : function(o){
12627         var sid = this.meta ? this.meta.id : null;
12628         var recordType = this.recordType, fields = recordType.prototype.fields;
12629         var records = [];
12630         var root = o;
12631             for(var i = 0; i < root.length; i++){
12632                     var n = root[i];
12633                 var values = {};
12634                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12635                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12636                 var f = fields.items[j];
12637                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12638                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12639                 v = f.convert(v);
12640                 values[f.name] = v;
12641             }
12642                 var record = new recordType(values, id);
12643                 record.json = n;
12644                 records[records.length] = record;
12645             }
12646             return {
12647                 records : records,
12648                 totalRecords : records.length
12649             };
12650     }
12651 });/*
12652  * - LGPL
12653  * * 
12654  */
12655
12656 /**
12657  * @class Roo.bootstrap.ComboBox
12658  * @extends Roo.bootstrap.TriggerField
12659  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12660  * @cfg {Boolean} append (true|false) default false
12661  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12662  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12663  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12664  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12665  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12666  * @cfg {Boolean} animate default true
12667  * @cfg {Boolean} emptyResultText only for touch device
12668  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12669  * @cfg {String} emptyTitle default ''
12670  * @constructor
12671  * Create a new ComboBox.
12672  * @param {Object} config Configuration options
12673  */
12674 Roo.bootstrap.ComboBox = function(config){
12675     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12676     this.addEvents({
12677         /**
12678          * @event expand
12679          * Fires when the dropdown list is expanded
12680         * @param {Roo.bootstrap.ComboBox} combo This combo box
12681         */
12682         'expand' : true,
12683         /**
12684          * @event collapse
12685          * Fires when the dropdown list is collapsed
12686         * @param {Roo.bootstrap.ComboBox} combo This combo box
12687         */
12688         'collapse' : true,
12689         /**
12690          * @event beforeselect
12691          * Fires before a list item is selected. Return false to cancel the selection.
12692         * @param {Roo.bootstrap.ComboBox} combo This combo box
12693         * @param {Roo.data.Record} record The data record returned from the underlying store
12694         * @param {Number} index The index of the selected item in the dropdown list
12695         */
12696         'beforeselect' : true,
12697         /**
12698          * @event select
12699          * Fires when a list item is selected
12700         * @param {Roo.bootstrap.ComboBox} combo This combo box
12701         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12702         * @param {Number} index The index of the selected item in the dropdown list
12703         */
12704         'select' : true,
12705         /**
12706          * @event beforequery
12707          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12708          * The event object passed has these properties:
12709         * @param {Roo.bootstrap.ComboBox} combo This combo box
12710         * @param {String} query The query
12711         * @param {Boolean} forceAll true to force "all" query
12712         * @param {Boolean} cancel true to cancel the query
12713         * @param {Object} e The query event object
12714         */
12715         'beforequery': true,
12716          /**
12717          * @event add
12718          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12719         * @param {Roo.bootstrap.ComboBox} combo This combo box
12720         */
12721         'add' : true,
12722         /**
12723          * @event edit
12724          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12725         * @param {Roo.bootstrap.ComboBox} combo This combo box
12726         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12727         */
12728         'edit' : true,
12729         /**
12730          * @event remove
12731          * Fires when the remove value from the combobox array
12732         * @param {Roo.bootstrap.ComboBox} combo This combo box
12733         */
12734         'remove' : true,
12735         /**
12736          * @event afterremove
12737          * Fires when the remove value from the combobox array
12738         * @param {Roo.bootstrap.ComboBox} combo This combo box
12739         */
12740         'afterremove' : true,
12741         /**
12742          * @event specialfilter
12743          * Fires when specialfilter
12744             * @param {Roo.bootstrap.ComboBox} combo This combo box
12745             */
12746         'specialfilter' : true,
12747         /**
12748          * @event tick
12749          * Fires when tick the element
12750             * @param {Roo.bootstrap.ComboBox} combo This combo box
12751             */
12752         'tick' : true,
12753         /**
12754          * @event touchviewdisplay
12755          * Fires when touch view require special display (default is using displayField)
12756             * @param {Roo.bootstrap.ComboBox} combo This combo box
12757             * @param {Object} cfg set html .
12758             */
12759         'touchviewdisplay' : true
12760         
12761     });
12762     
12763     this.item = [];
12764     this.tickItems = [];
12765     
12766     this.selectedIndex = -1;
12767     if(this.mode == 'local'){
12768         if(config.queryDelay === undefined){
12769             this.queryDelay = 10;
12770         }
12771         if(config.minChars === undefined){
12772             this.minChars = 0;
12773         }
12774     }
12775 };
12776
12777 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12778      
12779     /**
12780      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12781      * rendering into an Roo.Editor, defaults to false)
12782      */
12783     /**
12784      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12785      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12786      */
12787     /**
12788      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12789      */
12790     /**
12791      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12792      * the dropdown list (defaults to undefined, with no header element)
12793      */
12794
12795      /**
12796      * @cfg {String/Roo.Template} tpl The template to use to render the output
12797      */
12798      
12799      /**
12800      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12801      */
12802     listWidth: undefined,
12803     /**
12804      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12805      * mode = 'remote' or 'text' if mode = 'local')
12806      */
12807     displayField: undefined,
12808     
12809     /**
12810      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12811      * mode = 'remote' or 'value' if mode = 'local'). 
12812      * Note: use of a valueField requires the user make a selection
12813      * in order for a value to be mapped.
12814      */
12815     valueField: undefined,
12816     /**
12817      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12818      */
12819     modalTitle : '',
12820     
12821     /**
12822      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12823      * field's data value (defaults to the underlying DOM element's name)
12824      */
12825     hiddenName: undefined,
12826     /**
12827      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12828      */
12829     listClass: '',
12830     /**
12831      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12832      */
12833     selectedClass: 'active',
12834     
12835     /**
12836      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12837      */
12838     shadow:'sides',
12839     /**
12840      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12841      * anchor positions (defaults to 'tl-bl')
12842      */
12843     listAlign: 'tl-bl?',
12844     /**
12845      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12846      */
12847     maxHeight: 300,
12848     /**
12849      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12850      * query specified by the allQuery config option (defaults to 'query')
12851      */
12852     triggerAction: 'query',
12853     /**
12854      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12855      * (defaults to 4, does not apply if editable = false)
12856      */
12857     minChars : 4,
12858     /**
12859      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12860      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12861      */
12862     typeAhead: false,
12863     /**
12864      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12865      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12866      */
12867     queryDelay: 500,
12868     /**
12869      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12870      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12871      */
12872     pageSize: 0,
12873     /**
12874      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12875      * when editable = true (defaults to false)
12876      */
12877     selectOnFocus:false,
12878     /**
12879      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12880      */
12881     queryParam: 'query',
12882     /**
12883      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12884      * when mode = 'remote' (defaults to 'Loading...')
12885      */
12886     loadingText: 'Loading...',
12887     /**
12888      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12889      */
12890     resizable: false,
12891     /**
12892      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12893      */
12894     handleHeight : 8,
12895     /**
12896      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12897      * traditional select (defaults to true)
12898      */
12899     editable: true,
12900     /**
12901      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12902      */
12903     allQuery: '',
12904     /**
12905      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12906      */
12907     mode: 'remote',
12908     /**
12909      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12910      * listWidth has a higher value)
12911      */
12912     minListWidth : 70,
12913     /**
12914      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12915      * allow the user to set arbitrary text into the field (defaults to false)
12916      */
12917     forceSelection:false,
12918     /**
12919      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12920      * if typeAhead = true (defaults to 250)
12921      */
12922     typeAheadDelay : 250,
12923     /**
12924      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12925      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12926      */
12927     valueNotFoundText : undefined,
12928     /**
12929      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12930      */
12931     blockFocus : false,
12932     
12933     /**
12934      * @cfg {Boolean} disableClear Disable showing of clear button.
12935      */
12936     disableClear : false,
12937     /**
12938      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12939      */
12940     alwaysQuery : false,
12941     
12942     /**
12943      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12944      */
12945     multiple : false,
12946     
12947     /**
12948      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12949      */
12950     invalidClass : "has-warning",
12951     
12952     /**
12953      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12954      */
12955     validClass : "has-success",
12956     
12957     /**
12958      * @cfg {Boolean} specialFilter (true|false) special filter default false
12959      */
12960     specialFilter : false,
12961     
12962     /**
12963      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12964      */
12965     mobileTouchView : true,
12966     
12967     /**
12968      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12969      */
12970     useNativeIOS : false,
12971     
12972     ios_options : false,
12973     
12974     //private
12975     addicon : false,
12976     editicon: false,
12977     
12978     page: 0,
12979     hasQuery: false,
12980     append: false,
12981     loadNext: false,
12982     autoFocus : true,
12983     tickable : false,
12984     btnPosition : 'right',
12985     triggerList : true,
12986     showToggleBtn : true,
12987     animate : true,
12988     emptyResultText: 'Empty',
12989     triggerText : 'Select',
12990     emptyTitle : '',
12991     
12992     // element that contains real text value.. (when hidden is used..)
12993     
12994     getAutoCreate : function()
12995     {   
12996         var cfg = false;
12997         //render
12998         /*
12999          * Render classic select for iso
13000          */
13001         
13002         if(Roo.isIOS && this.useNativeIOS){
13003             cfg = this.getAutoCreateNativeIOS();
13004             return cfg;
13005         }
13006         
13007         /*
13008          * Touch Devices
13009          */
13010         
13011         if(Roo.isTouch && this.mobileTouchView){
13012             cfg = this.getAutoCreateTouchView();
13013             return cfg;;
13014         }
13015         
13016         /*
13017          *  Normal ComboBox
13018          */
13019         if(!this.tickable){
13020             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13021             return cfg;
13022         }
13023         
13024         /*
13025          *  ComboBox with tickable selections
13026          */
13027              
13028         var align = this.labelAlign || this.parentLabelAlign();
13029         
13030         cfg = {
13031             cls : 'form-group roo-combobox-tickable' //input-group
13032         };
13033         
13034         var btn_text_select = '';
13035         var btn_text_done = '';
13036         var btn_text_cancel = '';
13037         
13038         if (this.btn_text_show) {
13039             btn_text_select = 'Select';
13040             btn_text_done = 'Done';
13041             btn_text_cancel = 'Cancel'; 
13042         }
13043         
13044         var buttons = {
13045             tag : 'div',
13046             cls : 'tickable-buttons',
13047             cn : [
13048                 {
13049                     tag : 'button',
13050                     type : 'button',
13051                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13052                     //html : this.triggerText
13053                     html: btn_text_select
13054                 },
13055                 {
13056                     tag : 'button',
13057                     type : 'button',
13058                     name : 'ok',
13059                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13060                     //html : 'Done'
13061                     html: btn_text_done
13062                 },
13063                 {
13064                     tag : 'button',
13065                     type : 'button',
13066                     name : 'cancel',
13067                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13068                     //html : 'Cancel'
13069                     html: btn_text_cancel
13070                 }
13071             ]
13072         };
13073         
13074         if(this.editable){
13075             buttons.cn.unshift({
13076                 tag: 'input',
13077                 cls: 'roo-select2-search-field-input'
13078             });
13079         }
13080         
13081         var _this = this;
13082         
13083         Roo.each(buttons.cn, function(c){
13084             if (_this.size) {
13085                 c.cls += ' btn-' + _this.size;
13086             }
13087
13088             if (_this.disabled) {
13089                 c.disabled = true;
13090             }
13091         });
13092         
13093         var box = {
13094             tag: 'div',
13095             cn: [
13096                 {
13097                     tag: 'input',
13098                     type : 'hidden',
13099                     cls: 'form-hidden-field'
13100                 },
13101                 {
13102                     tag: 'ul',
13103                     cls: 'roo-select2-choices',
13104                     cn:[
13105                         {
13106                             tag: 'li',
13107                             cls: 'roo-select2-search-field',
13108                             cn: [
13109                                 buttons
13110                             ]
13111                         }
13112                     ]
13113                 }
13114             ]
13115         };
13116         
13117         var combobox = {
13118             cls: 'roo-select2-container input-group roo-select2-container-multi',
13119             cn: [
13120                 box
13121 //                {
13122 //                    tag: 'ul',
13123 //                    cls: 'typeahead typeahead-long dropdown-menu',
13124 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13125 //                }
13126             ]
13127         };
13128         
13129         if(this.hasFeedback && !this.allowBlank){
13130             
13131             var feedback = {
13132                 tag: 'span',
13133                 cls: 'glyphicon form-control-feedback'
13134             };
13135
13136             combobox.cn.push(feedback);
13137         }
13138         
13139         
13140         if (align ==='left' && this.fieldLabel.length) {
13141             
13142             cfg.cls += ' roo-form-group-label-left';
13143             
13144             cfg.cn = [
13145                 {
13146                     tag : 'i',
13147                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13148                     tooltip : 'This field is required'
13149                 },
13150                 {
13151                     tag: 'label',
13152                     'for' :  id,
13153                     cls : 'control-label',
13154                     html : this.fieldLabel
13155
13156                 },
13157                 {
13158                     cls : "", 
13159                     cn: [
13160                         combobox
13161                     ]
13162                 }
13163
13164             ];
13165             
13166             var labelCfg = cfg.cn[1];
13167             var contentCfg = cfg.cn[2];
13168             
13169
13170             if(this.indicatorpos == 'right'){
13171                 
13172                 cfg.cn = [
13173                     {
13174                         tag: 'label',
13175                         'for' :  id,
13176                         cls : 'control-label',
13177                         cn : [
13178                             {
13179                                 tag : 'span',
13180                                 html : this.fieldLabel
13181                             },
13182                             {
13183                                 tag : 'i',
13184                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13185                                 tooltip : 'This field is required'
13186                             }
13187                         ]
13188                     },
13189                     {
13190                         cls : "",
13191                         cn: [
13192                             combobox
13193                         ]
13194                     }
13195
13196                 ];
13197                 
13198                 
13199                 
13200                 labelCfg = cfg.cn[0];
13201                 contentCfg = cfg.cn[1];
13202             
13203             }
13204             
13205             if(this.labelWidth > 12){
13206                 labelCfg.style = "width: " + this.labelWidth + 'px';
13207             }
13208             
13209             if(this.labelWidth < 13 && this.labelmd == 0){
13210                 this.labelmd = this.labelWidth;
13211             }
13212             
13213             if(this.labellg > 0){
13214                 labelCfg.cls += ' col-lg-' + this.labellg;
13215                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13216             }
13217             
13218             if(this.labelmd > 0){
13219                 labelCfg.cls += ' col-md-' + this.labelmd;
13220                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13221             }
13222             
13223             if(this.labelsm > 0){
13224                 labelCfg.cls += ' col-sm-' + this.labelsm;
13225                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13226             }
13227             
13228             if(this.labelxs > 0){
13229                 labelCfg.cls += ' col-xs-' + this.labelxs;
13230                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13231             }
13232                 
13233                 
13234         } else if ( this.fieldLabel.length) {
13235 //                Roo.log(" label");
13236                  cfg.cn = [
13237                     {
13238                         tag : 'i',
13239                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13240                         tooltip : 'This field is required'
13241                     },
13242                     {
13243                         tag: 'label',
13244                         //cls : 'input-group-addon',
13245                         html : this.fieldLabel
13246                     },
13247                     combobox
13248                 ];
13249                 
13250                 if(this.indicatorpos == 'right'){
13251                     cfg.cn = [
13252                         {
13253                             tag: 'label',
13254                             //cls : 'input-group-addon',
13255                             html : this.fieldLabel
13256                         },
13257                         {
13258                             tag : 'i',
13259                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13260                             tooltip : 'This field is required'
13261                         },
13262                         combobox
13263                     ];
13264                     
13265                 }
13266
13267         } else {
13268             
13269 //                Roo.log(" no label && no align");
13270                 cfg = combobox
13271                      
13272                 
13273         }
13274          
13275         var settings=this;
13276         ['xs','sm','md','lg'].map(function(size){
13277             if (settings[size]) {
13278                 cfg.cls += ' col-' + size + '-' + settings[size];
13279             }
13280         });
13281         
13282         return cfg;
13283         
13284     },
13285     
13286     _initEventsCalled : false,
13287     
13288     // private
13289     initEvents: function()
13290     {   
13291         if (this._initEventsCalled) { // as we call render... prevent looping...
13292             return;
13293         }
13294         this._initEventsCalled = true;
13295         
13296         if (!this.store) {
13297             throw "can not find store for combo";
13298         }
13299         
13300         this.indicator = this.indicatorEl();
13301         
13302         this.store = Roo.factory(this.store, Roo.data);
13303         this.store.parent = this;
13304         
13305         // if we are building from html. then this element is so complex, that we can not really
13306         // use the rendered HTML.
13307         // so we have to trash and replace the previous code.
13308         if (Roo.XComponent.build_from_html) {
13309             // remove this element....
13310             var e = this.el.dom, k=0;
13311             while (e ) { e = e.previousSibling;  ++k;}
13312
13313             this.el.remove();
13314             
13315             this.el=false;
13316             this.rendered = false;
13317             
13318             this.render(this.parent().getChildContainer(true), k);
13319         }
13320         
13321         if(Roo.isIOS && this.useNativeIOS){
13322             this.initIOSView();
13323             return;
13324         }
13325         
13326         /*
13327          * Touch Devices
13328          */
13329         
13330         if(Roo.isTouch && this.mobileTouchView){
13331             this.initTouchView();
13332             return;
13333         }
13334         
13335         if(this.tickable){
13336             this.initTickableEvents();
13337             return;
13338         }
13339         
13340         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13341         
13342         if(this.hiddenName){
13343             
13344             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13345             
13346             this.hiddenField.dom.value =
13347                 this.hiddenValue !== undefined ? this.hiddenValue :
13348                 this.value !== undefined ? this.value : '';
13349
13350             // prevent input submission
13351             this.el.dom.removeAttribute('name');
13352             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13353              
13354              
13355         }
13356         //if(Roo.isGecko){
13357         //    this.el.dom.setAttribute('autocomplete', 'off');
13358         //}
13359         
13360         var cls = 'x-combo-list';
13361         
13362         //this.list = new Roo.Layer({
13363         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13364         //});
13365         
13366         var _this = this;
13367         
13368         (function(){
13369             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13370             _this.list.setWidth(lw);
13371         }).defer(100);
13372         
13373         this.list.on('mouseover', this.onViewOver, this);
13374         this.list.on('mousemove', this.onViewMove, this);
13375         this.list.on('scroll', this.onViewScroll, this);
13376         
13377         /*
13378         this.list.swallowEvent('mousewheel');
13379         this.assetHeight = 0;
13380
13381         if(this.title){
13382             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13383             this.assetHeight += this.header.getHeight();
13384         }
13385
13386         this.innerList = this.list.createChild({cls:cls+'-inner'});
13387         this.innerList.on('mouseover', this.onViewOver, this);
13388         this.innerList.on('mousemove', this.onViewMove, this);
13389         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13390         
13391         if(this.allowBlank && !this.pageSize && !this.disableClear){
13392             this.footer = this.list.createChild({cls:cls+'-ft'});
13393             this.pageTb = new Roo.Toolbar(this.footer);
13394            
13395         }
13396         if(this.pageSize){
13397             this.footer = this.list.createChild({cls:cls+'-ft'});
13398             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13399                     {pageSize: this.pageSize});
13400             
13401         }
13402         
13403         if (this.pageTb && this.allowBlank && !this.disableClear) {
13404             var _this = this;
13405             this.pageTb.add(new Roo.Toolbar.Fill(), {
13406                 cls: 'x-btn-icon x-btn-clear',
13407                 text: '&#160;',
13408                 handler: function()
13409                 {
13410                     _this.collapse();
13411                     _this.clearValue();
13412                     _this.onSelect(false, -1);
13413                 }
13414             });
13415         }
13416         if (this.footer) {
13417             this.assetHeight += this.footer.getHeight();
13418         }
13419         */
13420             
13421         if(!this.tpl){
13422             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13423         }
13424
13425         this.view = new Roo.View(this.list, this.tpl, {
13426             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13427         });
13428         //this.view.wrapEl.setDisplayed(false);
13429         this.view.on('click', this.onViewClick, this);
13430         
13431         
13432         this.store.on('beforeload', this.onBeforeLoad, this);
13433         this.store.on('load', this.onLoad, this);
13434         this.store.on('loadexception', this.onLoadException, this);
13435         /*
13436         if(this.resizable){
13437             this.resizer = new Roo.Resizable(this.list,  {
13438                pinned:true, handles:'se'
13439             });
13440             this.resizer.on('resize', function(r, w, h){
13441                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13442                 this.listWidth = w;
13443                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13444                 this.restrictHeight();
13445             }, this);
13446             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13447         }
13448         */
13449         if(!this.editable){
13450             this.editable = true;
13451             this.setEditable(false);
13452         }
13453         
13454         /*
13455         
13456         if (typeof(this.events.add.listeners) != 'undefined') {
13457             
13458             this.addicon = this.wrap.createChild(
13459                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13460        
13461             this.addicon.on('click', function(e) {
13462                 this.fireEvent('add', this);
13463             }, this);
13464         }
13465         if (typeof(this.events.edit.listeners) != 'undefined') {
13466             
13467             this.editicon = this.wrap.createChild(
13468                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13469             if (this.addicon) {
13470                 this.editicon.setStyle('margin-left', '40px');
13471             }
13472             this.editicon.on('click', function(e) {
13473                 
13474                 // we fire even  if inothing is selected..
13475                 this.fireEvent('edit', this, this.lastData );
13476                 
13477             }, this);
13478         }
13479         */
13480         
13481         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13482             "up" : function(e){
13483                 this.inKeyMode = true;
13484                 this.selectPrev();
13485             },
13486
13487             "down" : function(e){
13488                 if(!this.isExpanded()){
13489                     this.onTriggerClick();
13490                 }else{
13491                     this.inKeyMode = true;
13492                     this.selectNext();
13493                 }
13494             },
13495
13496             "enter" : function(e){
13497 //                this.onViewClick();
13498                 //return true;
13499                 this.collapse();
13500                 
13501                 if(this.fireEvent("specialkey", this, e)){
13502                     this.onViewClick(false);
13503                 }
13504                 
13505                 return true;
13506             },
13507
13508             "esc" : function(e){
13509                 this.collapse();
13510             },
13511
13512             "tab" : function(e){
13513                 this.collapse();
13514                 
13515                 if(this.fireEvent("specialkey", this, e)){
13516                     this.onViewClick(false);
13517                 }
13518                 
13519                 return true;
13520             },
13521
13522             scope : this,
13523
13524             doRelay : function(foo, bar, hname){
13525                 if(hname == 'down' || this.scope.isExpanded()){
13526                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13527                 }
13528                 return true;
13529             },
13530
13531             forceKeyDown: true
13532         });
13533         
13534         
13535         this.queryDelay = Math.max(this.queryDelay || 10,
13536                 this.mode == 'local' ? 10 : 250);
13537         
13538         
13539         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13540         
13541         if(this.typeAhead){
13542             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13543         }
13544         if(this.editable !== false){
13545             this.inputEl().on("keyup", this.onKeyUp, this);
13546         }
13547         if(this.forceSelection){
13548             this.inputEl().on('blur', this.doForce, this);
13549         }
13550         
13551         if(this.multiple){
13552             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13553             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13554         }
13555     },
13556     
13557     initTickableEvents: function()
13558     {   
13559         this.createList();
13560         
13561         if(this.hiddenName){
13562             
13563             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13564             
13565             this.hiddenField.dom.value =
13566                 this.hiddenValue !== undefined ? this.hiddenValue :
13567                 this.value !== undefined ? this.value : '';
13568
13569             // prevent input submission
13570             this.el.dom.removeAttribute('name');
13571             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13572              
13573              
13574         }
13575         
13576 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13577         
13578         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13579         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13580         if(this.triggerList){
13581             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13582         }
13583          
13584         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13585         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13586         
13587         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13588         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13589         
13590         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13591         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13592         
13593         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13594         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13595         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13596         
13597         this.okBtn.hide();
13598         this.cancelBtn.hide();
13599         
13600         var _this = this;
13601         
13602         (function(){
13603             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13604             _this.list.setWidth(lw);
13605         }).defer(100);
13606         
13607         this.list.on('mouseover', this.onViewOver, this);
13608         this.list.on('mousemove', this.onViewMove, this);
13609         
13610         this.list.on('scroll', this.onViewScroll, this);
13611         
13612         if(!this.tpl){
13613             this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' + 
13614                 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13615         }
13616
13617         this.view = new Roo.View(this.list, this.tpl, {
13618             singleSelect:true,
13619             tickable:true,
13620             parent:this,
13621             store: this.store,
13622             selectedClass: this.selectedClass
13623         });
13624         
13625         //this.view.wrapEl.setDisplayed(false);
13626         this.view.on('click', this.onViewClick, this);
13627         
13628         
13629         
13630         this.store.on('beforeload', this.onBeforeLoad, this);
13631         this.store.on('load', this.onLoad, this);
13632         this.store.on('loadexception', this.onLoadException, this);
13633         
13634         if(this.editable){
13635             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13636                 "up" : function(e){
13637                     this.inKeyMode = true;
13638                     this.selectPrev();
13639                 },
13640
13641                 "down" : function(e){
13642                     this.inKeyMode = true;
13643                     this.selectNext();
13644                 },
13645
13646                 "enter" : function(e){
13647                     if(this.fireEvent("specialkey", this, e)){
13648                         this.onViewClick(false);
13649                     }
13650                     
13651                     return true;
13652                 },
13653
13654                 "esc" : function(e){
13655                     this.onTickableFooterButtonClick(e, false, false);
13656                 },
13657
13658                 "tab" : function(e){
13659                     this.fireEvent("specialkey", this, e);
13660                     
13661                     this.onTickableFooterButtonClick(e, false, false);
13662                     
13663                     return true;
13664                 },
13665
13666                 scope : this,
13667
13668                 doRelay : function(e, fn, key){
13669                     if(this.scope.isExpanded()){
13670                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13671                     }
13672                     return true;
13673                 },
13674
13675                 forceKeyDown: true
13676             });
13677         }
13678         
13679         this.queryDelay = Math.max(this.queryDelay || 10,
13680                 this.mode == 'local' ? 10 : 250);
13681         
13682         
13683         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13684         
13685         if(this.typeAhead){
13686             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13687         }
13688         
13689         if(this.editable !== false){
13690             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13691         }
13692         
13693         this.indicator = this.indicatorEl();
13694         
13695         if(this.indicator){
13696             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13697             this.indicator.hide();
13698         }
13699         
13700     },
13701
13702     onDestroy : function(){
13703         if(this.view){
13704             this.view.setStore(null);
13705             this.view.el.removeAllListeners();
13706             this.view.el.remove();
13707             this.view.purgeListeners();
13708         }
13709         if(this.list){
13710             this.list.dom.innerHTML  = '';
13711         }
13712         
13713         if(this.store){
13714             this.store.un('beforeload', this.onBeforeLoad, this);
13715             this.store.un('load', this.onLoad, this);
13716             this.store.un('loadexception', this.onLoadException, this);
13717         }
13718         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13719     },
13720
13721     // private
13722     fireKey : function(e){
13723         if(e.isNavKeyPress() && !this.list.isVisible()){
13724             this.fireEvent("specialkey", this, e);
13725         }
13726     },
13727
13728     // private
13729     onResize: function(w, h){
13730 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13731 //        
13732 //        if(typeof w != 'number'){
13733 //            // we do not handle it!?!?
13734 //            return;
13735 //        }
13736 //        var tw = this.trigger.getWidth();
13737 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13738 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13739 //        var x = w - tw;
13740 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13741 //            
13742 //        //this.trigger.setStyle('left', x+'px');
13743 //        
13744 //        if(this.list && this.listWidth === undefined){
13745 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13746 //            this.list.setWidth(lw);
13747 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13748 //        }
13749         
13750     
13751         
13752     },
13753
13754     /**
13755      * Allow or prevent the user from directly editing the field text.  If false is passed,
13756      * the user will only be able to select from the items defined in the dropdown list.  This method
13757      * is the runtime equivalent of setting the 'editable' config option at config time.
13758      * @param {Boolean} value True to allow the user to directly edit the field text
13759      */
13760     setEditable : function(value){
13761         if(value == this.editable){
13762             return;
13763         }
13764         this.editable = value;
13765         if(!value){
13766             this.inputEl().dom.setAttribute('readOnly', true);
13767             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13768             this.inputEl().addClass('x-combo-noedit');
13769         }else{
13770             this.inputEl().dom.setAttribute('readOnly', false);
13771             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13772             this.inputEl().removeClass('x-combo-noedit');
13773         }
13774     },
13775
13776     // private
13777     
13778     onBeforeLoad : function(combo,opts){
13779         if(!this.hasFocus){
13780             return;
13781         }
13782          if (!opts.add) {
13783             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13784          }
13785         this.restrictHeight();
13786         this.selectedIndex = -1;
13787     },
13788
13789     // private
13790     onLoad : function(){
13791         
13792         this.hasQuery = false;
13793         
13794         if(!this.hasFocus){
13795             return;
13796         }
13797         
13798         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13799             this.loading.hide();
13800         }
13801         
13802         if(this.store.getCount() > 0){
13803             
13804             this.expand();
13805             this.restrictHeight();
13806             if(this.lastQuery == this.allQuery){
13807                 if(this.editable && !this.tickable){
13808                     this.inputEl().dom.select();
13809                 }
13810                 
13811                 if(
13812                     !this.selectByValue(this.value, true) &&
13813                     this.autoFocus && 
13814                     (
13815                         !this.store.lastOptions ||
13816                         typeof(this.store.lastOptions.add) == 'undefined' || 
13817                         this.store.lastOptions.add != true
13818                     )
13819                 ){
13820                     this.select(0, true);
13821                 }
13822             }else{
13823                 if(this.autoFocus){
13824                     this.selectNext();
13825                 }
13826                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13827                     this.taTask.delay(this.typeAheadDelay);
13828                 }
13829             }
13830         }else{
13831             this.onEmptyResults();
13832         }
13833         
13834         //this.el.focus();
13835     },
13836     // private
13837     onLoadException : function()
13838     {
13839         this.hasQuery = false;
13840         
13841         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13842             this.loading.hide();
13843         }
13844         
13845         if(this.tickable && this.editable){
13846             return;
13847         }
13848         
13849         this.collapse();
13850         // only causes errors at present
13851         //Roo.log(this.store.reader.jsonData);
13852         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13853             // fixme
13854             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13855         //}
13856         
13857         
13858     },
13859     // private
13860     onTypeAhead : function(){
13861         if(this.store.getCount() > 0){
13862             var r = this.store.getAt(0);
13863             var newValue = r.data[this.displayField];
13864             var len = newValue.length;
13865             var selStart = this.getRawValue().length;
13866             
13867             if(selStart != len){
13868                 this.setRawValue(newValue);
13869                 this.selectText(selStart, newValue.length);
13870             }
13871         }
13872     },
13873
13874     // private
13875     onSelect : function(record, index){
13876         
13877         if(this.fireEvent('beforeselect', this, record, index) !== false){
13878         
13879             this.setFromData(index > -1 ? record.data : false);
13880             
13881             this.collapse();
13882             this.fireEvent('select', this, record, index);
13883         }
13884     },
13885
13886     /**
13887      * Returns the currently selected field value or empty string if no value is set.
13888      * @return {String} value The selected value
13889      */
13890     getValue : function()
13891     {
13892         if(Roo.isIOS && this.useNativeIOS){
13893             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13894         }
13895         
13896         if(this.multiple){
13897             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13898         }
13899         
13900         if(this.valueField){
13901             return typeof this.value != 'undefined' ? this.value : '';
13902         }else{
13903             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13904         }
13905     },
13906     
13907     getRawValue : function()
13908     {
13909         if(Roo.isIOS && this.useNativeIOS){
13910             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13911         }
13912         
13913         var v = this.inputEl().getValue();
13914         
13915         return v;
13916     },
13917
13918     /**
13919      * Clears any text/value currently set in the field
13920      */
13921     clearValue : function(){
13922         
13923         if(this.hiddenField){
13924             this.hiddenField.dom.value = '';
13925         }
13926         this.value = '';
13927         this.setRawValue('');
13928         this.lastSelectionText = '';
13929         this.lastData = false;
13930         
13931         var close = this.closeTriggerEl();
13932         
13933         if(close){
13934             close.hide();
13935         }
13936         
13937         this.validate();
13938         
13939     },
13940
13941     /**
13942      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13943      * will be displayed in the field.  If the value does not match the data value of an existing item,
13944      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13945      * Otherwise the field will be blank (although the value will still be set).
13946      * @param {String} value The value to match
13947      */
13948     setValue : function(v)
13949     {
13950         if(Roo.isIOS && this.useNativeIOS){
13951             this.setIOSValue(v);
13952             return;
13953         }
13954         
13955         if(this.multiple){
13956             this.syncValue();
13957             return;
13958         }
13959         
13960         var text = v;
13961         if(this.valueField){
13962             var r = this.findRecord(this.valueField, v);
13963             if(r){
13964                 text = r.data[this.displayField];
13965             }else if(this.valueNotFoundText !== undefined){
13966                 text = this.valueNotFoundText;
13967             }
13968         }
13969         this.lastSelectionText = text;
13970         if(this.hiddenField){
13971             this.hiddenField.dom.value = v;
13972         }
13973         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13974         this.value = v;
13975         
13976         var close = this.closeTriggerEl();
13977         
13978         if(close){
13979             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13980         }
13981         
13982         this.validate();
13983     },
13984     /**
13985      * @property {Object} the last set data for the element
13986      */
13987     
13988     lastData : false,
13989     /**
13990      * Sets the value of the field based on a object which is related to the record format for the store.
13991      * @param {Object} value the value to set as. or false on reset?
13992      */
13993     setFromData : function(o){
13994         
13995         if(this.multiple){
13996             this.addItem(o);
13997             return;
13998         }
13999             
14000         var dv = ''; // display value
14001         var vv = ''; // value value..
14002         this.lastData = o;
14003         if (this.displayField) {
14004             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14005         } else {
14006             // this is an error condition!!!
14007             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14008         }
14009         
14010         if(this.valueField){
14011             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14012         }
14013         
14014         var close = this.closeTriggerEl();
14015         
14016         if(close){
14017             if(dv.length || vv * 1 > 0){
14018                 close.show() ;
14019                 this.blockFocus=true;
14020             } else {
14021                 close.hide();
14022             }             
14023         }
14024         
14025         if(this.hiddenField){
14026             this.hiddenField.dom.value = vv;
14027             
14028             this.lastSelectionText = dv;
14029             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14030             this.value = vv;
14031             return;
14032         }
14033         // no hidden field.. - we store the value in 'value', but still display
14034         // display field!!!!
14035         this.lastSelectionText = dv;
14036         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14037         this.value = vv;
14038         
14039         
14040         
14041     },
14042     // private
14043     reset : function(){
14044         // overridden so that last data is reset..
14045         
14046         if(this.multiple){
14047             this.clearItem();
14048             return;
14049         }
14050         
14051         this.setValue(this.originalValue);
14052         //this.clearInvalid();
14053         this.lastData = false;
14054         if (this.view) {
14055             this.view.clearSelections();
14056         }
14057         
14058         this.validate();
14059     },
14060     // private
14061     findRecord : function(prop, value){
14062         var record;
14063         if(this.store.getCount() > 0){
14064             this.store.each(function(r){
14065                 if(r.data[prop] == value){
14066                     record = r;
14067                     return false;
14068                 }
14069                 return true;
14070             });
14071         }
14072         return record;
14073     },
14074     
14075     getName: function()
14076     {
14077         // returns hidden if it's set..
14078         if (!this.rendered) {return ''};
14079         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14080         
14081     },
14082     // private
14083     onViewMove : function(e, t){
14084         this.inKeyMode = false;
14085     },
14086
14087     // private
14088     onViewOver : function(e, t){
14089         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14090             return;
14091         }
14092         var item = this.view.findItemFromChild(t);
14093         
14094         if(item){
14095             var index = this.view.indexOf(item);
14096             this.select(index, false);
14097         }
14098     },
14099
14100     // private
14101     onViewClick : function(view, doFocus, el, e)
14102     {
14103         var index = this.view.getSelectedIndexes()[0];
14104         
14105         var r = this.store.getAt(index);
14106         
14107         if(this.tickable){
14108             
14109             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14110                 return;
14111             }
14112             
14113             var rm = false;
14114             var _this = this;
14115             
14116             Roo.each(this.tickItems, function(v,k){
14117                 
14118                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14119                     Roo.log(v);
14120                     _this.tickItems.splice(k, 1);
14121                     
14122                     if(typeof(e) == 'undefined' && view == false){
14123                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14124                     }
14125                     
14126                     rm = true;
14127                     return;
14128                 }
14129             });
14130             
14131             if(rm){
14132                 return;
14133             }
14134             
14135             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14136                 this.tickItems.push(r.data);
14137             }
14138             
14139             if(typeof(e) == 'undefined' && view == false){
14140                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14141             }
14142                     
14143             return;
14144         }
14145         
14146         if(r){
14147             this.onSelect(r, index);
14148         }
14149         if(doFocus !== false && !this.blockFocus){
14150             this.inputEl().focus();
14151         }
14152     },
14153
14154     // private
14155     restrictHeight : function(){
14156         //this.innerList.dom.style.height = '';
14157         //var inner = this.innerList.dom;
14158         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14159         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14160         //this.list.beginUpdate();
14161         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14162         this.list.alignTo(this.inputEl(), this.listAlign);
14163         this.list.alignTo(this.inputEl(), this.listAlign);
14164         //this.list.endUpdate();
14165     },
14166
14167     // private
14168     onEmptyResults : function(){
14169         
14170         if(this.tickable && this.editable){
14171             this.hasFocus = false;
14172             this.restrictHeight();
14173             return;
14174         }
14175         
14176         this.collapse();
14177     },
14178
14179     /**
14180      * Returns true if the dropdown list is expanded, else false.
14181      */
14182     isExpanded : function(){
14183         return this.list.isVisible();
14184     },
14185
14186     /**
14187      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14188      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14189      * @param {String} value The data value of the item to select
14190      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14191      * selected item if it is not currently in view (defaults to true)
14192      * @return {Boolean} True if the value matched an item in the list, else false
14193      */
14194     selectByValue : function(v, scrollIntoView){
14195         if(v !== undefined && v !== null){
14196             var r = this.findRecord(this.valueField || this.displayField, v);
14197             if(r){
14198                 this.select(this.store.indexOf(r), scrollIntoView);
14199                 return true;
14200             }
14201         }
14202         return false;
14203     },
14204
14205     /**
14206      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14207      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14208      * @param {Number} index The zero-based index of the list item to select
14209      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14210      * selected item if it is not currently in view (defaults to true)
14211      */
14212     select : function(index, scrollIntoView){
14213         this.selectedIndex = index;
14214         this.view.select(index);
14215         if(scrollIntoView !== false){
14216             var el = this.view.getNode(index);
14217             /*
14218              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14219              */
14220             if(el){
14221                 this.list.scrollChildIntoView(el, false);
14222             }
14223         }
14224     },
14225
14226     // private
14227     selectNext : function(){
14228         var ct = this.store.getCount();
14229         if(ct > 0){
14230             if(this.selectedIndex == -1){
14231                 this.select(0);
14232             }else if(this.selectedIndex < ct-1){
14233                 this.select(this.selectedIndex+1);
14234             }
14235         }
14236     },
14237
14238     // private
14239     selectPrev : function(){
14240         var ct = this.store.getCount();
14241         if(ct > 0){
14242             if(this.selectedIndex == -1){
14243                 this.select(0);
14244             }else if(this.selectedIndex != 0){
14245                 this.select(this.selectedIndex-1);
14246             }
14247         }
14248     },
14249
14250     // private
14251     onKeyUp : function(e){
14252         if(this.editable !== false && !e.isSpecialKey()){
14253             this.lastKey = e.getKey();
14254             this.dqTask.delay(this.queryDelay);
14255         }
14256     },
14257
14258     // private
14259     validateBlur : function(){
14260         return !this.list || !this.list.isVisible();   
14261     },
14262
14263     // private
14264     initQuery : function(){
14265         
14266         var v = this.getRawValue();
14267         
14268         if(this.tickable && this.editable){
14269             v = this.tickableInputEl().getValue();
14270         }
14271         
14272         this.doQuery(v);
14273     },
14274
14275     // private
14276     doForce : function(){
14277         if(this.inputEl().dom.value.length > 0){
14278             this.inputEl().dom.value =
14279                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14280              
14281         }
14282     },
14283
14284     /**
14285      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14286      * query allowing the query action to be canceled if needed.
14287      * @param {String} query The SQL query to execute
14288      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14289      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14290      * saved in the current store (defaults to false)
14291      */
14292     doQuery : function(q, forceAll){
14293         
14294         if(q === undefined || q === null){
14295             q = '';
14296         }
14297         var qe = {
14298             query: q,
14299             forceAll: forceAll,
14300             combo: this,
14301             cancel:false
14302         };
14303         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14304             return false;
14305         }
14306         q = qe.query;
14307         
14308         forceAll = qe.forceAll;
14309         if(forceAll === true || (q.length >= this.minChars)){
14310             
14311             this.hasQuery = true;
14312             
14313             if(this.lastQuery != q || this.alwaysQuery){
14314                 this.lastQuery = q;
14315                 if(this.mode == 'local'){
14316                     this.selectedIndex = -1;
14317                     if(forceAll){
14318                         this.store.clearFilter();
14319                     }else{
14320                         
14321                         if(this.specialFilter){
14322                             this.fireEvent('specialfilter', this);
14323                             this.onLoad();
14324                             return;
14325                         }
14326                         
14327                         this.store.filter(this.displayField, q);
14328                     }
14329                     
14330                     this.store.fireEvent("datachanged", this.store);
14331                     
14332                     this.onLoad();
14333                     
14334                     
14335                 }else{
14336                     
14337                     this.store.baseParams[this.queryParam] = q;
14338                     
14339                     var options = {params : this.getParams(q)};
14340                     
14341                     if(this.loadNext){
14342                         options.add = true;
14343                         options.params.start = this.page * this.pageSize;
14344                     }
14345                     
14346                     this.store.load(options);
14347                     
14348                     /*
14349                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14350                      *  we should expand the list on onLoad
14351                      *  so command out it
14352                      */
14353 //                    this.expand();
14354                 }
14355             }else{
14356                 this.selectedIndex = -1;
14357                 this.onLoad();   
14358             }
14359         }
14360         
14361         this.loadNext = false;
14362     },
14363     
14364     // private
14365     getParams : function(q){
14366         var p = {};
14367         //p[this.queryParam] = q;
14368         
14369         if(this.pageSize){
14370             p.start = 0;
14371             p.limit = this.pageSize;
14372         }
14373         return p;
14374     },
14375
14376     /**
14377      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14378      */
14379     collapse : function(){
14380         if(!this.isExpanded()){
14381             return;
14382         }
14383         
14384         this.list.hide();
14385         
14386         this.hasFocus = false;
14387         
14388         if(this.tickable){
14389             this.okBtn.hide();
14390             this.cancelBtn.hide();
14391             this.trigger.show();
14392             
14393             if(this.editable){
14394                 this.tickableInputEl().dom.value = '';
14395                 this.tickableInputEl().blur();
14396             }
14397             
14398         }
14399         
14400         Roo.get(document).un('mousedown', this.collapseIf, this);
14401         Roo.get(document).un('mousewheel', this.collapseIf, this);
14402         if (!this.editable) {
14403             Roo.get(document).un('keydown', this.listKeyPress, this);
14404         }
14405         this.fireEvent('collapse', this);
14406         
14407         this.validate();
14408     },
14409
14410     // private
14411     collapseIf : function(e){
14412         var in_combo  = e.within(this.el);
14413         var in_list =  e.within(this.list);
14414         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14415         
14416         if (in_combo || in_list || is_list) {
14417             //e.stopPropagation();
14418             return;
14419         }
14420         
14421         if(this.tickable){
14422             this.onTickableFooterButtonClick(e, false, false);
14423         }
14424
14425         this.collapse();
14426         
14427     },
14428
14429     /**
14430      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14431      */
14432     expand : function(){
14433        
14434         if(this.isExpanded() || !this.hasFocus){
14435             return;
14436         }
14437         
14438         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14439         this.list.setWidth(lw);
14440         
14441         Roo.log('expand');
14442         
14443         this.list.show();
14444         
14445         this.restrictHeight();
14446         
14447         if(this.tickable){
14448             
14449             this.tickItems = Roo.apply([], this.item);
14450             
14451             this.okBtn.show();
14452             this.cancelBtn.show();
14453             this.trigger.hide();
14454             
14455             if(this.editable){
14456                 this.tickableInputEl().focus();
14457             }
14458             
14459         }
14460         
14461         Roo.get(document).on('mousedown', this.collapseIf, this);
14462         Roo.get(document).on('mousewheel', this.collapseIf, this);
14463         if (!this.editable) {
14464             Roo.get(document).on('keydown', this.listKeyPress, this);
14465         }
14466         
14467         this.fireEvent('expand', this);
14468     },
14469
14470     // private
14471     // Implements the default empty TriggerField.onTriggerClick function
14472     onTriggerClick : function(e)
14473     {
14474         Roo.log('trigger click');
14475         
14476         if(this.disabled || !this.triggerList){
14477             return;
14478         }
14479         
14480         this.page = 0;
14481         this.loadNext = false;
14482         
14483         if(this.isExpanded()){
14484             this.collapse();
14485             if (!this.blockFocus) {
14486                 this.inputEl().focus();
14487             }
14488             
14489         }else {
14490             this.hasFocus = true;
14491             if(this.triggerAction == 'all') {
14492                 this.doQuery(this.allQuery, true);
14493             } else {
14494                 this.doQuery(this.getRawValue());
14495             }
14496             if (!this.blockFocus) {
14497                 this.inputEl().focus();
14498             }
14499         }
14500     },
14501     
14502     onTickableTriggerClick : function(e)
14503     {
14504         if(this.disabled){
14505             return;
14506         }
14507         
14508         this.page = 0;
14509         this.loadNext = false;
14510         this.hasFocus = true;
14511         
14512         if(this.triggerAction == 'all') {
14513             this.doQuery(this.allQuery, true);
14514         } else {
14515             this.doQuery(this.getRawValue());
14516         }
14517     },
14518     
14519     onSearchFieldClick : function(e)
14520     {
14521         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14522             this.onTickableFooterButtonClick(e, false, false);
14523             return;
14524         }
14525         
14526         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14527             return;
14528         }
14529         
14530         this.page = 0;
14531         this.loadNext = false;
14532         this.hasFocus = true;
14533         
14534         if(this.triggerAction == 'all') {
14535             this.doQuery(this.allQuery, true);
14536         } else {
14537             this.doQuery(this.getRawValue());
14538         }
14539     },
14540     
14541     listKeyPress : function(e)
14542     {
14543         //Roo.log('listkeypress');
14544         // scroll to first matching element based on key pres..
14545         if (e.isSpecialKey()) {
14546             return false;
14547         }
14548         var k = String.fromCharCode(e.getKey()).toUpperCase();
14549         //Roo.log(k);
14550         var match  = false;
14551         var csel = this.view.getSelectedNodes();
14552         var cselitem = false;
14553         if (csel.length) {
14554             var ix = this.view.indexOf(csel[0]);
14555             cselitem  = this.store.getAt(ix);
14556             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14557                 cselitem = false;
14558             }
14559             
14560         }
14561         
14562         this.store.each(function(v) { 
14563             if (cselitem) {
14564                 // start at existing selection.
14565                 if (cselitem.id == v.id) {
14566                     cselitem = false;
14567                 }
14568                 return true;
14569             }
14570                 
14571             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14572                 match = this.store.indexOf(v);
14573                 return false;
14574             }
14575             return true;
14576         }, this);
14577         
14578         if (match === false) {
14579             return true; // no more action?
14580         }
14581         // scroll to?
14582         this.view.select(match);
14583         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14584         sn.scrollIntoView(sn.dom.parentNode, false);
14585     },
14586     
14587     onViewScroll : function(e, t){
14588         
14589         if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
14590             return;
14591         }
14592         
14593         this.hasQuery = true;
14594         
14595         this.loading = this.list.select('.loading', true).first();
14596         
14597         if(this.loading === null){
14598             this.list.createChild({
14599                 tag: 'div',
14600                 cls: 'loading roo-select2-more-results roo-select2-active',
14601                 html: 'Loading more results...'
14602             });
14603             
14604             this.loading = this.list.select('.loading', true).first();
14605             
14606             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14607             
14608             this.loading.hide();
14609         }
14610         
14611         this.loading.show();
14612         
14613         var _combo = this;
14614         
14615         this.page++;
14616         this.loadNext = true;
14617         
14618         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14619         
14620         return;
14621     },
14622     
14623     addItem : function(o)
14624     {   
14625         var dv = ''; // display value
14626         
14627         if (this.displayField) {
14628             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14629         } else {
14630             // this is an error condition!!!
14631             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14632         }
14633         
14634         if(!dv.length){
14635             return;
14636         }
14637         
14638         var choice = this.choices.createChild({
14639             tag: 'li',
14640             cls: 'roo-select2-search-choice',
14641             cn: [
14642                 {
14643                     tag: 'div',
14644                     html: dv
14645                 },
14646                 {
14647                     tag: 'a',
14648                     href: '#',
14649                     cls: 'roo-select2-search-choice-close fa fa-times',
14650                     tabindex: '-1'
14651                 }
14652             ]
14653             
14654         }, this.searchField);
14655         
14656         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14657         
14658         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14659         
14660         this.item.push(o);
14661         
14662         this.lastData = o;
14663         
14664         this.syncValue();
14665         
14666         this.inputEl().dom.value = '';
14667         
14668         this.validate();
14669     },
14670     
14671     onRemoveItem : function(e, _self, o)
14672     {
14673         e.preventDefault();
14674         
14675         this.lastItem = Roo.apply([], this.item);
14676         
14677         var index = this.item.indexOf(o.data) * 1;
14678         
14679         if( index < 0){
14680             Roo.log('not this item?!');
14681             return;
14682         }
14683         
14684         this.item.splice(index, 1);
14685         o.item.remove();
14686         
14687         this.syncValue();
14688         
14689         this.fireEvent('remove', this, e);
14690         
14691         this.validate();
14692         
14693     },
14694     
14695     syncValue : function()
14696     {
14697         if(!this.item.length){
14698             this.clearValue();
14699             return;
14700         }
14701             
14702         var value = [];
14703         var _this = this;
14704         Roo.each(this.item, function(i){
14705             if(_this.valueField){
14706                 value.push(i[_this.valueField]);
14707                 return;
14708             }
14709
14710             value.push(i);
14711         });
14712
14713         this.value = value.join(',');
14714
14715         if(this.hiddenField){
14716             this.hiddenField.dom.value = this.value;
14717         }
14718         
14719         this.store.fireEvent("datachanged", this.store);
14720         
14721         this.validate();
14722     },
14723     
14724     clearItem : function()
14725     {
14726         if(!this.multiple){
14727             return;
14728         }
14729         
14730         this.item = [];
14731         
14732         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14733            c.remove();
14734         });
14735         
14736         this.syncValue();
14737         
14738         this.validate();
14739         
14740         if(this.tickable && !Roo.isTouch){
14741             this.view.refresh();
14742         }
14743     },
14744     
14745     inputEl: function ()
14746     {
14747         if(Roo.isIOS && this.useNativeIOS){
14748             return this.el.select('select.roo-ios-select', true).first();
14749         }
14750         
14751         if(Roo.isTouch && this.mobileTouchView){
14752             return this.el.select('input.form-control',true).first();
14753         }
14754         
14755         if(this.tickable){
14756             return this.searchField;
14757         }
14758         
14759         return this.el.select('input.form-control',true).first();
14760     },
14761     
14762     onTickableFooterButtonClick : function(e, btn, el)
14763     {
14764         e.preventDefault();
14765         
14766         this.lastItem = Roo.apply([], this.item);
14767         
14768         if(btn && btn.name == 'cancel'){
14769             this.tickItems = Roo.apply([], this.item);
14770             this.collapse();
14771             return;
14772         }
14773         
14774         this.clearItem();
14775         
14776         var _this = this;
14777         
14778         Roo.each(this.tickItems, function(o){
14779             _this.addItem(o);
14780         });
14781         
14782         this.collapse();
14783         
14784     },
14785     
14786     validate : function()
14787     {
14788         if(this.getVisibilityEl().hasClass('hidden')){
14789             return true;
14790         }
14791         
14792         var v = this.getRawValue();
14793         
14794         if(this.multiple){
14795             v = this.getValue();
14796         }
14797         
14798         if(this.disabled || this.allowBlank || v.length){
14799             this.markValid();
14800             return true;
14801         }
14802         
14803         this.markInvalid();
14804         return false;
14805     },
14806     
14807     tickableInputEl : function()
14808     {
14809         if(!this.tickable || !this.editable){
14810             return this.inputEl();
14811         }
14812         
14813         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14814     },
14815     
14816     
14817     getAutoCreateTouchView : function()
14818     {
14819         var id = Roo.id();
14820         
14821         var cfg = {
14822             cls: 'form-group' //input-group
14823         };
14824         
14825         var input =  {
14826             tag: 'input',
14827             id : id,
14828             type : this.inputType,
14829             cls : 'form-control x-combo-noedit',
14830             autocomplete: 'new-password',
14831             placeholder : this.placeholder || '',
14832             readonly : true
14833         };
14834         
14835         if (this.name) {
14836             input.name = this.name;
14837         }
14838         
14839         if (this.size) {
14840             input.cls += ' input-' + this.size;
14841         }
14842         
14843         if (this.disabled) {
14844             input.disabled = true;
14845         }
14846         
14847         var inputblock = {
14848             cls : '',
14849             cn : [
14850                 input
14851             ]
14852         };
14853         
14854         if(this.before){
14855             inputblock.cls += ' input-group';
14856             
14857             inputblock.cn.unshift({
14858                 tag :'span',
14859                 cls : 'input-group-addon',
14860                 html : this.before
14861             });
14862         }
14863         
14864         if(this.removable && !this.multiple){
14865             inputblock.cls += ' roo-removable';
14866             
14867             inputblock.cn.push({
14868                 tag: 'button',
14869                 html : 'x',
14870                 cls : 'roo-combo-removable-btn close'
14871             });
14872         }
14873
14874         if(this.hasFeedback && !this.allowBlank){
14875             
14876             inputblock.cls += ' has-feedback';
14877             
14878             inputblock.cn.push({
14879                 tag: 'span',
14880                 cls: 'glyphicon form-control-feedback'
14881             });
14882             
14883         }
14884         
14885         if (this.after) {
14886             
14887             inputblock.cls += (this.before) ? '' : ' input-group';
14888             
14889             inputblock.cn.push({
14890                 tag :'span',
14891                 cls : 'input-group-addon',
14892                 html : this.after
14893             });
14894         }
14895
14896         var box = {
14897             tag: 'div',
14898             cn: [
14899                 {
14900                     tag: 'input',
14901                     type : 'hidden',
14902                     cls: 'form-hidden-field'
14903                 },
14904                 inputblock
14905             ]
14906             
14907         };
14908         
14909         if(this.multiple){
14910             box = {
14911                 tag: 'div',
14912                 cn: [
14913                     {
14914                         tag: 'input',
14915                         type : 'hidden',
14916                         cls: 'form-hidden-field'
14917                     },
14918                     {
14919                         tag: 'ul',
14920                         cls: 'roo-select2-choices',
14921                         cn:[
14922                             {
14923                                 tag: 'li',
14924                                 cls: 'roo-select2-search-field',
14925                                 cn: [
14926
14927                                     inputblock
14928                                 ]
14929                             }
14930                         ]
14931                     }
14932                 ]
14933             }
14934         };
14935         
14936         var combobox = {
14937             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14938             cn: [
14939                 box
14940             ]
14941         };
14942         
14943         if(!this.multiple && this.showToggleBtn){
14944             
14945             var caret = {
14946                         tag: 'span',
14947                         cls: 'caret'
14948             };
14949             
14950             if (this.caret != false) {
14951                 caret = {
14952                      tag: 'i',
14953                      cls: 'fa fa-' + this.caret
14954                 };
14955                 
14956             }
14957             
14958             combobox.cn.push({
14959                 tag :'span',
14960                 cls : 'input-group-addon btn dropdown-toggle',
14961                 cn : [
14962                     caret,
14963                     {
14964                         tag: 'span',
14965                         cls: 'combobox-clear',
14966                         cn  : [
14967                             {
14968                                 tag : 'i',
14969                                 cls: 'icon-remove'
14970                             }
14971                         ]
14972                     }
14973                 ]
14974
14975             })
14976         }
14977         
14978         if(this.multiple){
14979             combobox.cls += ' roo-select2-container-multi';
14980         }
14981         
14982         var align = this.labelAlign || this.parentLabelAlign();
14983         
14984         if (align ==='left' && this.fieldLabel.length) {
14985
14986             cfg.cn = [
14987                 {
14988                    tag : 'i',
14989                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14990                    tooltip : 'This field is required'
14991                 },
14992                 {
14993                     tag: 'label',
14994                     cls : 'control-label',
14995                     html : this.fieldLabel
14996
14997                 },
14998                 {
14999                     cls : '', 
15000                     cn: [
15001                         combobox
15002                     ]
15003                 }
15004             ];
15005             
15006             var labelCfg = cfg.cn[1];
15007             var contentCfg = cfg.cn[2];
15008             
15009
15010             if(this.indicatorpos == 'right'){
15011                 cfg.cn = [
15012                     {
15013                         tag: 'label',
15014                         'for' :  id,
15015                         cls : 'control-label',
15016                         cn : [
15017                             {
15018                                 tag : 'span',
15019                                 html : this.fieldLabel
15020                             },
15021                             {
15022                                 tag : 'i',
15023                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15024                                 tooltip : 'This field is required'
15025                             }
15026                         ]
15027                     },
15028                     {
15029                         cls : "",
15030                         cn: [
15031                             combobox
15032                         ]
15033                     }
15034
15035                 ];
15036                 
15037                 labelCfg = cfg.cn[0];
15038                 contentCfg = cfg.cn[1];
15039             }
15040             
15041            
15042             
15043             if(this.labelWidth > 12){
15044                 labelCfg.style = "width: " + this.labelWidth + 'px';
15045             }
15046             
15047             if(this.labelWidth < 13 && this.labelmd == 0){
15048                 this.labelmd = this.labelWidth;
15049             }
15050             
15051             if(this.labellg > 0){
15052                 labelCfg.cls += ' col-lg-' + this.labellg;
15053                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15054             }
15055             
15056             if(this.labelmd > 0){
15057                 labelCfg.cls += ' col-md-' + this.labelmd;
15058                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15059             }
15060             
15061             if(this.labelsm > 0){
15062                 labelCfg.cls += ' col-sm-' + this.labelsm;
15063                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15064             }
15065             
15066             if(this.labelxs > 0){
15067                 labelCfg.cls += ' col-xs-' + this.labelxs;
15068                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15069             }
15070                 
15071                 
15072         } else if ( this.fieldLabel.length) {
15073             cfg.cn = [
15074                 {
15075                    tag : 'i',
15076                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15077                    tooltip : 'This field is required'
15078                 },
15079                 {
15080                     tag: 'label',
15081                     cls : 'control-label',
15082                     html : this.fieldLabel
15083
15084                 },
15085                 {
15086                     cls : '', 
15087                     cn: [
15088                         combobox
15089                     ]
15090                 }
15091             ];
15092             
15093             if(this.indicatorpos == 'right'){
15094                 cfg.cn = [
15095                     {
15096                         tag: 'label',
15097                         cls : 'control-label',
15098                         html : this.fieldLabel,
15099                         cn : [
15100                             {
15101                                tag : 'i',
15102                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15103                                tooltip : 'This field is required'
15104                             }
15105                         ]
15106                     },
15107                     {
15108                         cls : '', 
15109                         cn: [
15110                             combobox
15111                         ]
15112                     }
15113                 ];
15114             }
15115         } else {
15116             cfg.cn = combobox;    
15117         }
15118         
15119         
15120         var settings = this;
15121         
15122         ['xs','sm','md','lg'].map(function(size){
15123             if (settings[size]) {
15124                 cfg.cls += ' col-' + size + '-' + settings[size];
15125             }
15126         });
15127         
15128         return cfg;
15129     },
15130     
15131     initTouchView : function()
15132     {
15133         this.renderTouchView();
15134         
15135         this.touchViewEl.on('scroll', function(){
15136             this.el.dom.scrollTop = 0;
15137         }, this);
15138         
15139         this.originalValue = this.getValue();
15140         
15141         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15142         
15143         this.inputEl().on("click", this.showTouchView, this);
15144         if (this.triggerEl) {
15145             this.triggerEl.on("click", this.showTouchView, this);
15146         }
15147         
15148         
15149         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15150         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15151         
15152         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15153         
15154         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15155         this.store.on('load', this.onTouchViewLoad, this);
15156         this.store.on('loadexception', this.onTouchViewLoadException, this);
15157         
15158         if(this.hiddenName){
15159             
15160             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15161             
15162             this.hiddenField.dom.value =
15163                 this.hiddenValue !== undefined ? this.hiddenValue :
15164                 this.value !== undefined ? this.value : '';
15165         
15166             this.el.dom.removeAttribute('name');
15167             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15168         }
15169         
15170         if(this.multiple){
15171             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15172             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15173         }
15174         
15175         if(this.removable && !this.multiple){
15176             var close = this.closeTriggerEl();
15177             if(close){
15178                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15179                 close.on('click', this.removeBtnClick, this, close);
15180             }
15181         }
15182         /*
15183          * fix the bug in Safari iOS8
15184          */
15185         this.inputEl().on("focus", function(e){
15186             document.activeElement.blur();
15187         }, this);
15188         
15189         return;
15190         
15191         
15192     },
15193     
15194     renderTouchView : function()
15195     {
15196         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15197         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15198         
15199         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15200         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15201         
15202         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15203         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15204         this.touchViewBodyEl.setStyle('overflow', 'auto');
15205         
15206         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15207         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15208         
15209         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15210         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15211         
15212     },
15213     
15214     showTouchView : function()
15215     {
15216         if(this.disabled){
15217             return;
15218         }
15219         
15220         this.touchViewHeaderEl.hide();
15221
15222         if(this.modalTitle.length){
15223             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15224             this.touchViewHeaderEl.show();
15225         }
15226
15227         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15228         this.touchViewEl.show();
15229
15230         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15231         
15232         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15233         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15234
15235         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15236
15237         if(this.modalTitle.length){
15238             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15239         }
15240         
15241         this.touchViewBodyEl.setHeight(bodyHeight);
15242
15243         if(this.animate){
15244             var _this = this;
15245             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15246         }else{
15247             this.touchViewEl.addClass('in');
15248         }
15249
15250         this.doTouchViewQuery();
15251         
15252     },
15253     
15254     hideTouchView : function()
15255     {
15256         this.touchViewEl.removeClass('in');
15257
15258         if(this.animate){
15259             var _this = this;
15260             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15261         }else{
15262             this.touchViewEl.setStyle('display', 'none');
15263         }
15264         
15265     },
15266     
15267     setTouchViewValue : function()
15268     {
15269         if(this.multiple){
15270             this.clearItem();
15271         
15272             var _this = this;
15273
15274             Roo.each(this.tickItems, function(o){
15275                 this.addItem(o);
15276             }, this);
15277         }
15278         
15279         this.hideTouchView();
15280     },
15281     
15282     doTouchViewQuery : function()
15283     {
15284         var qe = {
15285             query: '',
15286             forceAll: true,
15287             combo: this,
15288             cancel:false
15289         };
15290         
15291         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15292             return false;
15293         }
15294         
15295         if(!this.alwaysQuery || this.mode == 'local'){
15296             this.onTouchViewLoad();
15297             return;
15298         }
15299         
15300         this.store.load();
15301     },
15302     
15303     onTouchViewBeforeLoad : function(combo,opts)
15304     {
15305         return;
15306     },
15307
15308     // private
15309     onTouchViewLoad : function()
15310     {
15311         if(this.store.getCount() < 1){
15312             this.onTouchViewEmptyResults();
15313             return;
15314         }
15315         
15316         this.clearTouchView();
15317         
15318         var rawValue = this.getRawValue();
15319         
15320         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15321         
15322         this.tickItems = [];
15323         
15324         this.store.data.each(function(d, rowIndex){
15325             var row = this.touchViewListGroup.createChild(template);
15326             
15327             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15328                 row.addClass(d.data.cls);
15329             }
15330             
15331             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15332                 var cfg = {
15333                     data : d.data,
15334                     html : d.data[this.displayField]
15335                 };
15336                 
15337                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15338                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15339                 }
15340             }
15341             row.removeClass('selected');
15342             if(!this.multiple && this.valueField &&
15343                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15344             {
15345                 // radio buttons..
15346                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15347                 row.addClass('selected');
15348             }
15349             
15350             if(this.multiple && this.valueField &&
15351                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15352             {
15353                 
15354                 // checkboxes...
15355                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15356                 this.tickItems.push(d.data);
15357             }
15358             
15359             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15360             
15361         }, this);
15362         
15363         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15364         
15365         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15366
15367         if(this.modalTitle.length){
15368             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15369         }
15370
15371         var listHeight = this.touchViewListGroup.getHeight();
15372         
15373         var _this = this;
15374         
15375         if(firstChecked && listHeight > bodyHeight){
15376             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15377         }
15378         
15379     },
15380     
15381     onTouchViewLoadException : function()
15382     {
15383         this.hideTouchView();
15384     },
15385     
15386     onTouchViewEmptyResults : function()
15387     {
15388         this.clearTouchView();
15389         
15390         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15391         
15392         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15393         
15394     },
15395     
15396     clearTouchView : function()
15397     {
15398         this.touchViewListGroup.dom.innerHTML = '';
15399     },
15400     
15401     onTouchViewClick : function(e, el, o)
15402     {
15403         e.preventDefault();
15404         
15405         var row = o.row;
15406         var rowIndex = o.rowIndex;
15407         
15408         var r = this.store.getAt(rowIndex);
15409         
15410         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15411             
15412             if(!this.multiple){
15413                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15414                     c.dom.removeAttribute('checked');
15415                 }, this);
15416
15417                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15418
15419                 this.setFromData(r.data);
15420
15421                 var close = this.closeTriggerEl();
15422
15423                 if(close){
15424                     close.show();
15425                 }
15426
15427                 this.hideTouchView();
15428
15429                 this.fireEvent('select', this, r, rowIndex);
15430
15431                 return;
15432             }
15433
15434             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15435                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15436                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15437                 return;
15438             }
15439
15440             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15441             this.addItem(r.data);
15442             this.tickItems.push(r.data);
15443         }
15444     },
15445     
15446     getAutoCreateNativeIOS : function()
15447     {
15448         var cfg = {
15449             cls: 'form-group' //input-group,
15450         };
15451         
15452         var combobox =  {
15453             tag: 'select',
15454             cls : 'roo-ios-select'
15455         };
15456         
15457         if (this.name) {
15458             combobox.name = this.name;
15459         }
15460         
15461         if (this.disabled) {
15462             combobox.disabled = true;
15463         }
15464         
15465         var settings = this;
15466         
15467         ['xs','sm','md','lg'].map(function(size){
15468             if (settings[size]) {
15469                 cfg.cls += ' col-' + size + '-' + settings[size];
15470             }
15471         });
15472         
15473         cfg.cn = combobox;
15474         
15475         return cfg;
15476         
15477     },
15478     
15479     initIOSView : function()
15480     {
15481         this.store.on('load', this.onIOSViewLoad, this);
15482         
15483         return;
15484     },
15485     
15486     onIOSViewLoad : function()
15487     {
15488         if(this.store.getCount() < 1){
15489             return;
15490         }
15491         
15492         this.clearIOSView();
15493         
15494         if(this.allowBlank) {
15495             
15496             var default_text = '-- SELECT --';
15497             
15498             if(this.placeholder.length){
15499                 default_text = this.placeholder;
15500             }
15501             
15502             if(this.emptyTitle.length){
15503                 default_text += ' - ' + this.emptyTitle + ' -';
15504             }
15505             
15506             var opt = this.inputEl().createChild({
15507                 tag: 'option',
15508                 value : 0,
15509                 html : default_text
15510             });
15511             
15512             var o = {};
15513             o[this.valueField] = 0;
15514             o[this.displayField] = default_text;
15515             
15516             this.ios_options.push({
15517                 data : o,
15518                 el : opt
15519             });
15520             
15521         }
15522         
15523         this.store.data.each(function(d, rowIndex){
15524             
15525             var html = '';
15526             
15527             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15528                 html = d.data[this.displayField];
15529             }
15530             
15531             var value = '';
15532             
15533             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15534                 value = d.data[this.valueField];
15535             }
15536             
15537             var option = {
15538                 tag: 'option',
15539                 value : value,
15540                 html : html
15541             };
15542             
15543             if(this.value == d.data[this.valueField]){
15544                 option['selected'] = true;
15545             }
15546             
15547             var opt = this.inputEl().createChild(option);
15548             
15549             this.ios_options.push({
15550                 data : d.data,
15551                 el : opt
15552             });
15553             
15554         }, this);
15555         
15556         this.inputEl().on('change', function(){
15557            this.fireEvent('select', this);
15558         }, this);
15559         
15560     },
15561     
15562     clearIOSView: function()
15563     {
15564         this.inputEl().dom.innerHTML = '';
15565         
15566         this.ios_options = [];
15567     },
15568     
15569     setIOSValue: function(v)
15570     {
15571         this.value = v;
15572         
15573         if(!this.ios_options){
15574             return;
15575         }
15576         
15577         Roo.each(this.ios_options, function(opts){
15578            
15579            opts.el.dom.removeAttribute('selected');
15580            
15581            if(opts.data[this.valueField] != v){
15582                return;
15583            }
15584            
15585            opts.el.dom.setAttribute('selected', true);
15586            
15587         }, this);
15588     }
15589
15590     /** 
15591     * @cfg {Boolean} grow 
15592     * @hide 
15593     */
15594     /** 
15595     * @cfg {Number} growMin 
15596     * @hide 
15597     */
15598     /** 
15599     * @cfg {Number} growMax 
15600     * @hide 
15601     */
15602     /**
15603      * @hide
15604      * @method autoSize
15605      */
15606 });
15607
15608 Roo.apply(Roo.bootstrap.ComboBox,  {
15609     
15610     header : {
15611         tag: 'div',
15612         cls: 'modal-header',
15613         cn: [
15614             {
15615                 tag: 'h4',
15616                 cls: 'modal-title'
15617             }
15618         ]
15619     },
15620     
15621     body : {
15622         tag: 'div',
15623         cls: 'modal-body',
15624         cn: [
15625             {
15626                 tag: 'ul',
15627                 cls: 'list-group'
15628             }
15629         ]
15630     },
15631     
15632     listItemRadio : {
15633         tag: 'li',
15634         cls: 'list-group-item',
15635         cn: [
15636             {
15637                 tag: 'span',
15638                 cls: 'roo-combobox-list-group-item-value'
15639             },
15640             {
15641                 tag: 'div',
15642                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15643                 cn: [
15644                     {
15645                         tag: 'input',
15646                         type: 'radio'
15647                     },
15648                     {
15649                         tag: 'label'
15650                     }
15651                 ]
15652             }
15653         ]
15654     },
15655     
15656     listItemCheckbox : {
15657         tag: 'li',
15658         cls: 'list-group-item',
15659         cn: [
15660             {
15661                 tag: 'span',
15662                 cls: 'roo-combobox-list-group-item-value'
15663             },
15664             {
15665                 tag: 'div',
15666                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15667                 cn: [
15668                     {
15669                         tag: 'input',
15670                         type: 'checkbox'
15671                     },
15672                     {
15673                         tag: 'label'
15674                     }
15675                 ]
15676             }
15677         ]
15678     },
15679     
15680     emptyResult : {
15681         tag: 'div',
15682         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15683     },
15684     
15685     footer : {
15686         tag: 'div',
15687         cls: 'modal-footer',
15688         cn: [
15689             {
15690                 tag: 'div',
15691                 cls: 'row',
15692                 cn: [
15693                     {
15694                         tag: 'div',
15695                         cls: 'col-xs-6 text-left',
15696                         cn: {
15697                             tag: 'button',
15698                             cls: 'btn btn-danger roo-touch-view-cancel',
15699                             html: 'Cancel'
15700                         }
15701                     },
15702                     {
15703                         tag: 'div',
15704                         cls: 'col-xs-6 text-right',
15705                         cn: {
15706                             tag: 'button',
15707                             cls: 'btn btn-success roo-touch-view-ok',
15708                             html: 'OK'
15709                         }
15710                     }
15711                 ]
15712             }
15713         ]
15714         
15715     }
15716 });
15717
15718 Roo.apply(Roo.bootstrap.ComboBox,  {
15719     
15720     touchViewTemplate : {
15721         tag: 'div',
15722         cls: 'modal fade roo-combobox-touch-view',
15723         cn: [
15724             {
15725                 tag: 'div',
15726                 cls: 'modal-dialog',
15727                 style : 'position:fixed', // we have to fix position....
15728                 cn: [
15729                     {
15730                         tag: 'div',
15731                         cls: 'modal-content',
15732                         cn: [
15733                             Roo.bootstrap.ComboBox.header,
15734                             Roo.bootstrap.ComboBox.body,
15735                             Roo.bootstrap.ComboBox.footer
15736                         ]
15737                     }
15738                 ]
15739             }
15740         ]
15741     }
15742 });/*
15743  * Based on:
15744  * Ext JS Library 1.1.1
15745  * Copyright(c) 2006-2007, Ext JS, LLC.
15746  *
15747  * Originally Released Under LGPL - original licence link has changed is not relivant.
15748  *
15749  * Fork - LGPL
15750  * <script type="text/javascript">
15751  */
15752
15753 /**
15754  * @class Roo.View
15755  * @extends Roo.util.Observable
15756  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15757  * This class also supports single and multi selection modes. <br>
15758  * Create a data model bound view:
15759  <pre><code>
15760  var store = new Roo.data.Store(...);
15761
15762  var view = new Roo.View({
15763     el : "my-element",
15764     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15765  
15766     singleSelect: true,
15767     selectedClass: "ydataview-selected",
15768     store: store
15769  });
15770
15771  // listen for node click?
15772  view.on("click", function(vw, index, node, e){
15773  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15774  });
15775
15776  // load XML data
15777  dataModel.load("foobar.xml");
15778  </code></pre>
15779  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15780  * <br><br>
15781  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15782  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15783  * 
15784  * Note: old style constructor is still suported (container, template, config)
15785  * 
15786  * @constructor
15787  * Create a new View
15788  * @param {Object} config The config object
15789  * 
15790  */
15791 Roo.View = function(config, depreciated_tpl, depreciated_config){
15792     
15793     this.parent = false;
15794     
15795     if (typeof(depreciated_tpl) == 'undefined') {
15796         // new way.. - universal constructor.
15797         Roo.apply(this, config);
15798         this.el  = Roo.get(this.el);
15799     } else {
15800         // old format..
15801         this.el  = Roo.get(config);
15802         this.tpl = depreciated_tpl;
15803         Roo.apply(this, depreciated_config);
15804     }
15805     this.wrapEl  = this.el.wrap().wrap();
15806     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15807     
15808     
15809     if(typeof(this.tpl) == "string"){
15810         this.tpl = new Roo.Template(this.tpl);
15811     } else {
15812         // support xtype ctors..
15813         this.tpl = new Roo.factory(this.tpl, Roo);
15814     }
15815     
15816     
15817     this.tpl.compile();
15818     
15819     /** @private */
15820     this.addEvents({
15821         /**
15822          * @event beforeclick
15823          * Fires before a click is processed. Returns false to cancel the default action.
15824          * @param {Roo.View} this
15825          * @param {Number} index The index of the target node
15826          * @param {HTMLElement} node The target node
15827          * @param {Roo.EventObject} e The raw event object
15828          */
15829             "beforeclick" : true,
15830         /**
15831          * @event click
15832          * Fires when a template node is clicked.
15833          * @param {Roo.View} this
15834          * @param {Number} index The index of the target node
15835          * @param {HTMLElement} node The target node
15836          * @param {Roo.EventObject} e The raw event object
15837          */
15838             "click" : true,
15839         /**
15840          * @event dblclick
15841          * Fires when a template node is double clicked.
15842          * @param {Roo.View} this
15843          * @param {Number} index The index of the target node
15844          * @param {HTMLElement} node The target node
15845          * @param {Roo.EventObject} e The raw event object
15846          */
15847             "dblclick" : true,
15848         /**
15849          * @event contextmenu
15850          * Fires when a template node is right clicked.
15851          * @param {Roo.View} this
15852          * @param {Number} index The index of the target node
15853          * @param {HTMLElement} node The target node
15854          * @param {Roo.EventObject} e The raw event object
15855          */
15856             "contextmenu" : true,
15857         /**
15858          * @event selectionchange
15859          * Fires when the selected nodes change.
15860          * @param {Roo.View} this
15861          * @param {Array} selections Array of the selected nodes
15862          */
15863             "selectionchange" : true,
15864     
15865         /**
15866          * @event beforeselect
15867          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15868          * @param {Roo.View} this
15869          * @param {HTMLElement} node The node to be selected
15870          * @param {Array} selections Array of currently selected nodes
15871          */
15872             "beforeselect" : true,
15873         /**
15874          * @event preparedata
15875          * Fires on every row to render, to allow you to change the data.
15876          * @param {Roo.View} this
15877          * @param {Object} data to be rendered (change this)
15878          */
15879           "preparedata" : true
15880           
15881           
15882         });
15883
15884
15885
15886     this.el.on({
15887         "click": this.onClick,
15888         "dblclick": this.onDblClick,
15889         "contextmenu": this.onContextMenu,
15890         scope:this
15891     });
15892
15893     this.selections = [];
15894     this.nodes = [];
15895     this.cmp = new Roo.CompositeElementLite([]);
15896     if(this.store){
15897         this.store = Roo.factory(this.store, Roo.data);
15898         this.setStore(this.store, true);
15899     }
15900     
15901     if ( this.footer && this.footer.xtype) {
15902            
15903          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15904         
15905         this.footer.dataSource = this.store;
15906         this.footer.container = fctr;
15907         this.footer = Roo.factory(this.footer, Roo);
15908         fctr.insertFirst(this.el);
15909         
15910         // this is a bit insane - as the paging toolbar seems to detach the el..
15911 //        dom.parentNode.parentNode.parentNode
15912          // they get detached?
15913     }
15914     
15915     
15916     Roo.View.superclass.constructor.call(this);
15917     
15918     
15919 };
15920
15921 Roo.extend(Roo.View, Roo.util.Observable, {
15922     
15923      /**
15924      * @cfg {Roo.data.Store} store Data store to load data from.
15925      */
15926     store : false,
15927     
15928     /**
15929      * @cfg {String|Roo.Element} el The container element.
15930      */
15931     el : '',
15932     
15933     /**
15934      * @cfg {String|Roo.Template} tpl The template used by this View 
15935      */
15936     tpl : false,
15937     /**
15938      * @cfg {String} dataName the named area of the template to use as the data area
15939      *                          Works with domtemplates roo-name="name"
15940      */
15941     dataName: false,
15942     /**
15943      * @cfg {String} selectedClass The css class to add to selected nodes
15944      */
15945     selectedClass : "x-view-selected",
15946      /**
15947      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15948      */
15949     emptyText : "",
15950     
15951     /**
15952      * @cfg {String} text to display on mask (default Loading)
15953      */
15954     mask : false,
15955     /**
15956      * @cfg {Boolean} multiSelect Allow multiple selection
15957      */
15958     multiSelect : false,
15959     /**
15960      * @cfg {Boolean} singleSelect Allow single selection
15961      */
15962     singleSelect:  false,
15963     
15964     /**
15965      * @cfg {Boolean} toggleSelect - selecting 
15966      */
15967     toggleSelect : false,
15968     
15969     /**
15970      * @cfg {Boolean} tickable - selecting 
15971      */
15972     tickable : false,
15973     
15974     /**
15975      * Returns the element this view is bound to.
15976      * @return {Roo.Element}
15977      */
15978     getEl : function(){
15979         return this.wrapEl;
15980     },
15981     
15982     
15983
15984     /**
15985      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15986      */
15987     refresh : function(){
15988         //Roo.log('refresh');
15989         var t = this.tpl;
15990         
15991         // if we are using something like 'domtemplate', then
15992         // the what gets used is:
15993         // t.applySubtemplate(NAME, data, wrapping data..)
15994         // the outer template then get' applied with
15995         //     the store 'extra data'
15996         // and the body get's added to the
15997         //      roo-name="data" node?
15998         //      <span class='roo-tpl-{name}'></span> ?????
15999         
16000         
16001         
16002         this.clearSelections();
16003         this.el.update("");
16004         var html = [];
16005         var records = this.store.getRange();
16006         if(records.length < 1) {
16007             
16008             // is this valid??  = should it render a template??
16009             
16010             this.el.update(this.emptyText);
16011             return;
16012         }
16013         var el = this.el;
16014         if (this.dataName) {
16015             this.el.update(t.apply(this.store.meta)); //????
16016             el = this.el.child('.roo-tpl-' + this.dataName);
16017         }
16018         
16019         for(var i = 0, len = records.length; i < len; i++){
16020             var data = this.prepareData(records[i].data, i, records[i]);
16021             this.fireEvent("preparedata", this, data, i, records[i]);
16022             
16023             var d = Roo.apply({}, data);
16024             
16025             if(this.tickable){
16026                 Roo.apply(d, {'roo-id' : Roo.id()});
16027                 
16028                 var _this = this;
16029             
16030                 Roo.each(this.parent.item, function(item){
16031                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16032                         return;
16033                     }
16034                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16035                 });
16036             }
16037             
16038             html[html.length] = Roo.util.Format.trim(
16039                 this.dataName ?
16040                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16041                     t.apply(d)
16042             );
16043         }
16044         
16045         
16046         
16047         el.update(html.join(""));
16048         this.nodes = el.dom.childNodes;
16049         this.updateIndexes(0);
16050     },
16051     
16052
16053     /**
16054      * Function to override to reformat the data that is sent to
16055      * the template for each node.
16056      * DEPRICATED - use the preparedata event handler.
16057      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16058      * a JSON object for an UpdateManager bound view).
16059      */
16060     prepareData : function(data, index, record)
16061     {
16062         this.fireEvent("preparedata", this, data, index, record);
16063         return data;
16064     },
16065
16066     onUpdate : function(ds, record){
16067         // Roo.log('on update');   
16068         this.clearSelections();
16069         var index = this.store.indexOf(record);
16070         var n = this.nodes[index];
16071         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16072         n.parentNode.removeChild(n);
16073         this.updateIndexes(index, index);
16074     },
16075
16076     
16077     
16078 // --------- FIXME     
16079     onAdd : function(ds, records, index)
16080     {
16081         //Roo.log(['on Add', ds, records, index] );        
16082         this.clearSelections();
16083         if(this.nodes.length == 0){
16084             this.refresh();
16085             return;
16086         }
16087         var n = this.nodes[index];
16088         for(var i = 0, len = records.length; i < len; i++){
16089             var d = this.prepareData(records[i].data, i, records[i]);
16090             if(n){
16091                 this.tpl.insertBefore(n, d);
16092             }else{
16093                 
16094                 this.tpl.append(this.el, d);
16095             }
16096         }
16097         this.updateIndexes(index);
16098     },
16099
16100     onRemove : function(ds, record, index){
16101        // Roo.log('onRemove');
16102         this.clearSelections();
16103         var el = this.dataName  ?
16104             this.el.child('.roo-tpl-' + this.dataName) :
16105             this.el; 
16106         
16107         el.dom.removeChild(this.nodes[index]);
16108         this.updateIndexes(index);
16109     },
16110
16111     /**
16112      * Refresh an individual node.
16113      * @param {Number} index
16114      */
16115     refreshNode : function(index){
16116         this.onUpdate(this.store, this.store.getAt(index));
16117     },
16118
16119     updateIndexes : function(startIndex, endIndex){
16120         var ns = this.nodes;
16121         startIndex = startIndex || 0;
16122         endIndex = endIndex || ns.length - 1;
16123         for(var i = startIndex; i <= endIndex; i++){
16124             ns[i].nodeIndex = i;
16125         }
16126     },
16127
16128     /**
16129      * Changes the data store this view uses and refresh the view.
16130      * @param {Store} store
16131      */
16132     setStore : function(store, initial){
16133         if(!initial && this.store){
16134             this.store.un("datachanged", this.refresh);
16135             this.store.un("add", this.onAdd);
16136             this.store.un("remove", this.onRemove);
16137             this.store.un("update", this.onUpdate);
16138             this.store.un("clear", this.refresh);
16139             this.store.un("beforeload", this.onBeforeLoad);
16140             this.store.un("load", this.onLoad);
16141             this.store.un("loadexception", this.onLoad);
16142         }
16143         if(store){
16144           
16145             store.on("datachanged", this.refresh, this);
16146             store.on("add", this.onAdd, this);
16147             store.on("remove", this.onRemove, this);
16148             store.on("update", this.onUpdate, this);
16149             store.on("clear", this.refresh, this);
16150             store.on("beforeload", this.onBeforeLoad, this);
16151             store.on("load", this.onLoad, this);
16152             store.on("loadexception", this.onLoad, this);
16153         }
16154         
16155         if(store){
16156             this.refresh();
16157         }
16158     },
16159     /**
16160      * onbeforeLoad - masks the loading area.
16161      *
16162      */
16163     onBeforeLoad : function(store,opts)
16164     {
16165          //Roo.log('onBeforeLoad');   
16166         if (!opts.add) {
16167             this.el.update("");
16168         }
16169         this.el.mask(this.mask ? this.mask : "Loading" ); 
16170     },
16171     onLoad : function ()
16172     {
16173         this.el.unmask();
16174     },
16175     
16176
16177     /**
16178      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16179      * @param {HTMLElement} node
16180      * @return {HTMLElement} The template node
16181      */
16182     findItemFromChild : function(node){
16183         var el = this.dataName  ?
16184             this.el.child('.roo-tpl-' + this.dataName,true) :
16185             this.el.dom; 
16186         
16187         if(!node || node.parentNode == el){
16188                     return node;
16189             }
16190             var p = node.parentNode;
16191             while(p && p != el){
16192             if(p.parentNode == el){
16193                 return p;
16194             }
16195             p = p.parentNode;
16196         }
16197             return null;
16198     },
16199
16200     /** @ignore */
16201     onClick : function(e){
16202         var item = this.findItemFromChild(e.getTarget());
16203         if(item){
16204             var index = this.indexOf(item);
16205             if(this.onItemClick(item, index, e) !== false){
16206                 this.fireEvent("click", this, index, item, e);
16207             }
16208         }else{
16209             this.clearSelections();
16210         }
16211     },
16212
16213     /** @ignore */
16214     onContextMenu : function(e){
16215         var item = this.findItemFromChild(e.getTarget());
16216         if(item){
16217             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16218         }
16219     },
16220
16221     /** @ignore */
16222     onDblClick : function(e){
16223         var item = this.findItemFromChild(e.getTarget());
16224         if(item){
16225             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16226         }
16227     },
16228
16229     onItemClick : function(item, index, e)
16230     {
16231         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16232             return false;
16233         }
16234         if (this.toggleSelect) {
16235             var m = this.isSelected(item) ? 'unselect' : 'select';
16236             //Roo.log(m);
16237             var _t = this;
16238             _t[m](item, true, false);
16239             return true;
16240         }
16241         if(this.multiSelect || this.singleSelect){
16242             if(this.multiSelect && e.shiftKey && this.lastSelection){
16243                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16244             }else{
16245                 this.select(item, this.multiSelect && e.ctrlKey);
16246                 this.lastSelection = item;
16247             }
16248             
16249             if(!this.tickable){
16250                 e.preventDefault();
16251             }
16252             
16253         }
16254         return true;
16255     },
16256
16257     /**
16258      * Get the number of selected nodes.
16259      * @return {Number}
16260      */
16261     getSelectionCount : function(){
16262         return this.selections.length;
16263     },
16264
16265     /**
16266      * Get the currently selected nodes.
16267      * @return {Array} An array of HTMLElements
16268      */
16269     getSelectedNodes : function(){
16270         return this.selections;
16271     },
16272
16273     /**
16274      * Get the indexes of the selected nodes.
16275      * @return {Array}
16276      */
16277     getSelectedIndexes : function(){
16278         var indexes = [], s = this.selections;
16279         for(var i = 0, len = s.length; i < len; i++){
16280             indexes.push(s[i].nodeIndex);
16281         }
16282         return indexes;
16283     },
16284
16285     /**
16286      * Clear all selections
16287      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16288      */
16289     clearSelections : function(suppressEvent){
16290         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16291             this.cmp.elements = this.selections;
16292             this.cmp.removeClass(this.selectedClass);
16293             this.selections = [];
16294             if(!suppressEvent){
16295                 this.fireEvent("selectionchange", this, this.selections);
16296             }
16297         }
16298     },
16299
16300     /**
16301      * Returns true if the passed node is selected
16302      * @param {HTMLElement/Number} node The node or node index
16303      * @return {Boolean}
16304      */
16305     isSelected : function(node){
16306         var s = this.selections;
16307         if(s.length < 1){
16308             return false;
16309         }
16310         node = this.getNode(node);
16311         return s.indexOf(node) !== -1;
16312     },
16313
16314     /**
16315      * Selects nodes.
16316      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16317      * @param {Boolean} keepExisting (optional) true to keep existing selections
16318      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16319      */
16320     select : function(nodeInfo, keepExisting, suppressEvent){
16321         if(nodeInfo instanceof Array){
16322             if(!keepExisting){
16323                 this.clearSelections(true);
16324             }
16325             for(var i = 0, len = nodeInfo.length; i < len; i++){
16326                 this.select(nodeInfo[i], true, true);
16327             }
16328             return;
16329         } 
16330         var node = this.getNode(nodeInfo);
16331         if(!node || this.isSelected(node)){
16332             return; // already selected.
16333         }
16334         if(!keepExisting){
16335             this.clearSelections(true);
16336         }
16337         
16338         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16339             Roo.fly(node).addClass(this.selectedClass);
16340             this.selections.push(node);
16341             if(!suppressEvent){
16342                 this.fireEvent("selectionchange", this, this.selections);
16343             }
16344         }
16345         
16346         
16347     },
16348       /**
16349      * Unselects nodes.
16350      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16351      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16352      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16353      */
16354     unselect : function(nodeInfo, keepExisting, suppressEvent)
16355     {
16356         if(nodeInfo instanceof Array){
16357             Roo.each(this.selections, function(s) {
16358                 this.unselect(s, nodeInfo);
16359             }, this);
16360             return;
16361         }
16362         var node = this.getNode(nodeInfo);
16363         if(!node || !this.isSelected(node)){
16364             //Roo.log("not selected");
16365             return; // not selected.
16366         }
16367         // fireevent???
16368         var ns = [];
16369         Roo.each(this.selections, function(s) {
16370             if (s == node ) {
16371                 Roo.fly(node).removeClass(this.selectedClass);
16372
16373                 return;
16374             }
16375             ns.push(s);
16376         },this);
16377         
16378         this.selections= ns;
16379         this.fireEvent("selectionchange", this, this.selections);
16380     },
16381
16382     /**
16383      * Gets a template node.
16384      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16385      * @return {HTMLElement} The node or null if it wasn't found
16386      */
16387     getNode : function(nodeInfo){
16388         if(typeof nodeInfo == "string"){
16389             return document.getElementById(nodeInfo);
16390         }else if(typeof nodeInfo == "number"){
16391             return this.nodes[nodeInfo];
16392         }
16393         return nodeInfo;
16394     },
16395
16396     /**
16397      * Gets a range template nodes.
16398      * @param {Number} startIndex
16399      * @param {Number} endIndex
16400      * @return {Array} An array of nodes
16401      */
16402     getNodes : function(start, end){
16403         var ns = this.nodes;
16404         start = start || 0;
16405         end = typeof end == "undefined" ? ns.length - 1 : end;
16406         var nodes = [];
16407         if(start <= end){
16408             for(var i = start; i <= end; i++){
16409                 nodes.push(ns[i]);
16410             }
16411         } else{
16412             for(var i = start; i >= end; i--){
16413                 nodes.push(ns[i]);
16414             }
16415         }
16416         return nodes;
16417     },
16418
16419     /**
16420      * Finds the index of the passed node
16421      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16422      * @return {Number} The index of the node or -1
16423      */
16424     indexOf : function(node){
16425         node = this.getNode(node);
16426         if(typeof node.nodeIndex == "number"){
16427             return node.nodeIndex;
16428         }
16429         var ns = this.nodes;
16430         for(var i = 0, len = ns.length; i < len; i++){
16431             if(ns[i] == node){
16432                 return i;
16433             }
16434         }
16435         return -1;
16436     }
16437 });
16438 /*
16439  * - LGPL
16440  *
16441  * based on jquery fullcalendar
16442  * 
16443  */
16444
16445 Roo.bootstrap = Roo.bootstrap || {};
16446 /**
16447  * @class Roo.bootstrap.Calendar
16448  * @extends Roo.bootstrap.Component
16449  * Bootstrap Calendar class
16450  * @cfg {Boolean} loadMask (true|false) default false
16451  * @cfg {Object} header generate the user specific header of the calendar, default false
16452
16453  * @constructor
16454  * Create a new Container
16455  * @param {Object} config The config object
16456  */
16457
16458
16459
16460 Roo.bootstrap.Calendar = function(config){
16461     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16462      this.addEvents({
16463         /**
16464              * @event select
16465              * Fires when a date is selected
16466              * @param {DatePicker} this
16467              * @param {Date} date The selected date
16468              */
16469         'select': true,
16470         /**
16471              * @event monthchange
16472              * Fires when the displayed month changes 
16473              * @param {DatePicker} this
16474              * @param {Date} date The selected month
16475              */
16476         'monthchange': true,
16477         /**
16478              * @event evententer
16479              * Fires when mouse over an event
16480              * @param {Calendar} this
16481              * @param {event} Event
16482              */
16483         'evententer': true,
16484         /**
16485              * @event eventleave
16486              * Fires when the mouse leaves an
16487              * @param {Calendar} this
16488              * @param {event}
16489              */
16490         'eventleave': true,
16491         /**
16492              * @event eventclick
16493              * Fires when the mouse click an
16494              * @param {Calendar} this
16495              * @param {event}
16496              */
16497         'eventclick': true
16498         
16499     });
16500
16501 };
16502
16503 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16504     
16505      /**
16506      * @cfg {Number} startDay
16507      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16508      */
16509     startDay : 0,
16510     
16511     loadMask : false,
16512     
16513     header : false,
16514       
16515     getAutoCreate : function(){
16516         
16517         
16518         var fc_button = function(name, corner, style, content ) {
16519             return Roo.apply({},{
16520                 tag : 'span',
16521                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16522                          (corner.length ?
16523                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16524                             ''
16525                         ),
16526                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16527                 unselectable: 'on'
16528             });
16529         };
16530         
16531         var header = {};
16532         
16533         if(!this.header){
16534             header = {
16535                 tag : 'table',
16536                 cls : 'fc-header',
16537                 style : 'width:100%',
16538                 cn : [
16539                     {
16540                         tag: 'tr',
16541                         cn : [
16542                             {
16543                                 tag : 'td',
16544                                 cls : 'fc-header-left',
16545                                 cn : [
16546                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16547                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16548                                     { tag: 'span', cls: 'fc-header-space' },
16549                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16550
16551
16552                                 ]
16553                             },
16554
16555                             {
16556                                 tag : 'td',
16557                                 cls : 'fc-header-center',
16558                                 cn : [
16559                                     {
16560                                         tag: 'span',
16561                                         cls: 'fc-header-title',
16562                                         cn : {
16563                                             tag: 'H2',
16564                                             html : 'month / year'
16565                                         }
16566                                     }
16567
16568                                 ]
16569                             },
16570                             {
16571                                 tag : 'td',
16572                                 cls : 'fc-header-right',
16573                                 cn : [
16574                               /*      fc_button('month', 'left', '', 'month' ),
16575                                     fc_button('week', '', '', 'week' ),
16576                                     fc_button('day', 'right', '', 'day' )
16577                                 */    
16578
16579                                 ]
16580                             }
16581
16582                         ]
16583                     }
16584                 ]
16585             };
16586         }
16587         
16588         header = this.header;
16589         
16590        
16591         var cal_heads = function() {
16592             var ret = [];
16593             // fixme - handle this.
16594             
16595             for (var i =0; i < Date.dayNames.length; i++) {
16596                 var d = Date.dayNames[i];
16597                 ret.push({
16598                     tag: 'th',
16599                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16600                     html : d.substring(0,3)
16601                 });
16602                 
16603             }
16604             ret[0].cls += ' fc-first';
16605             ret[6].cls += ' fc-last';
16606             return ret;
16607         };
16608         var cal_cell = function(n) {
16609             return  {
16610                 tag: 'td',
16611                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16612                 cn : [
16613                     {
16614                         cn : [
16615                             {
16616                                 cls: 'fc-day-number',
16617                                 html: 'D'
16618                             },
16619                             {
16620                                 cls: 'fc-day-content',
16621                              
16622                                 cn : [
16623                                      {
16624                                         style: 'position: relative;' // height: 17px;
16625                                     }
16626                                 ]
16627                             }
16628                             
16629                             
16630                         ]
16631                     }
16632                 ]
16633                 
16634             }
16635         };
16636         var cal_rows = function() {
16637             
16638             var ret = [];
16639             for (var r = 0; r < 6; r++) {
16640                 var row= {
16641                     tag : 'tr',
16642                     cls : 'fc-week',
16643                     cn : []
16644                 };
16645                 
16646                 for (var i =0; i < Date.dayNames.length; i++) {
16647                     var d = Date.dayNames[i];
16648                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16649
16650                 }
16651                 row.cn[0].cls+=' fc-first';
16652                 row.cn[0].cn[0].style = 'min-height:90px';
16653                 row.cn[6].cls+=' fc-last';
16654                 ret.push(row);
16655                 
16656             }
16657             ret[0].cls += ' fc-first';
16658             ret[4].cls += ' fc-prev-last';
16659             ret[5].cls += ' fc-last';
16660             return ret;
16661             
16662         };
16663         
16664         var cal_table = {
16665             tag: 'table',
16666             cls: 'fc-border-separate',
16667             style : 'width:100%',
16668             cellspacing  : 0,
16669             cn : [
16670                 { 
16671                     tag: 'thead',
16672                     cn : [
16673                         { 
16674                             tag: 'tr',
16675                             cls : 'fc-first fc-last',
16676                             cn : cal_heads()
16677                         }
16678                     ]
16679                 },
16680                 { 
16681                     tag: 'tbody',
16682                     cn : cal_rows()
16683                 }
16684                   
16685             ]
16686         };
16687          
16688          var cfg = {
16689             cls : 'fc fc-ltr',
16690             cn : [
16691                 header,
16692                 {
16693                     cls : 'fc-content',
16694                     style : "position: relative;",
16695                     cn : [
16696                         {
16697                             cls : 'fc-view fc-view-month fc-grid',
16698                             style : 'position: relative',
16699                             unselectable : 'on',
16700                             cn : [
16701                                 {
16702                                     cls : 'fc-event-container',
16703                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16704                                 },
16705                                 cal_table
16706                             ]
16707                         }
16708                     ]
16709     
16710                 }
16711            ] 
16712             
16713         };
16714         
16715          
16716         
16717         return cfg;
16718     },
16719     
16720     
16721     initEvents : function()
16722     {
16723         if(!this.store){
16724             throw "can not find store for calendar";
16725         }
16726         
16727         var mark = {
16728             tag: "div",
16729             cls:"x-dlg-mask",
16730             style: "text-align:center",
16731             cn: [
16732                 {
16733                     tag: "div",
16734                     style: "background-color:white;width:50%;margin:250 auto",
16735                     cn: [
16736                         {
16737                             tag: "img",
16738                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16739                         },
16740                         {
16741                             tag: "span",
16742                             html: "Loading"
16743                         }
16744                         
16745                     ]
16746                 }
16747             ]
16748         };
16749         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16750         
16751         var size = this.el.select('.fc-content', true).first().getSize();
16752         this.maskEl.setSize(size.width, size.height);
16753         this.maskEl.enableDisplayMode("block");
16754         if(!this.loadMask){
16755             this.maskEl.hide();
16756         }
16757         
16758         this.store = Roo.factory(this.store, Roo.data);
16759         this.store.on('load', this.onLoad, this);
16760         this.store.on('beforeload', this.onBeforeLoad, this);
16761         
16762         this.resize();
16763         
16764         this.cells = this.el.select('.fc-day',true);
16765         //Roo.log(this.cells);
16766         this.textNodes = this.el.query('.fc-day-number');
16767         this.cells.addClassOnOver('fc-state-hover');
16768         
16769         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16770         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16771         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16772         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16773         
16774         this.on('monthchange', this.onMonthChange, this);
16775         
16776         this.update(new Date().clearTime());
16777     },
16778     
16779     resize : function() {
16780         var sz  = this.el.getSize();
16781         
16782         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16783         this.el.select('.fc-day-content div',true).setHeight(34);
16784     },
16785     
16786     
16787     // private
16788     showPrevMonth : function(e){
16789         this.update(this.activeDate.add("mo", -1));
16790     },
16791     showToday : function(e){
16792         this.update(new Date().clearTime());
16793     },
16794     // private
16795     showNextMonth : function(e){
16796         this.update(this.activeDate.add("mo", 1));
16797     },
16798
16799     // private
16800     showPrevYear : function(){
16801         this.update(this.activeDate.add("y", -1));
16802     },
16803
16804     // private
16805     showNextYear : function(){
16806         this.update(this.activeDate.add("y", 1));
16807     },
16808
16809     
16810    // private
16811     update : function(date)
16812     {
16813         var vd = this.activeDate;
16814         this.activeDate = date;
16815 //        if(vd && this.el){
16816 //            var t = date.getTime();
16817 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16818 //                Roo.log('using add remove');
16819 //                
16820 //                this.fireEvent('monthchange', this, date);
16821 //                
16822 //                this.cells.removeClass("fc-state-highlight");
16823 //                this.cells.each(function(c){
16824 //                   if(c.dateValue == t){
16825 //                       c.addClass("fc-state-highlight");
16826 //                       setTimeout(function(){
16827 //                            try{c.dom.firstChild.focus();}catch(e){}
16828 //                       }, 50);
16829 //                       return false;
16830 //                   }
16831 //                   return true;
16832 //                });
16833 //                return;
16834 //            }
16835 //        }
16836         
16837         var days = date.getDaysInMonth();
16838         
16839         var firstOfMonth = date.getFirstDateOfMonth();
16840         var startingPos = firstOfMonth.getDay()-this.startDay;
16841         
16842         if(startingPos < this.startDay){
16843             startingPos += 7;
16844         }
16845         
16846         var pm = date.add(Date.MONTH, -1);
16847         var prevStart = pm.getDaysInMonth()-startingPos;
16848 //        
16849         this.cells = this.el.select('.fc-day',true);
16850         this.textNodes = this.el.query('.fc-day-number');
16851         this.cells.addClassOnOver('fc-state-hover');
16852         
16853         var cells = this.cells.elements;
16854         var textEls = this.textNodes;
16855         
16856         Roo.each(cells, function(cell){
16857             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16858         });
16859         
16860         days += startingPos;
16861
16862         // convert everything to numbers so it's fast
16863         var day = 86400000;
16864         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16865         //Roo.log(d);
16866         //Roo.log(pm);
16867         //Roo.log(prevStart);
16868         
16869         var today = new Date().clearTime().getTime();
16870         var sel = date.clearTime().getTime();
16871         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16872         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16873         var ddMatch = this.disabledDatesRE;
16874         var ddText = this.disabledDatesText;
16875         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16876         var ddaysText = this.disabledDaysText;
16877         var format = this.format;
16878         
16879         var setCellClass = function(cal, cell){
16880             cell.row = 0;
16881             cell.events = [];
16882             cell.more = [];
16883             //Roo.log('set Cell Class');
16884             cell.title = "";
16885             var t = d.getTime();
16886             
16887             //Roo.log(d);
16888             
16889             cell.dateValue = t;
16890             if(t == today){
16891                 cell.className += " fc-today";
16892                 cell.className += " fc-state-highlight";
16893                 cell.title = cal.todayText;
16894             }
16895             if(t == sel){
16896                 // disable highlight in other month..
16897                 //cell.className += " fc-state-highlight";
16898                 
16899             }
16900             // disabling
16901             if(t < min) {
16902                 cell.className = " fc-state-disabled";
16903                 cell.title = cal.minText;
16904                 return;
16905             }
16906             if(t > max) {
16907                 cell.className = " fc-state-disabled";
16908                 cell.title = cal.maxText;
16909                 return;
16910             }
16911             if(ddays){
16912                 if(ddays.indexOf(d.getDay()) != -1){
16913                     cell.title = ddaysText;
16914                     cell.className = " fc-state-disabled";
16915                 }
16916             }
16917             if(ddMatch && format){
16918                 var fvalue = d.dateFormat(format);
16919                 if(ddMatch.test(fvalue)){
16920                     cell.title = ddText.replace("%0", fvalue);
16921                     cell.className = " fc-state-disabled";
16922                 }
16923             }
16924             
16925             if (!cell.initialClassName) {
16926                 cell.initialClassName = cell.dom.className;
16927             }
16928             
16929             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16930         };
16931
16932         var i = 0;
16933         
16934         for(; i < startingPos; i++) {
16935             textEls[i].innerHTML = (++prevStart);
16936             d.setDate(d.getDate()+1);
16937             
16938             cells[i].className = "fc-past fc-other-month";
16939             setCellClass(this, cells[i]);
16940         }
16941         
16942         var intDay = 0;
16943         
16944         for(; i < days; i++){
16945             intDay = i - startingPos + 1;
16946             textEls[i].innerHTML = (intDay);
16947             d.setDate(d.getDate()+1);
16948             
16949             cells[i].className = ''; // "x-date-active";
16950             setCellClass(this, cells[i]);
16951         }
16952         var extraDays = 0;
16953         
16954         for(; i < 42; i++) {
16955             textEls[i].innerHTML = (++extraDays);
16956             d.setDate(d.getDate()+1);
16957             
16958             cells[i].className = "fc-future fc-other-month";
16959             setCellClass(this, cells[i]);
16960         }
16961         
16962         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16963         
16964         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16965         
16966         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16967         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16968         
16969         if(totalRows != 6){
16970             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16971             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16972         }
16973         
16974         this.fireEvent('monthchange', this, date);
16975         
16976         
16977         /*
16978         if(!this.internalRender){
16979             var main = this.el.dom.firstChild;
16980             var w = main.offsetWidth;
16981             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16982             Roo.fly(main).setWidth(w);
16983             this.internalRender = true;
16984             // opera does not respect the auto grow header center column
16985             // then, after it gets a width opera refuses to recalculate
16986             // without a second pass
16987             if(Roo.isOpera && !this.secondPass){
16988                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16989                 this.secondPass = true;
16990                 this.update.defer(10, this, [date]);
16991             }
16992         }
16993         */
16994         
16995     },
16996     
16997     findCell : function(dt) {
16998         dt = dt.clearTime().getTime();
16999         var ret = false;
17000         this.cells.each(function(c){
17001             //Roo.log("check " +c.dateValue + '?=' + dt);
17002             if(c.dateValue == dt){
17003                 ret = c;
17004                 return false;
17005             }
17006             return true;
17007         });
17008         
17009         return ret;
17010     },
17011     
17012     findCells : function(ev) {
17013         var s = ev.start.clone().clearTime().getTime();
17014        // Roo.log(s);
17015         var e= ev.end.clone().clearTime().getTime();
17016        // Roo.log(e);
17017         var ret = [];
17018         this.cells.each(function(c){
17019              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17020             
17021             if(c.dateValue > e){
17022                 return ;
17023             }
17024             if(c.dateValue < s){
17025                 return ;
17026             }
17027             ret.push(c);
17028         });
17029         
17030         return ret;    
17031     },
17032     
17033 //    findBestRow: function(cells)
17034 //    {
17035 //        var ret = 0;
17036 //        
17037 //        for (var i =0 ; i < cells.length;i++) {
17038 //            ret  = Math.max(cells[i].rows || 0,ret);
17039 //        }
17040 //        return ret;
17041 //        
17042 //    },
17043     
17044     
17045     addItem : function(ev)
17046     {
17047         // look for vertical location slot in
17048         var cells = this.findCells(ev);
17049         
17050 //        ev.row = this.findBestRow(cells);
17051         
17052         // work out the location.
17053         
17054         var crow = false;
17055         var rows = [];
17056         for(var i =0; i < cells.length; i++) {
17057             
17058             cells[i].row = cells[0].row;
17059             
17060             if(i == 0){
17061                 cells[i].row = cells[i].row + 1;
17062             }
17063             
17064             if (!crow) {
17065                 crow = {
17066                     start : cells[i],
17067                     end :  cells[i]
17068                 };
17069                 continue;
17070             }
17071             if (crow.start.getY() == cells[i].getY()) {
17072                 // on same row.
17073                 crow.end = cells[i];
17074                 continue;
17075             }
17076             // different row.
17077             rows.push(crow);
17078             crow = {
17079                 start: cells[i],
17080                 end : cells[i]
17081             };
17082             
17083         }
17084         
17085         rows.push(crow);
17086         ev.els = [];
17087         ev.rows = rows;
17088         ev.cells = cells;
17089         
17090         cells[0].events.push(ev);
17091         
17092         this.calevents.push(ev);
17093     },
17094     
17095     clearEvents: function() {
17096         
17097         if(!this.calevents){
17098             return;
17099         }
17100         
17101         Roo.each(this.cells.elements, function(c){
17102             c.row = 0;
17103             c.events = [];
17104             c.more = [];
17105         });
17106         
17107         Roo.each(this.calevents, function(e) {
17108             Roo.each(e.els, function(el) {
17109                 el.un('mouseenter' ,this.onEventEnter, this);
17110                 el.un('mouseleave' ,this.onEventLeave, this);
17111                 el.remove();
17112             },this);
17113         },this);
17114         
17115         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17116             e.remove();
17117         });
17118         
17119     },
17120     
17121     renderEvents: function()
17122     {   
17123         var _this = this;
17124         
17125         this.cells.each(function(c) {
17126             
17127             if(c.row < 5){
17128                 return;
17129             }
17130             
17131             var ev = c.events;
17132             
17133             var r = 4;
17134             if(c.row != c.events.length){
17135                 r = 4 - (4 - (c.row - c.events.length));
17136             }
17137             
17138             c.events = ev.slice(0, r);
17139             c.more = ev.slice(r);
17140             
17141             if(c.more.length && c.more.length == 1){
17142                 c.events.push(c.more.pop());
17143             }
17144             
17145             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17146             
17147         });
17148             
17149         this.cells.each(function(c) {
17150             
17151             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17152             
17153             
17154             for (var e = 0; e < c.events.length; e++){
17155                 var ev = c.events[e];
17156                 var rows = ev.rows;
17157                 
17158                 for(var i = 0; i < rows.length; i++) {
17159                 
17160                     // how many rows should it span..
17161
17162                     var  cfg = {
17163                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17164                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17165
17166                         unselectable : "on",
17167                         cn : [
17168                             {
17169                                 cls: 'fc-event-inner',
17170                                 cn : [
17171     //                                {
17172     //                                  tag:'span',
17173     //                                  cls: 'fc-event-time',
17174     //                                  html : cells.length > 1 ? '' : ev.time
17175     //                                },
17176                                     {
17177                                       tag:'span',
17178                                       cls: 'fc-event-title',
17179                                       html : String.format('{0}', ev.title)
17180                                     }
17181
17182
17183                                 ]
17184                             },
17185                             {
17186                                 cls: 'ui-resizable-handle ui-resizable-e',
17187                                 html : '&nbsp;&nbsp;&nbsp'
17188                             }
17189
17190                         ]
17191                     };
17192
17193                     if (i == 0) {
17194                         cfg.cls += ' fc-event-start';
17195                     }
17196                     if ((i+1) == rows.length) {
17197                         cfg.cls += ' fc-event-end';
17198                     }
17199
17200                     var ctr = _this.el.select('.fc-event-container',true).first();
17201                     var cg = ctr.createChild(cfg);
17202
17203                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17204                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17205
17206                     var r = (c.more.length) ? 1 : 0;
17207                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17208                     cg.setWidth(ebox.right - sbox.x -2);
17209
17210                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17211                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17212                     cg.on('click', _this.onEventClick, _this, ev);
17213
17214                     ev.els.push(cg);
17215                     
17216                 }
17217                 
17218             }
17219             
17220             
17221             if(c.more.length){
17222                 var  cfg = {
17223                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17224                     style : 'position: absolute',
17225                     unselectable : "on",
17226                     cn : [
17227                         {
17228                             cls: 'fc-event-inner',
17229                             cn : [
17230                                 {
17231                                   tag:'span',
17232                                   cls: 'fc-event-title',
17233                                   html : 'More'
17234                                 }
17235
17236
17237                             ]
17238                         },
17239                         {
17240                             cls: 'ui-resizable-handle ui-resizable-e',
17241                             html : '&nbsp;&nbsp;&nbsp'
17242                         }
17243
17244                     ]
17245                 };
17246
17247                 var ctr = _this.el.select('.fc-event-container',true).first();
17248                 var cg = ctr.createChild(cfg);
17249
17250                 var sbox = c.select('.fc-day-content',true).first().getBox();
17251                 var ebox = c.select('.fc-day-content',true).first().getBox();
17252                 //Roo.log(cg);
17253                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17254                 cg.setWidth(ebox.right - sbox.x -2);
17255
17256                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17257                 
17258             }
17259             
17260         });
17261         
17262         
17263         
17264     },
17265     
17266     onEventEnter: function (e, el,event,d) {
17267         this.fireEvent('evententer', this, el, event);
17268     },
17269     
17270     onEventLeave: function (e, el,event,d) {
17271         this.fireEvent('eventleave', this, el, event);
17272     },
17273     
17274     onEventClick: function (e, el,event,d) {
17275         this.fireEvent('eventclick', this, el, event);
17276     },
17277     
17278     onMonthChange: function () {
17279         this.store.load();
17280     },
17281     
17282     onMoreEventClick: function(e, el, more)
17283     {
17284         var _this = this;
17285         
17286         this.calpopover.placement = 'right';
17287         this.calpopover.setTitle('More');
17288         
17289         this.calpopover.setContent('');
17290         
17291         var ctr = this.calpopover.el.select('.popover-content', true).first();
17292         
17293         Roo.each(more, function(m){
17294             var cfg = {
17295                 cls : 'fc-event-hori fc-event-draggable',
17296                 html : m.title
17297             };
17298             var cg = ctr.createChild(cfg);
17299             
17300             cg.on('click', _this.onEventClick, _this, m);
17301         });
17302         
17303         this.calpopover.show(el);
17304         
17305         
17306     },
17307     
17308     onLoad: function () 
17309     {   
17310         this.calevents = [];
17311         var cal = this;
17312         
17313         if(this.store.getCount() > 0){
17314             this.store.data.each(function(d){
17315                cal.addItem({
17316                     id : d.data.id,
17317                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17318                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17319                     time : d.data.start_time,
17320                     title : d.data.title,
17321                     description : d.data.description,
17322                     venue : d.data.venue
17323                 });
17324             });
17325         }
17326         
17327         this.renderEvents();
17328         
17329         if(this.calevents.length && this.loadMask){
17330             this.maskEl.hide();
17331         }
17332     },
17333     
17334     onBeforeLoad: function()
17335     {
17336         this.clearEvents();
17337         if(this.loadMask){
17338             this.maskEl.show();
17339         }
17340     }
17341 });
17342
17343  
17344  /*
17345  * - LGPL
17346  *
17347  * element
17348  * 
17349  */
17350
17351 /**
17352  * @class Roo.bootstrap.Popover
17353  * @extends Roo.bootstrap.Component
17354  * Bootstrap Popover class
17355  * @cfg {String} html contents of the popover   (or false to use children..)
17356  * @cfg {String} title of popover (or false to hide)
17357  * @cfg {String} placement how it is placed
17358  * @cfg {String} trigger click || hover (or false to trigger manually)
17359  * @cfg {String} over what (parent or false to trigger manually.)
17360  * @cfg {Number} delay - delay before showing
17361  
17362  * @constructor
17363  * Create a new Popover
17364  * @param {Object} config The config object
17365  */
17366
17367 Roo.bootstrap.Popover = function(config){
17368     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17369     
17370     this.addEvents({
17371         // raw events
17372          /**
17373          * @event show
17374          * After the popover show
17375          * 
17376          * @param {Roo.bootstrap.Popover} this
17377          */
17378         "show" : true,
17379         /**
17380          * @event hide
17381          * After the popover hide
17382          * 
17383          * @param {Roo.bootstrap.Popover} this
17384          */
17385         "hide" : true
17386     });
17387 };
17388
17389 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17390     
17391     title: 'Fill in a title',
17392     html: false,
17393     
17394     placement : 'right',
17395     trigger : 'hover', // hover
17396     
17397     delay : 0,
17398     
17399     over: 'parent',
17400     
17401     can_build_overlaid : false,
17402     
17403     getChildContainer : function()
17404     {
17405         return this.el.select('.popover-content',true).first();
17406     },
17407     
17408     getAutoCreate : function(){
17409          
17410         var cfg = {
17411            cls : 'popover roo-dynamic',
17412            style: 'display:block',
17413            cn : [
17414                 {
17415                     cls : 'arrow'
17416                 },
17417                 {
17418                     cls : 'popover-inner',
17419                     cn : [
17420                         {
17421                             tag: 'h3',
17422                             cls: 'popover-title',
17423                             html : this.title
17424                         },
17425                         {
17426                             cls : 'popover-content',
17427                             html : this.html
17428                         }
17429                     ]
17430                     
17431                 }
17432            ]
17433         };
17434         
17435         return cfg;
17436     },
17437     setTitle: function(str)
17438     {
17439         this.title = str;
17440         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17441     },
17442     setContent: function(str)
17443     {
17444         this.html = str;
17445         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17446     },
17447     // as it get's added to the bottom of the page.
17448     onRender : function(ct, position)
17449     {
17450         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17451         if(!this.el){
17452             var cfg = Roo.apply({},  this.getAutoCreate());
17453             cfg.id = Roo.id();
17454             
17455             if (this.cls) {
17456                 cfg.cls += ' ' + this.cls;
17457             }
17458             if (this.style) {
17459                 cfg.style = this.style;
17460             }
17461             //Roo.log("adding to ");
17462             this.el = Roo.get(document.body).createChild(cfg, position);
17463 //            Roo.log(this.el);
17464         }
17465         this.initEvents();
17466     },
17467     
17468     initEvents : function()
17469     {
17470         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17471         this.el.enableDisplayMode('block');
17472         this.el.hide();
17473         if (this.over === false) {
17474             return; 
17475         }
17476         if (this.triggers === false) {
17477             return;
17478         }
17479         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17480         var triggers = this.trigger ? this.trigger.split(' ') : [];
17481         Roo.each(triggers, function(trigger) {
17482         
17483             if (trigger == 'click') {
17484                 on_el.on('click', this.toggle, this);
17485             } else if (trigger != 'manual') {
17486                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17487                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17488       
17489                 on_el.on(eventIn  ,this.enter, this);
17490                 on_el.on(eventOut, this.leave, this);
17491             }
17492         }, this);
17493         
17494     },
17495     
17496     
17497     // private
17498     timeout : null,
17499     hoverState : null,
17500     
17501     toggle : function () {
17502         this.hoverState == 'in' ? this.leave() : this.enter();
17503     },
17504     
17505     enter : function () {
17506         
17507         clearTimeout(this.timeout);
17508     
17509         this.hoverState = 'in';
17510     
17511         if (!this.delay || !this.delay.show) {
17512             this.show();
17513             return;
17514         }
17515         var _t = this;
17516         this.timeout = setTimeout(function () {
17517             if (_t.hoverState == 'in') {
17518                 _t.show();
17519             }
17520         }, this.delay.show)
17521     },
17522     
17523     leave : function() {
17524         clearTimeout(this.timeout);
17525     
17526         this.hoverState = 'out';
17527     
17528         if (!this.delay || !this.delay.hide) {
17529             this.hide();
17530             return;
17531         }
17532         var _t = this;
17533         this.timeout = setTimeout(function () {
17534             if (_t.hoverState == 'out') {
17535                 _t.hide();
17536             }
17537         }, this.delay.hide)
17538     },
17539     
17540     show : function (on_el)
17541     {
17542         if (!on_el) {
17543             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17544         }
17545         
17546         // set content.
17547         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17548         if (this.html !== false) {
17549             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17550         }
17551         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17552         if (!this.title.length) {
17553             this.el.select('.popover-title',true).hide();
17554         }
17555         
17556         var placement = typeof this.placement == 'function' ?
17557             this.placement.call(this, this.el, on_el) :
17558             this.placement;
17559             
17560         var autoToken = /\s?auto?\s?/i;
17561         var autoPlace = autoToken.test(placement);
17562         if (autoPlace) {
17563             placement = placement.replace(autoToken, '') || 'top';
17564         }
17565         
17566         //this.el.detach()
17567         //this.el.setXY([0,0]);
17568         this.el.show();
17569         this.el.dom.style.display='block';
17570         this.el.addClass(placement);
17571         
17572         //this.el.appendTo(on_el);
17573         
17574         var p = this.getPosition();
17575         var box = this.el.getBox();
17576         
17577         if (autoPlace) {
17578             // fixme..
17579         }
17580         var align = Roo.bootstrap.Popover.alignment[placement];
17581         
17582 //        Roo.log(align);
17583         this.el.alignTo(on_el, align[0],align[1]);
17584         //var arrow = this.el.select('.arrow',true).first();
17585         //arrow.set(align[2], 
17586         
17587         this.el.addClass('in');
17588         
17589         
17590         if (this.el.hasClass('fade')) {
17591             // fade it?
17592         }
17593         
17594         this.hoverState = 'in';
17595         
17596         this.fireEvent('show', this);
17597         
17598     },
17599     hide : function()
17600     {
17601         this.el.setXY([0,0]);
17602         this.el.removeClass('in');
17603         this.el.hide();
17604         this.hoverState = null;
17605         
17606         this.fireEvent('hide', this);
17607     }
17608     
17609 });
17610
17611 Roo.bootstrap.Popover.alignment = {
17612     'left' : ['r-l', [-10,0], 'right'],
17613     'right' : ['l-r', [10,0], 'left'],
17614     'bottom' : ['t-b', [0,10], 'top'],
17615     'top' : [ 'b-t', [0,-10], 'bottom']
17616 };
17617
17618  /*
17619  * - LGPL
17620  *
17621  * Progress
17622  * 
17623  */
17624
17625 /**
17626  * @class Roo.bootstrap.Progress
17627  * @extends Roo.bootstrap.Component
17628  * Bootstrap Progress class
17629  * @cfg {Boolean} striped striped of the progress bar
17630  * @cfg {Boolean} active animated of the progress bar
17631  * 
17632  * 
17633  * @constructor
17634  * Create a new Progress
17635  * @param {Object} config The config object
17636  */
17637
17638 Roo.bootstrap.Progress = function(config){
17639     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17640 };
17641
17642 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17643     
17644     striped : false,
17645     active: false,
17646     
17647     getAutoCreate : function(){
17648         var cfg = {
17649             tag: 'div',
17650             cls: 'progress'
17651         };
17652         
17653         
17654         if(this.striped){
17655             cfg.cls += ' progress-striped';
17656         }
17657       
17658         if(this.active){
17659             cfg.cls += ' active';
17660         }
17661         
17662         
17663         return cfg;
17664     }
17665    
17666 });
17667
17668  
17669
17670  /*
17671  * - LGPL
17672  *
17673  * ProgressBar
17674  * 
17675  */
17676
17677 /**
17678  * @class Roo.bootstrap.ProgressBar
17679  * @extends Roo.bootstrap.Component
17680  * Bootstrap ProgressBar class
17681  * @cfg {Number} aria_valuenow aria-value now
17682  * @cfg {Number} aria_valuemin aria-value min
17683  * @cfg {Number} aria_valuemax aria-value max
17684  * @cfg {String} label label for the progress bar
17685  * @cfg {String} panel (success | info | warning | danger )
17686  * @cfg {String} role role of the progress bar
17687  * @cfg {String} sr_only text
17688  * 
17689  * 
17690  * @constructor
17691  * Create a new ProgressBar
17692  * @param {Object} config The config object
17693  */
17694
17695 Roo.bootstrap.ProgressBar = function(config){
17696     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17697 };
17698
17699 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17700     
17701     aria_valuenow : 0,
17702     aria_valuemin : 0,
17703     aria_valuemax : 100,
17704     label : false,
17705     panel : false,
17706     role : false,
17707     sr_only: false,
17708     
17709     getAutoCreate : function()
17710     {
17711         
17712         var cfg = {
17713             tag: 'div',
17714             cls: 'progress-bar',
17715             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17716         };
17717         
17718         if(this.sr_only){
17719             cfg.cn = {
17720                 tag: 'span',
17721                 cls: 'sr-only',
17722                 html: this.sr_only
17723             }
17724         }
17725         
17726         if(this.role){
17727             cfg.role = this.role;
17728         }
17729         
17730         if(this.aria_valuenow){
17731             cfg['aria-valuenow'] = this.aria_valuenow;
17732         }
17733         
17734         if(this.aria_valuemin){
17735             cfg['aria-valuemin'] = this.aria_valuemin;
17736         }
17737         
17738         if(this.aria_valuemax){
17739             cfg['aria-valuemax'] = this.aria_valuemax;
17740         }
17741         
17742         if(this.label && !this.sr_only){
17743             cfg.html = this.label;
17744         }
17745         
17746         if(this.panel){
17747             cfg.cls += ' progress-bar-' + this.panel;
17748         }
17749         
17750         return cfg;
17751     },
17752     
17753     update : function(aria_valuenow)
17754     {
17755         this.aria_valuenow = aria_valuenow;
17756         
17757         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17758     }
17759    
17760 });
17761
17762  
17763
17764  /*
17765  * - LGPL
17766  *
17767  * column
17768  * 
17769  */
17770
17771 /**
17772  * @class Roo.bootstrap.TabGroup
17773  * @extends Roo.bootstrap.Column
17774  * Bootstrap Column class
17775  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17776  * @cfg {Boolean} carousel true to make the group behave like a carousel
17777  * @cfg {Boolean} bullets show bullets for the panels
17778  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17779  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17780  * @cfg {Boolean} showarrow (true|false) show arrow default true
17781  * 
17782  * @constructor
17783  * Create a new TabGroup
17784  * @param {Object} config The config object
17785  */
17786
17787 Roo.bootstrap.TabGroup = function(config){
17788     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17789     if (!this.navId) {
17790         this.navId = Roo.id();
17791     }
17792     this.tabs = [];
17793     Roo.bootstrap.TabGroup.register(this);
17794     
17795 };
17796
17797 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17798     
17799     carousel : false,
17800     transition : false,
17801     bullets : 0,
17802     timer : 0,
17803     autoslide : false,
17804     slideFn : false,
17805     slideOnTouch : false,
17806     showarrow : true,
17807     
17808     getAutoCreate : function()
17809     {
17810         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17811         
17812         cfg.cls += ' tab-content';
17813         
17814         if (this.carousel) {
17815             cfg.cls += ' carousel slide';
17816             
17817             cfg.cn = [{
17818                cls : 'carousel-inner',
17819                cn : []
17820             }];
17821         
17822             if(this.bullets  && !Roo.isTouch){
17823                 
17824                 var bullets = {
17825                     cls : 'carousel-bullets',
17826                     cn : []
17827                 };
17828                
17829                 if(this.bullets_cls){
17830                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17831                 }
17832                 
17833                 bullets.cn.push({
17834                     cls : 'clear'
17835                 });
17836                 
17837                 cfg.cn[0].cn.push(bullets);
17838             }
17839             
17840             if(this.showarrow){
17841                 cfg.cn[0].cn.push({
17842                     tag : 'div',
17843                     class : 'carousel-arrow',
17844                     cn : [
17845                         {
17846                             tag : 'div',
17847                             class : 'carousel-prev',
17848                             cn : [
17849                                 {
17850                                     tag : 'i',
17851                                     class : 'fa fa-chevron-left'
17852                                 }
17853                             ]
17854                         },
17855                         {
17856                             tag : 'div',
17857                             class : 'carousel-next',
17858                             cn : [
17859                                 {
17860                                     tag : 'i',
17861                                     class : 'fa fa-chevron-right'
17862                                 }
17863                             ]
17864                         }
17865                     ]
17866                 });
17867             }
17868             
17869         }
17870         
17871         return cfg;
17872     },
17873     
17874     initEvents:  function()
17875     {
17876 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17877 //            this.el.on("touchstart", this.onTouchStart, this);
17878 //        }
17879         
17880         if(this.autoslide){
17881             var _this = this;
17882             
17883             this.slideFn = window.setInterval(function() {
17884                 _this.showPanelNext();
17885             }, this.timer);
17886         }
17887         
17888         if(this.showarrow){
17889             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17890             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17891         }
17892         
17893         
17894     },
17895     
17896 //    onTouchStart : function(e, el, o)
17897 //    {
17898 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17899 //            return;
17900 //        }
17901 //        
17902 //        this.showPanelNext();
17903 //    },
17904     
17905     
17906     getChildContainer : function()
17907     {
17908         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17909     },
17910     
17911     /**
17912     * register a Navigation item
17913     * @param {Roo.bootstrap.NavItem} the navitem to add
17914     */
17915     register : function(item)
17916     {
17917         this.tabs.push( item);
17918         item.navId = this.navId; // not really needed..
17919         this.addBullet();
17920     
17921     },
17922     
17923     getActivePanel : function()
17924     {
17925         var r = false;
17926         Roo.each(this.tabs, function(t) {
17927             if (t.active) {
17928                 r = t;
17929                 return false;
17930             }
17931             return null;
17932         });
17933         return r;
17934         
17935     },
17936     getPanelByName : function(n)
17937     {
17938         var r = false;
17939         Roo.each(this.tabs, function(t) {
17940             if (t.tabId == n) {
17941                 r = t;
17942                 return false;
17943             }
17944             return null;
17945         });
17946         return r;
17947     },
17948     indexOfPanel : function(p)
17949     {
17950         var r = false;
17951         Roo.each(this.tabs, function(t,i) {
17952             if (t.tabId == p.tabId) {
17953                 r = i;
17954                 return false;
17955             }
17956             return null;
17957         });
17958         return r;
17959     },
17960     /**
17961      * show a specific panel
17962      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17963      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17964      */
17965     showPanel : function (pan)
17966     {
17967         if(this.transition || typeof(pan) == 'undefined'){
17968             Roo.log("waiting for the transitionend");
17969             return;
17970         }
17971         
17972         if (typeof(pan) == 'number') {
17973             pan = this.tabs[pan];
17974         }
17975         
17976         if (typeof(pan) == 'string') {
17977             pan = this.getPanelByName(pan);
17978         }
17979         
17980         var cur = this.getActivePanel();
17981         
17982         if(!pan || !cur){
17983             Roo.log('pan or acitve pan is undefined');
17984             return false;
17985         }
17986         
17987         if (pan.tabId == this.getActivePanel().tabId) {
17988             return true;
17989         }
17990         
17991         if (false === cur.fireEvent('beforedeactivate')) {
17992             return false;
17993         }
17994         
17995         if(this.bullets > 0 && !Roo.isTouch){
17996             this.setActiveBullet(this.indexOfPanel(pan));
17997         }
17998         
17999         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18000             
18001             this.transition = true;
18002             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
18003             var lr = dir == 'next' ? 'left' : 'right';
18004             pan.el.addClass(dir); // or prev
18005             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18006             cur.el.addClass(lr); // or right
18007             pan.el.addClass(lr);
18008             
18009             var _this = this;
18010             cur.el.on('transitionend', function() {
18011                 Roo.log("trans end?");
18012                 
18013                 pan.el.removeClass([lr,dir]);
18014                 pan.setActive(true);
18015                 
18016                 cur.el.removeClass([lr]);
18017                 cur.setActive(false);
18018                 
18019                 _this.transition = false;
18020                 
18021             }, this, { single:  true } );
18022             
18023             return true;
18024         }
18025         
18026         cur.setActive(false);
18027         pan.setActive(true);
18028         
18029         return true;
18030         
18031     },
18032     showPanelNext : function()
18033     {
18034         var i = this.indexOfPanel(this.getActivePanel());
18035         
18036         if (i >= this.tabs.length - 1 && !this.autoslide) {
18037             return;
18038         }
18039         
18040         if (i >= this.tabs.length - 1 && this.autoslide) {
18041             i = -1;
18042         }
18043         
18044         this.showPanel(this.tabs[i+1]);
18045     },
18046     
18047     showPanelPrev : function()
18048     {
18049         var i = this.indexOfPanel(this.getActivePanel());
18050         
18051         if (i  < 1 && !this.autoslide) {
18052             return;
18053         }
18054         
18055         if (i < 1 && this.autoslide) {
18056             i = this.tabs.length;
18057         }
18058         
18059         this.showPanel(this.tabs[i-1]);
18060     },
18061     
18062     
18063     addBullet: function()
18064     {
18065         if(!this.bullets || Roo.isTouch){
18066             return;
18067         }
18068         var ctr = this.el.select('.carousel-bullets',true).first();
18069         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18070         var bullet = ctr.createChild({
18071             cls : 'bullet bullet-' + i
18072         },ctr.dom.lastChild);
18073         
18074         
18075         var _this = this;
18076         
18077         bullet.on('click', (function(e, el, o, ii, t){
18078
18079             e.preventDefault();
18080
18081             this.showPanel(ii);
18082
18083             if(this.autoslide && this.slideFn){
18084                 clearInterval(this.slideFn);
18085                 this.slideFn = window.setInterval(function() {
18086                     _this.showPanelNext();
18087                 }, this.timer);
18088             }
18089
18090         }).createDelegate(this, [i, bullet], true));
18091                 
18092         
18093     },
18094      
18095     setActiveBullet : function(i)
18096     {
18097         if(Roo.isTouch){
18098             return;
18099         }
18100         
18101         Roo.each(this.el.select('.bullet', true).elements, function(el){
18102             el.removeClass('selected');
18103         });
18104
18105         var bullet = this.el.select('.bullet-' + i, true).first();
18106         
18107         if(!bullet){
18108             return;
18109         }
18110         
18111         bullet.addClass('selected');
18112     }
18113     
18114     
18115   
18116 });
18117
18118  
18119
18120  
18121  
18122 Roo.apply(Roo.bootstrap.TabGroup, {
18123     
18124     groups: {},
18125      /**
18126     * register a Navigation Group
18127     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18128     */
18129     register : function(navgrp)
18130     {
18131         this.groups[navgrp.navId] = navgrp;
18132         
18133     },
18134     /**
18135     * fetch a Navigation Group based on the navigation ID
18136     * if one does not exist , it will get created.
18137     * @param {string} the navgroup to add
18138     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18139     */
18140     get: function(navId) {
18141         if (typeof(this.groups[navId]) == 'undefined') {
18142             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18143         }
18144         return this.groups[navId] ;
18145     }
18146     
18147     
18148     
18149 });
18150
18151  /*
18152  * - LGPL
18153  *
18154  * TabPanel
18155  * 
18156  */
18157
18158 /**
18159  * @class Roo.bootstrap.TabPanel
18160  * @extends Roo.bootstrap.Component
18161  * Bootstrap TabPanel class
18162  * @cfg {Boolean} active panel active
18163  * @cfg {String} html panel content
18164  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18165  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18166  * @cfg {String} href click to link..
18167  * 
18168  * 
18169  * @constructor
18170  * Create a new TabPanel
18171  * @param {Object} config The config object
18172  */
18173
18174 Roo.bootstrap.TabPanel = function(config){
18175     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18176     this.addEvents({
18177         /**
18178              * @event changed
18179              * Fires when the active status changes
18180              * @param {Roo.bootstrap.TabPanel} this
18181              * @param {Boolean} state the new state
18182             
18183          */
18184         'changed': true,
18185         /**
18186              * @event beforedeactivate
18187              * Fires before a tab is de-activated - can be used to do validation on a form.
18188              * @param {Roo.bootstrap.TabPanel} this
18189              * @return {Boolean} false if there is an error
18190             
18191          */
18192         'beforedeactivate': true
18193      });
18194     
18195     this.tabId = this.tabId || Roo.id();
18196   
18197 };
18198
18199 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18200     
18201     active: false,
18202     html: false,
18203     tabId: false,
18204     navId : false,
18205     href : '',
18206     
18207     getAutoCreate : function(){
18208         var cfg = {
18209             tag: 'div',
18210             // item is needed for carousel - not sure if it has any effect otherwise
18211             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18212             html: this.html || ''
18213         };
18214         
18215         if(this.active){
18216             cfg.cls += ' active';
18217         }
18218         
18219         if(this.tabId){
18220             cfg.tabId = this.tabId;
18221         }
18222         
18223         
18224         return cfg;
18225     },
18226     
18227     initEvents:  function()
18228     {
18229         var p = this.parent();
18230         
18231         this.navId = this.navId || p.navId;
18232         
18233         if (typeof(this.navId) != 'undefined') {
18234             // not really needed.. but just in case.. parent should be a NavGroup.
18235             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18236             
18237             tg.register(this);
18238             
18239             var i = tg.tabs.length - 1;
18240             
18241             if(this.active && tg.bullets > 0 && i < tg.bullets){
18242                 tg.setActiveBullet(i);
18243             }
18244         }
18245         
18246         this.el.on('click', this.onClick, this);
18247         
18248         if(Roo.isTouch){
18249             this.el.on("touchstart", this.onTouchStart, this);
18250             this.el.on("touchmove", this.onTouchMove, this);
18251             this.el.on("touchend", this.onTouchEnd, this);
18252         }
18253         
18254     },
18255     
18256     onRender : function(ct, position)
18257     {
18258         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18259     },
18260     
18261     setActive : function(state)
18262     {
18263         Roo.log("panel - set active " + this.tabId + "=" + state);
18264         
18265         this.active = state;
18266         if (!state) {
18267             this.el.removeClass('active');
18268             
18269         } else  if (!this.el.hasClass('active')) {
18270             this.el.addClass('active');
18271         }
18272         
18273         this.fireEvent('changed', this, state);
18274     },
18275     
18276     onClick : function(e)
18277     {
18278         e.preventDefault();
18279         
18280         if(!this.href.length){
18281             return;
18282         }
18283         
18284         window.location.href = this.href;
18285     },
18286     
18287     startX : 0,
18288     startY : 0,
18289     endX : 0,
18290     endY : 0,
18291     swiping : false,
18292     
18293     onTouchStart : function(e)
18294     {
18295         this.swiping = false;
18296         
18297         this.startX = e.browserEvent.touches[0].clientX;
18298         this.startY = e.browserEvent.touches[0].clientY;
18299     },
18300     
18301     onTouchMove : function(e)
18302     {
18303         this.swiping = true;
18304         
18305         this.endX = e.browserEvent.touches[0].clientX;
18306         this.endY = e.browserEvent.touches[0].clientY;
18307     },
18308     
18309     onTouchEnd : function(e)
18310     {
18311         if(!this.swiping){
18312             this.onClick(e);
18313             return;
18314         }
18315         
18316         var tabGroup = this.parent();
18317         
18318         if(this.endX > this.startX){ // swiping right
18319             tabGroup.showPanelPrev();
18320             return;
18321         }
18322         
18323         if(this.startX > this.endX){ // swiping left
18324             tabGroup.showPanelNext();
18325             return;
18326         }
18327     }
18328     
18329     
18330 });
18331  
18332
18333  
18334
18335  /*
18336  * - LGPL
18337  *
18338  * DateField
18339  * 
18340  */
18341
18342 /**
18343  * @class Roo.bootstrap.DateField
18344  * @extends Roo.bootstrap.Input
18345  * Bootstrap DateField class
18346  * @cfg {Number} weekStart default 0
18347  * @cfg {String} viewMode default empty, (months|years)
18348  * @cfg {String} minViewMode default empty, (months|years)
18349  * @cfg {Number} startDate default -Infinity
18350  * @cfg {Number} endDate default Infinity
18351  * @cfg {Boolean} todayHighlight default false
18352  * @cfg {Boolean} todayBtn default false
18353  * @cfg {Boolean} calendarWeeks default false
18354  * @cfg {Object} daysOfWeekDisabled default empty
18355  * @cfg {Boolean} singleMode default false (true | false)
18356  * 
18357  * @cfg {Boolean} keyboardNavigation default true
18358  * @cfg {String} language default en
18359  * 
18360  * @constructor
18361  * Create a new DateField
18362  * @param {Object} config The config object
18363  */
18364
18365 Roo.bootstrap.DateField = function(config){
18366     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18367      this.addEvents({
18368             /**
18369              * @event show
18370              * Fires when this field show.
18371              * @param {Roo.bootstrap.DateField} this
18372              * @param {Mixed} date The date value
18373              */
18374             show : true,
18375             /**
18376              * @event show
18377              * Fires when this field hide.
18378              * @param {Roo.bootstrap.DateField} this
18379              * @param {Mixed} date The date value
18380              */
18381             hide : true,
18382             /**
18383              * @event select
18384              * Fires when select a date.
18385              * @param {Roo.bootstrap.DateField} this
18386              * @param {Mixed} date The date value
18387              */
18388             select : true,
18389             /**
18390              * @event beforeselect
18391              * Fires when before select a date.
18392              * @param {Roo.bootstrap.DateField} this
18393              * @param {Mixed} date The date value
18394              */
18395             beforeselect : true
18396         });
18397 };
18398
18399 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18400     
18401     /**
18402      * @cfg {String} format
18403      * The default date format string which can be overriden for localization support.  The format must be
18404      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18405      */
18406     format : "m/d/y",
18407     /**
18408      * @cfg {String} altFormats
18409      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18410      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18411      */
18412     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18413     
18414     weekStart : 0,
18415     
18416     viewMode : '',
18417     
18418     minViewMode : '',
18419     
18420     todayHighlight : false,
18421     
18422     todayBtn: false,
18423     
18424     language: 'en',
18425     
18426     keyboardNavigation: true,
18427     
18428     calendarWeeks: false,
18429     
18430     startDate: -Infinity,
18431     
18432     endDate: Infinity,
18433     
18434     daysOfWeekDisabled: [],
18435     
18436     _events: [],
18437     
18438     singleMode : false,
18439     
18440     UTCDate: function()
18441     {
18442         return new Date(Date.UTC.apply(Date, arguments));
18443     },
18444     
18445     UTCToday: function()
18446     {
18447         var today = new Date();
18448         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18449     },
18450     
18451     getDate: function() {
18452             var d = this.getUTCDate();
18453             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18454     },
18455     
18456     getUTCDate: function() {
18457             return this.date;
18458     },
18459     
18460     setDate: function(d) {
18461             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18462     },
18463     
18464     setUTCDate: function(d) {
18465             this.date = d;
18466             this.setValue(this.formatDate(this.date));
18467     },
18468         
18469     onRender: function(ct, position)
18470     {
18471         
18472         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18473         
18474         this.language = this.language || 'en';
18475         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18476         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18477         
18478         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18479         this.format = this.format || 'm/d/y';
18480         this.isInline = false;
18481         this.isInput = true;
18482         this.component = this.el.select('.add-on', true).first() || false;
18483         this.component = (this.component && this.component.length === 0) ? false : this.component;
18484         this.hasInput = this.component && this.inputEl().length;
18485         
18486         if (typeof(this.minViewMode === 'string')) {
18487             switch (this.minViewMode) {
18488                 case 'months':
18489                     this.minViewMode = 1;
18490                     break;
18491                 case 'years':
18492                     this.minViewMode = 2;
18493                     break;
18494                 default:
18495                     this.minViewMode = 0;
18496                     break;
18497             }
18498         }
18499         
18500         if (typeof(this.viewMode === 'string')) {
18501             switch (this.viewMode) {
18502                 case 'months':
18503                     this.viewMode = 1;
18504                     break;
18505                 case 'years':
18506                     this.viewMode = 2;
18507                     break;
18508                 default:
18509                     this.viewMode = 0;
18510                     break;
18511             }
18512         }
18513                 
18514         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18515         
18516 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18517         
18518         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18519         
18520         this.picker().on('mousedown', this.onMousedown, this);
18521         this.picker().on('click', this.onClick, this);
18522         
18523         this.picker().addClass('datepicker-dropdown');
18524         
18525         this.startViewMode = this.viewMode;
18526         
18527         if(this.singleMode){
18528             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18529                 v.setVisibilityMode(Roo.Element.DISPLAY);
18530                 v.hide();
18531             });
18532             
18533             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18534                 v.setStyle('width', '189px');
18535             });
18536         }
18537         
18538         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18539             if(!this.calendarWeeks){
18540                 v.remove();
18541                 return;
18542             }
18543             
18544             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18545             v.attr('colspan', function(i, val){
18546                 return parseInt(val) + 1;
18547             });
18548         });
18549                         
18550         
18551         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18552         
18553         this.setStartDate(this.startDate);
18554         this.setEndDate(this.endDate);
18555         
18556         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18557         
18558         this.fillDow();
18559         this.fillMonths();
18560         this.update();
18561         this.showMode();
18562         
18563         if(this.isInline) {
18564             this.showPopup();
18565         }
18566     },
18567     
18568     picker : function()
18569     {
18570         return this.pickerEl;
18571 //        return this.el.select('.datepicker', true).first();
18572     },
18573     
18574     fillDow: function()
18575     {
18576         var dowCnt = this.weekStart;
18577         
18578         var dow = {
18579             tag: 'tr',
18580             cn: [
18581                 
18582             ]
18583         };
18584         
18585         if(this.calendarWeeks){
18586             dow.cn.push({
18587                 tag: 'th',
18588                 cls: 'cw',
18589                 html: '&nbsp;'
18590             })
18591         }
18592         
18593         while (dowCnt < this.weekStart + 7) {
18594             dow.cn.push({
18595                 tag: 'th',
18596                 cls: 'dow',
18597                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18598             });
18599         }
18600         
18601         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18602     },
18603     
18604     fillMonths: function()
18605     {    
18606         var i = 0;
18607         var months = this.picker().select('>.datepicker-months td', true).first();
18608         
18609         months.dom.innerHTML = '';
18610         
18611         while (i < 12) {
18612             var month = {
18613                 tag: 'span',
18614                 cls: 'month',
18615                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18616             };
18617             
18618             months.createChild(month);
18619         }
18620         
18621     },
18622     
18623     update: function()
18624     {
18625         this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
18626         
18627         if (this.date < this.startDate) {
18628             this.viewDate = new Date(this.startDate);
18629         } else if (this.date > this.endDate) {
18630             this.viewDate = new Date(this.endDate);
18631         } else {
18632             this.viewDate = new Date(this.date);
18633         }
18634         
18635         this.fill();
18636     },
18637     
18638     fill: function() 
18639     {
18640         var d = new Date(this.viewDate),
18641                 year = d.getUTCFullYear(),
18642                 month = d.getUTCMonth(),
18643                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18644                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18645                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18646                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18647                 currentDate = this.date && this.date.valueOf(),
18648                 today = this.UTCToday();
18649         
18650         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18651         
18652 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18653         
18654 //        this.picker.select('>tfoot th.today').
18655 //                                              .text(dates[this.language].today)
18656 //                                              .toggle(this.todayBtn !== false);
18657     
18658         this.updateNavArrows();
18659         this.fillMonths();
18660                                                 
18661         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18662         
18663         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18664          
18665         prevMonth.setUTCDate(day);
18666         
18667         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18668         
18669         var nextMonth = new Date(prevMonth);
18670         
18671         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18672         
18673         nextMonth = nextMonth.valueOf();
18674         
18675         var fillMonths = false;
18676         
18677         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18678         
18679         while(prevMonth.valueOf() <= nextMonth) {
18680             var clsName = '';
18681             
18682             if (prevMonth.getUTCDay() === this.weekStart) {
18683                 if(fillMonths){
18684                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18685                 }
18686                     
18687                 fillMonths = {
18688                     tag: 'tr',
18689                     cn: []
18690                 };
18691                 
18692                 if(this.calendarWeeks){
18693                     // ISO 8601: First week contains first thursday.
18694                     // ISO also states week starts on Monday, but we can be more abstract here.
18695                     var
18696                     // Start of current week: based on weekstart/current date
18697                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18698                     // Thursday of this week
18699                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18700                     // First Thursday of year, year from thursday
18701                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18702                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18703                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18704                     
18705                     fillMonths.cn.push({
18706                         tag: 'td',
18707                         cls: 'cw',
18708                         html: calWeek
18709                     });
18710                 }
18711             }
18712             
18713             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18714                 clsName += ' old';
18715             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18716                 clsName += ' new';
18717             }
18718             if (this.todayHighlight &&
18719                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18720                 prevMonth.getUTCMonth() == today.getMonth() &&
18721                 prevMonth.getUTCDate() == today.getDate()) {
18722                 clsName += ' today';
18723             }
18724             
18725             if (currentDate && prevMonth.valueOf() === currentDate) {
18726                 clsName += ' active';
18727             }
18728             
18729             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18730                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18731                     clsName += ' disabled';
18732             }
18733             
18734             fillMonths.cn.push({
18735                 tag: 'td',
18736                 cls: 'day ' + clsName,
18737                 html: prevMonth.getDate()
18738             });
18739             
18740             prevMonth.setDate(prevMonth.getDate()+1);
18741         }
18742           
18743         var currentYear = this.date && this.date.getUTCFullYear();
18744         var currentMonth = this.date && this.date.getUTCMonth();
18745         
18746         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18747         
18748         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18749             v.removeClass('active');
18750             
18751             if(currentYear === year && k === currentMonth){
18752                 v.addClass('active');
18753             }
18754             
18755             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18756                 v.addClass('disabled');
18757             }
18758             
18759         });
18760         
18761         
18762         year = parseInt(year/10, 10) * 10;
18763         
18764         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18765         
18766         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18767         
18768         year -= 1;
18769         for (var i = -1; i < 11; i++) {
18770             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18771                 tag: 'span',
18772                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18773                 html: year
18774             });
18775             
18776             year += 1;
18777         }
18778     },
18779     
18780     showMode: function(dir) 
18781     {
18782         if (dir) {
18783             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18784         }
18785         
18786         Roo.each(this.picker().select('>div',true).elements, function(v){
18787             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18788             v.hide();
18789         });
18790         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18791     },
18792     
18793     place: function()
18794     {
18795         if(this.isInline) {
18796             return;
18797         }
18798         
18799         this.picker().removeClass(['bottom', 'top']);
18800         
18801         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18802             /*
18803              * place to the top of element!
18804              *
18805              */
18806             
18807             this.picker().addClass('top');
18808             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18809             
18810             return;
18811         }
18812         
18813         this.picker().addClass('bottom');
18814         
18815         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18816     },
18817     
18818     parseDate : function(value)
18819     {
18820         if(!value || value instanceof Date){
18821             return value;
18822         }
18823         var v = Date.parseDate(value, this.format);
18824         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18825             v = Date.parseDate(value, 'Y-m-d');
18826         }
18827         if(!v && this.altFormats){
18828             if(!this.altFormatsArray){
18829                 this.altFormatsArray = this.altFormats.split("|");
18830             }
18831             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18832                 v = Date.parseDate(value, this.altFormatsArray[i]);
18833             }
18834         }
18835         return v;
18836     },
18837     
18838     formatDate : function(date, fmt)
18839     {   
18840         return (!date || !(date instanceof Date)) ?
18841         date : date.dateFormat(fmt || this.format);
18842     },
18843     
18844     onFocus : function()
18845     {
18846         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18847         this.showPopup();
18848     },
18849     
18850     onBlur : function()
18851     {
18852         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18853         
18854         var d = this.inputEl().getValue();
18855         
18856         this.setValue(d);
18857                 
18858         this.hidePopup();
18859     },
18860     
18861     showPopup : function()
18862     {
18863         this.picker().show();
18864         this.update();
18865         this.place();
18866         
18867         this.fireEvent('showpopup', this, this.date);
18868     },
18869     
18870     hidePopup : function()
18871     {
18872         if(this.isInline) {
18873             return;
18874         }
18875         this.picker().hide();
18876         this.viewMode = this.startViewMode;
18877         this.showMode();
18878         
18879         this.fireEvent('hidepopup', this, this.date);
18880         
18881     },
18882     
18883     onMousedown: function(e)
18884     {
18885         e.stopPropagation();
18886         e.preventDefault();
18887     },
18888     
18889     keyup: function(e)
18890     {
18891         Roo.bootstrap.DateField.superclass.keyup.call(this);
18892         this.update();
18893     },
18894
18895     setValue: function(v)
18896     {
18897         if(this.fireEvent('beforeselect', this, v) !== false){
18898             var d = new Date(this.parseDate(v) ).clearTime();
18899         
18900             if(isNaN(d.getTime())){
18901                 this.date = this.viewDate = '';
18902                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18903                 return;
18904             }
18905
18906             v = this.formatDate(d);
18907
18908             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18909
18910             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18911
18912             this.update();
18913
18914             this.fireEvent('select', this, this.date);
18915         }
18916     },
18917     
18918     getValue: function()
18919     {
18920         return this.formatDate(this.date);
18921     },
18922     
18923     fireKey: function(e)
18924     {
18925         if (!this.picker().isVisible()){
18926             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18927                 this.showPopup();
18928             }
18929             return;
18930         }
18931         
18932         var dateChanged = false,
18933         dir, day, month,
18934         newDate, newViewDate;
18935         
18936         switch(e.keyCode){
18937             case 27: // escape
18938                 this.hidePopup();
18939                 e.preventDefault();
18940                 break;
18941             case 37: // left
18942             case 39: // right
18943                 if (!this.keyboardNavigation) {
18944                     break;
18945                 }
18946                 dir = e.keyCode == 37 ? -1 : 1;
18947                 
18948                 if (e.ctrlKey){
18949                     newDate = this.moveYear(this.date, dir);
18950                     newViewDate = this.moveYear(this.viewDate, dir);
18951                 } else if (e.shiftKey){
18952                     newDate = this.moveMonth(this.date, dir);
18953                     newViewDate = this.moveMonth(this.viewDate, dir);
18954                 } else {
18955                     newDate = new Date(this.date);
18956                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18957                     newViewDate = new Date(this.viewDate);
18958                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18959                 }
18960                 if (this.dateWithinRange(newDate)){
18961                     this.date = newDate;
18962                     this.viewDate = newViewDate;
18963                     this.setValue(this.formatDate(this.date));
18964 //                    this.update();
18965                     e.preventDefault();
18966                     dateChanged = true;
18967                 }
18968                 break;
18969             case 38: // up
18970             case 40: // down
18971                 if (!this.keyboardNavigation) {
18972                     break;
18973                 }
18974                 dir = e.keyCode == 38 ? -1 : 1;
18975                 if (e.ctrlKey){
18976                     newDate = this.moveYear(this.date, dir);
18977                     newViewDate = this.moveYear(this.viewDate, dir);
18978                 } else if (e.shiftKey){
18979                     newDate = this.moveMonth(this.date, dir);
18980                     newViewDate = this.moveMonth(this.viewDate, dir);
18981                 } else {
18982                     newDate = new Date(this.date);
18983                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18984                     newViewDate = new Date(this.viewDate);
18985                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18986                 }
18987                 if (this.dateWithinRange(newDate)){
18988                     this.date = newDate;
18989                     this.viewDate = newViewDate;
18990                     this.setValue(this.formatDate(this.date));
18991 //                    this.update();
18992                     e.preventDefault();
18993                     dateChanged = true;
18994                 }
18995                 break;
18996             case 13: // enter
18997                 this.setValue(this.formatDate(this.date));
18998                 this.hidePopup();
18999                 e.preventDefault();
19000                 break;
19001             case 9: // tab
19002                 this.setValue(this.formatDate(this.date));
19003                 this.hidePopup();
19004                 break;
19005             case 16: // shift
19006             case 17: // ctrl
19007             case 18: // alt
19008                 break;
19009             default :
19010                 this.hide();
19011                 
19012         }
19013     },
19014     
19015     
19016     onClick: function(e) 
19017     {
19018         e.stopPropagation();
19019         e.preventDefault();
19020         
19021         var target = e.getTarget();
19022         
19023         if(target.nodeName.toLowerCase() === 'i'){
19024             target = Roo.get(target).dom.parentNode;
19025         }
19026         
19027         var nodeName = target.nodeName;
19028         var className = target.className;
19029         var html = target.innerHTML;
19030         //Roo.log(nodeName);
19031         
19032         switch(nodeName.toLowerCase()) {
19033             case 'th':
19034                 switch(className) {
19035                     case 'switch':
19036                         this.showMode(1);
19037                         break;
19038                     case 'prev':
19039                     case 'next':
19040                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19041                         switch(this.viewMode){
19042                                 case 0:
19043                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19044                                         break;
19045                                 case 1:
19046                                 case 2:
19047                                         this.viewDate = this.moveYear(this.viewDate, dir);
19048                                         break;
19049                         }
19050                         this.fill();
19051                         break;
19052                     case 'today':
19053                         var date = new Date();
19054                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19055 //                        this.fill()
19056                         this.setValue(this.formatDate(this.date));
19057                         
19058                         this.hidePopup();
19059                         break;
19060                 }
19061                 break;
19062             case 'span':
19063                 if (className.indexOf('disabled') < 0) {
19064                     this.viewDate.setUTCDate(1);
19065                     if (className.indexOf('month') > -1) {
19066                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19067                     } else {
19068                         var year = parseInt(html, 10) || 0;
19069                         this.viewDate.setUTCFullYear(year);
19070                         
19071                     }
19072                     
19073                     if(this.singleMode){
19074                         this.setValue(this.formatDate(this.viewDate));
19075                         this.hidePopup();
19076                         return;
19077                     }
19078                     
19079                     this.showMode(-1);
19080                     this.fill();
19081                 }
19082                 break;
19083                 
19084             case 'td':
19085                 //Roo.log(className);
19086                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19087                     var day = parseInt(html, 10) || 1;
19088                     var year = this.viewDate.getUTCFullYear(),
19089                         month = this.viewDate.getUTCMonth();
19090
19091                     if (className.indexOf('old') > -1) {
19092                         if(month === 0 ){
19093                             month = 11;
19094                             year -= 1;
19095                         }else{
19096                             month -= 1;
19097                         }
19098                     } else if (className.indexOf('new') > -1) {
19099                         if (month == 11) {
19100                             month = 0;
19101                             year += 1;
19102                         } else {
19103                             month += 1;
19104                         }
19105                     }
19106                     //Roo.log([year,month,day]);
19107                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19108                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19109 //                    this.fill();
19110                     //Roo.log(this.formatDate(this.date));
19111                     this.setValue(this.formatDate(this.date));
19112                     this.hidePopup();
19113                 }
19114                 break;
19115         }
19116     },
19117     
19118     setStartDate: function(startDate)
19119     {
19120         this.startDate = startDate || -Infinity;
19121         if (this.startDate !== -Infinity) {
19122             this.startDate = this.parseDate(this.startDate);
19123         }
19124         this.update();
19125         this.updateNavArrows();
19126     },
19127
19128     setEndDate: function(endDate)
19129     {
19130         this.endDate = endDate || Infinity;
19131         if (this.endDate !== Infinity) {
19132             this.endDate = this.parseDate(this.endDate);
19133         }
19134         this.update();
19135         this.updateNavArrows();
19136     },
19137     
19138     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19139     {
19140         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19141         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19142             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19143         }
19144         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19145             return parseInt(d, 10);
19146         });
19147         this.update();
19148         this.updateNavArrows();
19149     },
19150     
19151     updateNavArrows: function() 
19152     {
19153         if(this.singleMode){
19154             return;
19155         }
19156         
19157         var d = new Date(this.viewDate),
19158         year = d.getUTCFullYear(),
19159         month = d.getUTCMonth();
19160         
19161         Roo.each(this.picker().select('.prev', true).elements, function(v){
19162             v.show();
19163             switch (this.viewMode) {
19164                 case 0:
19165
19166                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19167                         v.hide();
19168                     }
19169                     break;
19170                 case 1:
19171                 case 2:
19172                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19173                         v.hide();
19174                     }
19175                     break;
19176             }
19177         });
19178         
19179         Roo.each(this.picker().select('.next', true).elements, function(v){
19180             v.show();
19181             switch (this.viewMode) {
19182                 case 0:
19183
19184                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19185                         v.hide();
19186                     }
19187                     break;
19188                 case 1:
19189                 case 2:
19190                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19191                         v.hide();
19192                     }
19193                     break;
19194             }
19195         })
19196     },
19197     
19198     moveMonth: function(date, dir)
19199     {
19200         if (!dir) {
19201             return date;
19202         }
19203         var new_date = new Date(date.valueOf()),
19204         day = new_date.getUTCDate(),
19205         month = new_date.getUTCMonth(),
19206         mag = Math.abs(dir),
19207         new_month, test;
19208         dir = dir > 0 ? 1 : -1;
19209         if (mag == 1){
19210             test = dir == -1
19211             // If going back one month, make sure month is not current month
19212             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19213             ? function(){
19214                 return new_date.getUTCMonth() == month;
19215             }
19216             // If going forward one month, make sure month is as expected
19217             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19218             : function(){
19219                 return new_date.getUTCMonth() != new_month;
19220             };
19221             new_month = month + dir;
19222             new_date.setUTCMonth(new_month);
19223             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19224             if (new_month < 0 || new_month > 11) {
19225                 new_month = (new_month + 12) % 12;
19226             }
19227         } else {
19228             // For magnitudes >1, move one month at a time...
19229             for (var i=0; i<mag; i++) {
19230                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19231                 new_date = this.moveMonth(new_date, dir);
19232             }
19233             // ...then reset the day, keeping it in the new month
19234             new_month = new_date.getUTCMonth();
19235             new_date.setUTCDate(day);
19236             test = function(){
19237                 return new_month != new_date.getUTCMonth();
19238             };
19239         }
19240         // Common date-resetting loop -- if date is beyond end of month, make it
19241         // end of month
19242         while (test()){
19243             new_date.setUTCDate(--day);
19244             new_date.setUTCMonth(new_month);
19245         }
19246         return new_date;
19247     },
19248
19249     moveYear: function(date, dir)
19250     {
19251         return this.moveMonth(date, dir*12);
19252     },
19253
19254     dateWithinRange: function(date)
19255     {
19256         return date >= this.startDate && date <= this.endDate;
19257     },
19258
19259     
19260     remove: function() 
19261     {
19262         this.picker().remove();
19263     },
19264     
19265     validateValue : function(value)
19266     {
19267         if(this.getVisibilityEl().hasClass('hidden')){
19268             return true;
19269         }
19270         
19271         if(value.length < 1)  {
19272             if(this.allowBlank){
19273                 return true;
19274             }
19275             return false;
19276         }
19277         
19278         if(value.length < this.minLength){
19279             return false;
19280         }
19281         if(value.length > this.maxLength){
19282             return false;
19283         }
19284         if(this.vtype){
19285             var vt = Roo.form.VTypes;
19286             if(!vt[this.vtype](value, this)){
19287                 return false;
19288             }
19289         }
19290         if(typeof this.validator == "function"){
19291             var msg = this.validator(value);
19292             if(msg !== true){
19293                 return false;
19294             }
19295         }
19296         
19297         if(this.regex && !this.regex.test(value)){
19298             return false;
19299         }
19300         
19301         if(typeof(this.parseDate(value)) == 'undefined'){
19302             return false;
19303         }
19304         
19305         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19306             return false;
19307         }      
19308         
19309         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19310             return false;
19311         } 
19312         
19313         
19314         return true;
19315     },
19316     
19317     reset : function()
19318     {
19319         this.date = this.viewDate = '';
19320         
19321         Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19322     }
19323    
19324 });
19325
19326 Roo.apply(Roo.bootstrap.DateField,  {
19327     
19328     head : {
19329         tag: 'thead',
19330         cn: [
19331         {
19332             tag: 'tr',
19333             cn: [
19334             {
19335                 tag: 'th',
19336                 cls: 'prev',
19337                 html: '<i class="fa fa-arrow-left"/>'
19338             },
19339             {
19340                 tag: 'th',
19341                 cls: 'switch',
19342                 colspan: '5'
19343             },
19344             {
19345                 tag: 'th',
19346                 cls: 'next',
19347                 html: '<i class="fa fa-arrow-right"/>'
19348             }
19349
19350             ]
19351         }
19352         ]
19353     },
19354     
19355     content : {
19356         tag: 'tbody',
19357         cn: [
19358         {
19359             tag: 'tr',
19360             cn: [
19361             {
19362                 tag: 'td',
19363                 colspan: '7'
19364             }
19365             ]
19366         }
19367         ]
19368     },
19369     
19370     footer : {
19371         tag: 'tfoot',
19372         cn: [
19373         {
19374             tag: 'tr',
19375             cn: [
19376             {
19377                 tag: 'th',
19378                 colspan: '7',
19379                 cls: 'today'
19380             }
19381                     
19382             ]
19383         }
19384         ]
19385     },
19386     
19387     dates:{
19388         en: {
19389             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19390             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19391             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19392             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19393             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19394             today: "Today"
19395         }
19396     },
19397     
19398     modes: [
19399     {
19400         clsName: 'days',
19401         navFnc: 'Month',
19402         navStep: 1
19403     },
19404     {
19405         clsName: 'months',
19406         navFnc: 'FullYear',
19407         navStep: 1
19408     },
19409     {
19410         clsName: 'years',
19411         navFnc: 'FullYear',
19412         navStep: 10
19413     }]
19414 });
19415
19416 Roo.apply(Roo.bootstrap.DateField,  {
19417   
19418     template : {
19419         tag: 'div',
19420         cls: 'datepicker dropdown-menu roo-dynamic',
19421         cn: [
19422         {
19423             tag: 'div',
19424             cls: 'datepicker-days',
19425             cn: [
19426             {
19427                 tag: 'table',
19428                 cls: 'table-condensed',
19429                 cn:[
19430                 Roo.bootstrap.DateField.head,
19431                 {
19432                     tag: 'tbody'
19433                 },
19434                 Roo.bootstrap.DateField.footer
19435                 ]
19436             }
19437             ]
19438         },
19439         {
19440             tag: 'div',
19441             cls: 'datepicker-months',
19442             cn: [
19443             {
19444                 tag: 'table',
19445                 cls: 'table-condensed',
19446                 cn:[
19447                 Roo.bootstrap.DateField.head,
19448                 Roo.bootstrap.DateField.content,
19449                 Roo.bootstrap.DateField.footer
19450                 ]
19451             }
19452             ]
19453         },
19454         {
19455             tag: 'div',
19456             cls: 'datepicker-years',
19457             cn: [
19458             {
19459                 tag: 'table',
19460                 cls: 'table-condensed',
19461                 cn:[
19462                 Roo.bootstrap.DateField.head,
19463                 Roo.bootstrap.DateField.content,
19464                 Roo.bootstrap.DateField.footer
19465                 ]
19466             }
19467             ]
19468         }
19469         ]
19470     }
19471 });
19472
19473  
19474
19475  /*
19476  * - LGPL
19477  *
19478  * TimeField
19479  * 
19480  */
19481
19482 /**
19483  * @class Roo.bootstrap.TimeField
19484  * @extends Roo.bootstrap.Input
19485  * Bootstrap DateField class
19486  * 
19487  * 
19488  * @constructor
19489  * Create a new TimeField
19490  * @param {Object} config The config object
19491  */
19492
19493 Roo.bootstrap.TimeField = function(config){
19494     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19495     this.addEvents({
19496             /**
19497              * @event show
19498              * Fires when this field show.
19499              * @param {Roo.bootstrap.DateField} thisthis
19500              * @param {Mixed} date The date value
19501              */
19502             show : true,
19503             /**
19504              * @event show
19505              * Fires when this field hide.
19506              * @param {Roo.bootstrap.DateField} this
19507              * @param {Mixed} date The date value
19508              */
19509             hide : true,
19510             /**
19511              * @event select
19512              * Fires when select a date.
19513              * @param {Roo.bootstrap.DateField} this
19514              * @param {Mixed} date The date value
19515              */
19516             select : true
19517         });
19518 };
19519
19520 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19521     
19522     /**
19523      * @cfg {String} format
19524      * The default time format string which can be overriden for localization support.  The format must be
19525      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19526      */
19527     format : "H:i",
19528        
19529     onRender: function(ct, position)
19530     {
19531         
19532         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19533                 
19534         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19535         
19536         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19537         
19538         this.pop = this.picker().select('>.datepicker-time',true).first();
19539         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19540         
19541         this.picker().on('mousedown', this.onMousedown, this);
19542         this.picker().on('click', this.onClick, this);
19543         
19544         this.picker().addClass('datepicker-dropdown');
19545     
19546         this.fillTime();
19547         this.update();
19548             
19549         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19550         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19551         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19552         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19553         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19554         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19555
19556     },
19557     
19558     fireKey: function(e){
19559         if (!this.picker().isVisible()){
19560             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19561                 this.show();
19562             }
19563             return;
19564         }
19565
19566         e.preventDefault();
19567         
19568         switch(e.keyCode){
19569             case 27: // escape
19570                 this.hide();
19571                 break;
19572             case 37: // left
19573             case 39: // right
19574                 this.onTogglePeriod();
19575                 break;
19576             case 38: // up
19577                 this.onIncrementMinutes();
19578                 break;
19579             case 40: // down
19580                 this.onDecrementMinutes();
19581                 break;
19582             case 13: // enter
19583             case 9: // tab
19584                 this.setTime();
19585                 break;
19586         }
19587     },
19588     
19589     onClick: function(e) {
19590         e.stopPropagation();
19591         e.preventDefault();
19592     },
19593     
19594     picker : function()
19595     {
19596         return this.el.select('.datepicker', true).first();
19597     },
19598     
19599     fillTime: function()
19600     {    
19601         var time = this.pop.select('tbody', true).first();
19602         
19603         time.dom.innerHTML = '';
19604         
19605         time.createChild({
19606             tag: 'tr',
19607             cn: [
19608                 {
19609                     tag: 'td',
19610                     cn: [
19611                         {
19612                             tag: 'a',
19613                             href: '#',
19614                             cls: 'btn',
19615                             cn: [
19616                                 {
19617                                     tag: 'span',
19618                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19619                                 }
19620                             ]
19621                         } 
19622                     ]
19623                 },
19624                 {
19625                     tag: 'td',
19626                     cls: 'separator'
19627                 },
19628                 {
19629                     tag: 'td',
19630                     cn: [
19631                         {
19632                             tag: 'a',
19633                             href: '#',
19634                             cls: 'btn',
19635                             cn: [
19636                                 {
19637                                     tag: 'span',
19638                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19639                                 }
19640                             ]
19641                         }
19642                     ]
19643                 },
19644                 {
19645                     tag: 'td',
19646                     cls: 'separator'
19647                 }
19648             ]
19649         });
19650         
19651         time.createChild({
19652             tag: 'tr',
19653             cn: [
19654                 {
19655                     tag: 'td',
19656                     cn: [
19657                         {
19658                             tag: 'span',
19659                             cls: 'timepicker-hour',
19660                             html: '00'
19661                         }  
19662                     ]
19663                 },
19664                 {
19665                     tag: 'td',
19666                     cls: 'separator',
19667                     html: ':'
19668                 },
19669                 {
19670                     tag: 'td',
19671                     cn: [
19672                         {
19673                             tag: 'span',
19674                             cls: 'timepicker-minute',
19675                             html: '00'
19676                         }  
19677                     ]
19678                 },
19679                 {
19680                     tag: 'td',
19681                     cls: 'separator'
19682                 },
19683                 {
19684                     tag: 'td',
19685                     cn: [
19686                         {
19687                             tag: 'button',
19688                             type: 'button',
19689                             cls: 'btn btn-primary period',
19690                             html: 'AM'
19691                             
19692                         }
19693                     ]
19694                 }
19695             ]
19696         });
19697         
19698         time.createChild({
19699             tag: 'tr',
19700             cn: [
19701                 {
19702                     tag: 'td',
19703                     cn: [
19704                         {
19705                             tag: 'a',
19706                             href: '#',
19707                             cls: 'btn',
19708                             cn: [
19709                                 {
19710                                     tag: 'span',
19711                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19712                                 }
19713                             ]
19714                         }
19715                     ]
19716                 },
19717                 {
19718                     tag: 'td',
19719                     cls: 'separator'
19720                 },
19721                 {
19722                     tag: 'td',
19723                     cn: [
19724                         {
19725                             tag: 'a',
19726                             href: '#',
19727                             cls: 'btn',
19728                             cn: [
19729                                 {
19730                                     tag: 'span',
19731                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19732                                 }
19733                             ]
19734                         }
19735                     ]
19736                 },
19737                 {
19738                     tag: 'td',
19739                     cls: 'separator'
19740                 }
19741             ]
19742         });
19743         
19744     },
19745     
19746     update: function()
19747     {
19748         
19749         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19750         
19751         this.fill();
19752     },
19753     
19754     fill: function() 
19755     {
19756         var hours = this.time.getHours();
19757         var minutes = this.time.getMinutes();
19758         var period = 'AM';
19759         
19760         if(hours > 11){
19761             period = 'PM';
19762         }
19763         
19764         if(hours == 0){
19765             hours = 12;
19766         }
19767         
19768         
19769         if(hours > 12){
19770             hours = hours - 12;
19771         }
19772         
19773         if(hours < 10){
19774             hours = '0' + hours;
19775         }
19776         
19777         if(minutes < 10){
19778             minutes = '0' + minutes;
19779         }
19780         
19781         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19782         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19783         this.pop.select('button', true).first().dom.innerHTML = period;
19784         
19785     },
19786     
19787     place: function()
19788     {   
19789         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19790         
19791         var cls = ['bottom'];
19792         
19793         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19794             cls.pop();
19795             cls.push('top');
19796         }
19797         
19798         cls.push('right');
19799         
19800         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19801             cls.pop();
19802             cls.push('left');
19803         }
19804         
19805         this.picker().addClass(cls.join('-'));
19806         
19807         var _this = this;
19808         
19809         Roo.each(cls, function(c){
19810             if(c == 'bottom'){
19811                 _this.picker().setTop(_this.inputEl().getHeight());
19812                 return;
19813             }
19814             if(c == 'top'){
19815                 _this.picker().setTop(0 - _this.picker().getHeight());
19816                 return;
19817             }
19818             
19819             if(c == 'left'){
19820                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19821                 return;
19822             }
19823             if(c == 'right'){
19824                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19825                 return;
19826             }
19827         });
19828         
19829     },
19830   
19831     onFocus : function()
19832     {
19833         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19834         this.show();
19835     },
19836     
19837     onBlur : function()
19838     {
19839         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19840         this.hide();
19841     },
19842     
19843     show : function()
19844     {
19845         this.picker().show();
19846         this.pop.show();
19847         this.update();
19848         this.place();
19849         
19850         this.fireEvent('show', this, this.date);
19851     },
19852     
19853     hide : function()
19854     {
19855         this.picker().hide();
19856         this.pop.hide();
19857         
19858         this.fireEvent('hide', this, this.date);
19859     },
19860     
19861     setTime : function()
19862     {
19863         this.hide();
19864         this.setValue(this.time.format(this.format));
19865         
19866         this.fireEvent('select', this, this.date);
19867         
19868         
19869     },
19870     
19871     onMousedown: function(e){
19872         e.stopPropagation();
19873         e.preventDefault();
19874     },
19875     
19876     onIncrementHours: function()
19877     {
19878         Roo.log('onIncrementHours');
19879         this.time = this.time.add(Date.HOUR, 1);
19880         this.update();
19881         
19882     },
19883     
19884     onDecrementHours: function()
19885     {
19886         Roo.log('onDecrementHours');
19887         this.time = this.time.add(Date.HOUR, -1);
19888         this.update();
19889     },
19890     
19891     onIncrementMinutes: function()
19892     {
19893         Roo.log('onIncrementMinutes');
19894         this.time = this.time.add(Date.MINUTE, 1);
19895         this.update();
19896     },
19897     
19898     onDecrementMinutes: function()
19899     {
19900         Roo.log('onDecrementMinutes');
19901         this.time = this.time.add(Date.MINUTE, -1);
19902         this.update();
19903     },
19904     
19905     onTogglePeriod: function()
19906     {
19907         Roo.log('onTogglePeriod');
19908         this.time = this.time.add(Date.HOUR, 12);
19909         this.update();
19910     }
19911     
19912    
19913 });
19914
19915 Roo.apply(Roo.bootstrap.TimeField,  {
19916     
19917     content : {
19918         tag: 'tbody',
19919         cn: [
19920             {
19921                 tag: 'tr',
19922                 cn: [
19923                 {
19924                     tag: 'td',
19925                     colspan: '7'
19926                 }
19927                 ]
19928             }
19929         ]
19930     },
19931     
19932     footer : {
19933         tag: 'tfoot',
19934         cn: [
19935             {
19936                 tag: 'tr',
19937                 cn: [
19938                 {
19939                     tag: 'th',
19940                     colspan: '7',
19941                     cls: '',
19942                     cn: [
19943                         {
19944                             tag: 'button',
19945                             cls: 'btn btn-info ok',
19946                             html: 'OK'
19947                         }
19948                     ]
19949                 }
19950
19951                 ]
19952             }
19953         ]
19954     }
19955 });
19956
19957 Roo.apply(Roo.bootstrap.TimeField,  {
19958   
19959     template : {
19960         tag: 'div',
19961         cls: 'datepicker dropdown-menu',
19962         cn: [
19963             {
19964                 tag: 'div',
19965                 cls: 'datepicker-time',
19966                 cn: [
19967                 {
19968                     tag: 'table',
19969                     cls: 'table-condensed',
19970                     cn:[
19971                     Roo.bootstrap.TimeField.content,
19972                     Roo.bootstrap.TimeField.footer
19973                     ]
19974                 }
19975                 ]
19976             }
19977         ]
19978     }
19979 });
19980
19981  
19982
19983  /*
19984  * - LGPL
19985  *
19986  * MonthField
19987  * 
19988  */
19989
19990 /**
19991  * @class Roo.bootstrap.MonthField
19992  * @extends Roo.bootstrap.Input
19993  * Bootstrap MonthField class
19994  * 
19995  * @cfg {String} language default en
19996  * 
19997  * @constructor
19998  * Create a new MonthField
19999  * @param {Object} config The config object
20000  */
20001
20002 Roo.bootstrap.MonthField = function(config){
20003     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20004     
20005     this.addEvents({
20006         /**
20007          * @event show
20008          * Fires when this field show.
20009          * @param {Roo.bootstrap.MonthField} this
20010          * @param {Mixed} date The date value
20011          */
20012         show : true,
20013         /**
20014          * @event show
20015          * Fires when this field hide.
20016          * @param {Roo.bootstrap.MonthField} this
20017          * @param {Mixed} date The date value
20018          */
20019         hide : true,
20020         /**
20021          * @event select
20022          * Fires when select a date.
20023          * @param {Roo.bootstrap.MonthField} this
20024          * @param {String} oldvalue The old value
20025          * @param {String} newvalue The new value
20026          */
20027         select : true
20028     });
20029 };
20030
20031 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20032     
20033     onRender: function(ct, position)
20034     {
20035         
20036         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20037         
20038         this.language = this.language || 'en';
20039         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20040         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20041         
20042         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20043         this.isInline = false;
20044         this.isInput = true;
20045         this.component = this.el.select('.add-on', true).first() || false;
20046         this.component = (this.component && this.component.length === 0) ? false : this.component;
20047         this.hasInput = this.component && this.inputEL().length;
20048         
20049         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20050         
20051         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20052         
20053         this.picker().on('mousedown', this.onMousedown, this);
20054         this.picker().on('click', this.onClick, this);
20055         
20056         this.picker().addClass('datepicker-dropdown');
20057         
20058         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20059             v.setStyle('width', '189px');
20060         });
20061         
20062         this.fillMonths();
20063         
20064         this.update();
20065         
20066         if(this.isInline) {
20067             this.show();
20068         }
20069         
20070     },
20071     
20072     setValue: function(v, suppressEvent)
20073     {   
20074         var o = this.getValue();
20075         
20076         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20077         
20078         this.update();
20079
20080         if(suppressEvent !== true){
20081             this.fireEvent('select', this, o, v);
20082         }
20083         
20084     },
20085     
20086     getValue: function()
20087     {
20088         return this.value;
20089     },
20090     
20091     onClick: function(e) 
20092     {
20093         e.stopPropagation();
20094         e.preventDefault();
20095         
20096         var target = e.getTarget();
20097         
20098         if(target.nodeName.toLowerCase() === 'i'){
20099             target = Roo.get(target).dom.parentNode;
20100         }
20101         
20102         var nodeName = target.nodeName;
20103         var className = target.className;
20104         var html = target.innerHTML;
20105         
20106         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20107             return;
20108         }
20109         
20110         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20111         
20112         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20113         
20114         this.hide();
20115                         
20116     },
20117     
20118     picker : function()
20119     {
20120         return this.pickerEl;
20121     },
20122     
20123     fillMonths: function()
20124     {    
20125         var i = 0;
20126         var months = this.picker().select('>.datepicker-months td', true).first();
20127         
20128         months.dom.innerHTML = '';
20129         
20130         while (i < 12) {
20131             var month = {
20132                 tag: 'span',
20133                 cls: 'month',
20134                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20135             };
20136             
20137             months.createChild(month);
20138         }
20139         
20140     },
20141     
20142     update: function()
20143     {
20144         var _this = this;
20145         
20146         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20147             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20148         }
20149         
20150         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20151             e.removeClass('active');
20152             
20153             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20154                 e.addClass('active');
20155             }
20156         })
20157     },
20158     
20159     place: function()
20160     {
20161         if(this.isInline) {
20162             return;
20163         }
20164         
20165         this.picker().removeClass(['bottom', 'top']);
20166         
20167         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20168             /*
20169              * place to the top of element!
20170              *
20171              */
20172             
20173             this.picker().addClass('top');
20174             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20175             
20176             return;
20177         }
20178         
20179         this.picker().addClass('bottom');
20180         
20181         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20182     },
20183     
20184     onFocus : function()
20185     {
20186         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20187         this.show();
20188     },
20189     
20190     onBlur : function()
20191     {
20192         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20193         
20194         var d = this.inputEl().getValue();
20195         
20196         this.setValue(d);
20197                 
20198         this.hide();
20199     },
20200     
20201     show : function()
20202     {
20203         this.picker().show();
20204         this.picker().select('>.datepicker-months', true).first().show();
20205         this.update();
20206         this.place();
20207         
20208         this.fireEvent('show', this, this.date);
20209     },
20210     
20211     hide : function()
20212     {
20213         if(this.isInline) {
20214             return;
20215         }
20216         this.picker().hide();
20217         this.fireEvent('hide', this, this.date);
20218         
20219     },
20220     
20221     onMousedown: function(e)
20222     {
20223         e.stopPropagation();
20224         e.preventDefault();
20225     },
20226     
20227     keyup: function(e)
20228     {
20229         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20230         this.update();
20231     },
20232
20233     fireKey: function(e)
20234     {
20235         if (!this.picker().isVisible()){
20236             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20237                 this.show();
20238             }
20239             return;
20240         }
20241         
20242         var dir;
20243         
20244         switch(e.keyCode){
20245             case 27: // escape
20246                 this.hide();
20247                 e.preventDefault();
20248                 break;
20249             case 37: // left
20250             case 39: // right
20251                 dir = e.keyCode == 37 ? -1 : 1;
20252                 
20253                 this.vIndex = this.vIndex + dir;
20254                 
20255                 if(this.vIndex < 0){
20256                     this.vIndex = 0;
20257                 }
20258                 
20259                 if(this.vIndex > 11){
20260                     this.vIndex = 11;
20261                 }
20262                 
20263                 if(isNaN(this.vIndex)){
20264                     this.vIndex = 0;
20265                 }
20266                 
20267                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20268                 
20269                 break;
20270             case 38: // up
20271             case 40: // down
20272                 
20273                 dir = e.keyCode == 38 ? -1 : 1;
20274                 
20275                 this.vIndex = this.vIndex + dir * 4;
20276                 
20277                 if(this.vIndex < 0){
20278                     this.vIndex = 0;
20279                 }
20280                 
20281                 if(this.vIndex > 11){
20282                     this.vIndex = 11;
20283                 }
20284                 
20285                 if(isNaN(this.vIndex)){
20286                     this.vIndex = 0;
20287                 }
20288                 
20289                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20290                 break;
20291                 
20292             case 13: // enter
20293                 
20294                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20295                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20296                 }
20297                 
20298                 this.hide();
20299                 e.preventDefault();
20300                 break;
20301             case 9: // tab
20302                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20303                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20304                 }
20305                 this.hide();
20306                 break;
20307             case 16: // shift
20308             case 17: // ctrl
20309             case 18: // alt
20310                 break;
20311             default :
20312                 this.hide();
20313                 
20314         }
20315     },
20316     
20317     remove: function() 
20318     {
20319         this.picker().remove();
20320     }
20321    
20322 });
20323
20324 Roo.apply(Roo.bootstrap.MonthField,  {
20325     
20326     content : {
20327         tag: 'tbody',
20328         cn: [
20329         {
20330             tag: 'tr',
20331             cn: [
20332             {
20333                 tag: 'td',
20334                 colspan: '7'
20335             }
20336             ]
20337         }
20338         ]
20339     },
20340     
20341     dates:{
20342         en: {
20343             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20344             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20345         }
20346     }
20347 });
20348
20349 Roo.apply(Roo.bootstrap.MonthField,  {
20350   
20351     template : {
20352         tag: 'div',
20353         cls: 'datepicker dropdown-menu roo-dynamic',
20354         cn: [
20355             {
20356                 tag: 'div',
20357                 cls: 'datepicker-months',
20358                 cn: [
20359                 {
20360                     tag: 'table',
20361                     cls: 'table-condensed',
20362                     cn:[
20363                         Roo.bootstrap.DateField.content
20364                     ]
20365                 }
20366                 ]
20367             }
20368         ]
20369     }
20370 });
20371
20372  
20373
20374  
20375  /*
20376  * - LGPL
20377  *
20378  * CheckBox
20379  * 
20380  */
20381
20382 /**
20383  * @class Roo.bootstrap.CheckBox
20384  * @extends Roo.bootstrap.Input
20385  * Bootstrap CheckBox class
20386  * 
20387  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20388  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20389  * @cfg {String} boxLabel The text that appears beside the checkbox
20390  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20391  * @cfg {Boolean} checked initnal the element
20392  * @cfg {Boolean} inline inline the element (default false)
20393  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20394  * @cfg {String} tooltip label tooltip
20395  * 
20396  * @constructor
20397  * Create a new CheckBox
20398  * @param {Object} config The config object
20399  */
20400
20401 Roo.bootstrap.CheckBox = function(config){
20402     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20403    
20404     this.addEvents({
20405         /**
20406         * @event check
20407         * Fires when the element is checked or unchecked.
20408         * @param {Roo.bootstrap.CheckBox} this This input
20409         * @param {Boolean} checked The new checked value
20410         */
20411        check : true,
20412        /**
20413         * @event click
20414         * Fires when the element is click.
20415         * @param {Roo.bootstrap.CheckBox} this This input
20416         */
20417        click : true
20418     });
20419     
20420 };
20421
20422 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20423   
20424     inputType: 'checkbox',
20425     inputValue: 1,
20426     valueOff: 0,
20427     boxLabel: false,
20428     checked: false,
20429     weight : false,
20430     inline: false,
20431     tooltip : '',
20432     
20433     getAutoCreate : function()
20434     {
20435         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20436         
20437         var id = Roo.id();
20438         
20439         var cfg = {};
20440         
20441         cfg.cls = 'form-group ' + this.inputType; //input-group
20442         
20443         if(this.inline){
20444             cfg.cls += ' ' + this.inputType + '-inline';
20445         }
20446         
20447         var input =  {
20448             tag: 'input',
20449             id : id,
20450             type : this.inputType,
20451             value : this.inputValue,
20452             cls : 'roo-' + this.inputType, //'form-box',
20453             placeholder : this.placeholder || ''
20454             
20455         };
20456         
20457         if(this.inputType != 'radio'){
20458             var hidden =  {
20459                 tag: 'input',
20460                 type : 'hidden',
20461                 cls : 'roo-hidden-value',
20462                 value : this.checked ? this.inputValue : this.valueOff
20463             };
20464         }
20465         
20466             
20467         if (this.weight) { // Validity check?
20468             cfg.cls += " " + this.inputType + "-" + this.weight;
20469         }
20470         
20471         if (this.disabled) {
20472             input.disabled=true;
20473         }
20474         
20475         if(this.checked){
20476             input.checked = this.checked;
20477         }
20478         
20479         if (this.name) {
20480             
20481             input.name = this.name;
20482             
20483             if(this.inputType != 'radio'){
20484                 hidden.name = this.name;
20485                 input.name = '_hidden_' + this.name;
20486             }
20487         }
20488         
20489         if (this.size) {
20490             input.cls += ' input-' + this.size;
20491         }
20492         
20493         var settings=this;
20494         
20495         ['xs','sm','md','lg'].map(function(size){
20496             if (settings[size]) {
20497                 cfg.cls += ' col-' + size + '-' + settings[size];
20498             }
20499         });
20500         
20501         var inputblock = input;
20502          
20503         if (this.before || this.after) {
20504             
20505             inputblock = {
20506                 cls : 'input-group',
20507                 cn :  [] 
20508             };
20509             
20510             if (this.before) {
20511                 inputblock.cn.push({
20512                     tag :'span',
20513                     cls : 'input-group-addon',
20514                     html : this.before
20515                 });
20516             }
20517             
20518             inputblock.cn.push(input);
20519             
20520             if(this.inputType != 'radio'){
20521                 inputblock.cn.push(hidden);
20522             }
20523             
20524             if (this.after) {
20525                 inputblock.cn.push({
20526                     tag :'span',
20527                     cls : 'input-group-addon',
20528                     html : this.after
20529                 });
20530             }
20531             
20532         }
20533         
20534         if (align ==='left' && this.fieldLabel.length) {
20535 //                Roo.log("left and has label");
20536             cfg.cn = [
20537                 {
20538                     tag: 'label',
20539                     'for' :  id,
20540                     cls : 'control-label',
20541                     html : this.fieldLabel
20542                 },
20543                 {
20544                     cls : "", 
20545                     cn: [
20546                         inputblock
20547                     ]
20548                 }
20549             ];
20550             
20551             if(this.labelWidth > 12){
20552                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20553             }
20554             
20555             if(this.labelWidth < 13 && this.labelmd == 0){
20556                 this.labelmd = this.labelWidth;
20557             }
20558             
20559             if(this.labellg > 0){
20560                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20561                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20562             }
20563             
20564             if(this.labelmd > 0){
20565                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20566                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20567             }
20568             
20569             if(this.labelsm > 0){
20570                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20571                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20572             }
20573             
20574             if(this.labelxs > 0){
20575                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20576                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20577             }
20578             
20579         } else if ( this.fieldLabel.length) {
20580 //                Roo.log(" label");
20581                 cfg.cn = [
20582                    
20583                     {
20584                         tag: this.boxLabel ? 'span' : 'label',
20585                         'for': id,
20586                         cls: 'control-label box-input-label',
20587                         //cls : 'input-group-addon',
20588                         html : this.fieldLabel
20589                     },
20590                     
20591                     inputblock
20592                     
20593                 ];
20594
20595         } else {
20596             
20597 //                Roo.log(" no label && no align");
20598                 cfg.cn = [  inputblock ] ;
20599                 
20600                 
20601         }
20602         
20603         if(this.boxLabel){
20604              var boxLabelCfg = {
20605                 tag: 'label',
20606                 //'for': id, // box label is handled by onclick - so no for...
20607                 cls: 'box-label',
20608                 html: this.boxLabel
20609             };
20610             
20611             if(this.tooltip){
20612                 boxLabelCfg.tooltip = this.tooltip;
20613             }
20614              
20615             cfg.cn.push(boxLabelCfg);
20616         }
20617         
20618         if(this.inputType != 'radio'){
20619             cfg.cn.push(hidden);
20620         }
20621         
20622         return cfg;
20623         
20624     },
20625     
20626     /**
20627      * return the real input element.
20628      */
20629     inputEl: function ()
20630     {
20631         return this.el.select('input.roo-' + this.inputType,true).first();
20632     },
20633     hiddenEl: function ()
20634     {
20635         return this.el.select('input.roo-hidden-value',true).first();
20636     },
20637     
20638     labelEl: function()
20639     {
20640         return this.el.select('label.control-label',true).first();
20641     },
20642     /* depricated... */
20643     
20644     label: function()
20645     {
20646         return this.labelEl();
20647     },
20648     
20649     boxLabelEl: function()
20650     {
20651         return this.el.select('label.box-label',true).first();
20652     },
20653     
20654     initEvents : function()
20655     {
20656 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20657         
20658         this.inputEl().on('click', this.onClick,  this);
20659         
20660         if (this.boxLabel) { 
20661             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20662         }
20663         
20664         this.startValue = this.getValue();
20665         
20666         if(this.groupId){
20667             Roo.bootstrap.CheckBox.register(this);
20668         }
20669     },
20670     
20671     onClick : function(e)
20672     {   
20673         if(this.fireEvent('click', this, e) !== false){
20674             this.setChecked(!this.checked);
20675         }
20676         
20677     },
20678     
20679     setChecked : function(state,suppressEvent)
20680     {
20681         this.startValue = this.getValue();
20682
20683         if(this.inputType == 'radio'){
20684             
20685             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20686                 e.dom.checked = false;
20687             });
20688             
20689             this.inputEl().dom.checked = true;
20690             
20691             this.inputEl().dom.value = this.inputValue;
20692             
20693             if(suppressEvent !== true){
20694                 this.fireEvent('check', this, true);
20695             }
20696             
20697             this.validate();
20698             
20699             return;
20700         }
20701         
20702         this.checked = state;
20703         
20704         this.inputEl().dom.checked = state;
20705         
20706         
20707         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20708         
20709         if(suppressEvent !== true){
20710             this.fireEvent('check', this, state);
20711         }
20712         
20713         this.validate();
20714     },
20715     
20716     getValue : function()
20717     {
20718         if(this.inputType == 'radio'){
20719             return this.getGroupValue();
20720         }
20721         
20722         return this.hiddenEl().dom.value;
20723         
20724     },
20725     
20726     getGroupValue : function()
20727     {
20728         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20729             return '';
20730         }
20731         
20732         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20733     },
20734     
20735     setValue : function(v,suppressEvent)
20736     {
20737         if(this.inputType == 'radio'){
20738             this.setGroupValue(v, suppressEvent);
20739             return;
20740         }
20741         
20742         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20743         
20744         this.validate();
20745     },
20746     
20747     setGroupValue : function(v, suppressEvent)
20748     {
20749         this.startValue = this.getValue();
20750         
20751         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20752             e.dom.checked = false;
20753             
20754             if(e.dom.value == v){
20755                 e.dom.checked = true;
20756             }
20757         });
20758         
20759         if(suppressEvent !== true){
20760             this.fireEvent('check', this, true);
20761         }
20762
20763         this.validate();
20764         
20765         return;
20766     },
20767     
20768     validate : function()
20769     {
20770         if(this.getVisibilityEl().hasClass('hidden')){
20771             return true;
20772         }
20773         
20774         if(
20775                 this.disabled || 
20776                 (this.inputType == 'radio' && this.validateRadio()) ||
20777                 (this.inputType == 'checkbox' && this.validateCheckbox())
20778         ){
20779             this.markValid();
20780             return true;
20781         }
20782         
20783         this.markInvalid();
20784         return false;
20785     },
20786     
20787     validateRadio : function()
20788     {
20789         if(this.getVisibilityEl().hasClass('hidden')){
20790             return true;
20791         }
20792         
20793         if(this.allowBlank){
20794             return true;
20795         }
20796         
20797         var valid = false;
20798         
20799         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20800             if(!e.dom.checked){
20801                 return;
20802             }
20803             
20804             valid = true;
20805             
20806             return false;
20807         });
20808         
20809         return valid;
20810     },
20811     
20812     validateCheckbox : function()
20813     {
20814         if(!this.groupId){
20815             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20816             //return (this.getValue() == this.inputValue) ? true : false;
20817         }
20818         
20819         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20820         
20821         if(!group){
20822             return false;
20823         }
20824         
20825         var r = false;
20826         
20827         for(var i in group){
20828             if(group[i].el.isVisible(true)){
20829                 r = false;
20830                 break;
20831             }
20832             
20833             r = true;
20834         }
20835         
20836         for(var i in group){
20837             if(r){
20838                 break;
20839             }
20840             
20841             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20842         }
20843         
20844         return r;
20845     },
20846     
20847     /**
20848      * Mark this field as valid
20849      */
20850     markValid : function()
20851     {
20852         var _this = this;
20853         
20854         this.fireEvent('valid', this);
20855         
20856         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20857         
20858         if(this.groupId){
20859             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20860         }
20861         
20862         if(label){
20863             label.markValid();
20864         }
20865
20866         if(this.inputType == 'radio'){
20867             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20868                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20869                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20870             });
20871             
20872             return;
20873         }
20874
20875         if(!this.groupId){
20876             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20877             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20878             return;
20879         }
20880         
20881         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20882         
20883         if(!group){
20884             return;
20885         }
20886         
20887         for(var i in group){
20888             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20889             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20890         }
20891     },
20892     
20893      /**
20894      * Mark this field as invalid
20895      * @param {String} msg The validation message
20896      */
20897     markInvalid : function(msg)
20898     {
20899         if(this.allowBlank){
20900             return;
20901         }
20902         
20903         var _this = this;
20904         
20905         this.fireEvent('invalid', this, msg);
20906         
20907         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20908         
20909         if(this.groupId){
20910             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20911         }
20912         
20913         if(label){
20914             label.markInvalid();
20915         }
20916             
20917         if(this.inputType == 'radio'){
20918             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20919                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20920                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20921             });
20922             
20923             return;
20924         }
20925         
20926         if(!this.groupId){
20927             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20928             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20929             return;
20930         }
20931         
20932         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20933         
20934         if(!group){
20935             return;
20936         }
20937         
20938         for(var i in group){
20939             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20940             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20941         }
20942         
20943     },
20944     
20945     clearInvalid : function()
20946     {
20947         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20948         
20949         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20950         
20951         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20952         
20953         if (label && label.iconEl) {
20954             label.iconEl.removeClass(label.validClass);
20955             label.iconEl.removeClass(label.invalidClass);
20956         }
20957     },
20958     
20959     disable : function()
20960     {
20961         if(this.inputType != 'radio'){
20962             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20963             return;
20964         }
20965         
20966         var _this = this;
20967         
20968         if(this.rendered){
20969             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20970                 _this.getActionEl().addClass(this.disabledClass);
20971                 e.dom.disabled = true;
20972             });
20973         }
20974         
20975         this.disabled = true;
20976         this.fireEvent("disable", this);
20977         return this;
20978     },
20979
20980     enable : function()
20981     {
20982         if(this.inputType != 'radio'){
20983             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20984             return;
20985         }
20986         
20987         var _this = this;
20988         
20989         if(this.rendered){
20990             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20991                 _this.getActionEl().removeClass(this.disabledClass);
20992                 e.dom.disabled = false;
20993             });
20994         }
20995         
20996         this.disabled = false;
20997         this.fireEvent("enable", this);
20998         return this;
20999     },
21000     
21001     setBoxLabel : function(v)
21002     {
21003         this.boxLabel = v;
21004         
21005         if(this.rendered){
21006             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21007         }
21008     }
21009
21010 });
21011
21012 Roo.apply(Roo.bootstrap.CheckBox, {
21013     
21014     groups: {},
21015     
21016      /**
21017     * register a CheckBox Group
21018     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21019     */
21020     register : function(checkbox)
21021     {
21022         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21023             this.groups[checkbox.groupId] = {};
21024         }
21025         
21026         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21027             return;
21028         }
21029         
21030         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21031         
21032     },
21033     /**
21034     * fetch a CheckBox Group based on the group ID
21035     * @param {string} the group ID
21036     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21037     */
21038     get: function(groupId) {
21039         if (typeof(this.groups[groupId]) == 'undefined') {
21040             return false;
21041         }
21042         
21043         return this.groups[groupId] ;
21044     }
21045     
21046     
21047 });
21048 /*
21049  * - LGPL
21050  *
21051  * RadioItem
21052  * 
21053  */
21054
21055 /**
21056  * @class Roo.bootstrap.Radio
21057  * @extends Roo.bootstrap.Component
21058  * Bootstrap Radio class
21059  * @cfg {String} boxLabel - the label associated
21060  * @cfg {String} value - the value of radio
21061  * 
21062  * @constructor
21063  * Create a new Radio
21064  * @param {Object} config The config object
21065  */
21066 Roo.bootstrap.Radio = function(config){
21067     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21068     
21069 };
21070
21071 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21072     
21073     boxLabel : '',
21074     
21075     value : '',
21076     
21077     getAutoCreate : function()
21078     {
21079         var cfg = {
21080             tag : 'div',
21081             cls : 'form-group radio',
21082             cn : [
21083                 {
21084                     tag : 'label',
21085                     cls : 'box-label',
21086                     html : this.boxLabel
21087                 }
21088             ]
21089         };
21090         
21091         return cfg;
21092     },
21093     
21094     initEvents : function() 
21095     {
21096         this.parent().register(this);
21097         
21098         this.el.on('click', this.onClick, this);
21099         
21100     },
21101     
21102     onClick : function(e)
21103     {
21104         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21105             this.setChecked(true);
21106         }
21107     },
21108     
21109     setChecked : function(state, suppressEvent)
21110     {
21111         this.parent().setValue(this.value, suppressEvent);
21112         
21113     },
21114     
21115     setBoxLabel : function(v)
21116     {
21117         this.boxLabel = v;
21118         
21119         if(this.rendered){
21120             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21121         }
21122     }
21123     
21124 });
21125  
21126
21127  /*
21128  * - LGPL
21129  *
21130  * Input
21131  * 
21132  */
21133
21134 /**
21135  * @class Roo.bootstrap.SecurePass
21136  * @extends Roo.bootstrap.Input
21137  * Bootstrap SecurePass class
21138  *
21139  * 
21140  * @constructor
21141  * Create a new SecurePass
21142  * @param {Object} config The config object
21143  */
21144  
21145 Roo.bootstrap.SecurePass = function (config) {
21146     // these go here, so the translation tool can replace them..
21147     this.errors = {
21148         PwdEmpty: "Please type a password, and then retype it to confirm.",
21149         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21150         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21151         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21152         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21153         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21154         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21155         TooWeak: "Your password is Too Weak."
21156     },
21157     this.meterLabel = "Password strength:";
21158     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21159     this.meterClass = [
21160         "roo-password-meter-tooweak", 
21161         "roo-password-meter-weak", 
21162         "roo-password-meter-medium", 
21163         "roo-password-meter-strong", 
21164         "roo-password-meter-grey"
21165     ];
21166     
21167     this.errors = {};
21168     
21169     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21170 }
21171
21172 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21173     /**
21174      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21175      * {
21176      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21177      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21178      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21179      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21180      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21181      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21182      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21183      * })
21184      */
21185     // private
21186     
21187     meterWidth: 300,
21188     errorMsg :'',    
21189     errors: false,
21190     imageRoot: '/',
21191     /**
21192      * @cfg {String/Object} Label for the strength meter (defaults to
21193      * 'Password strength:')
21194      */
21195     // private
21196     meterLabel: '',
21197     /**
21198      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21199      * ['Weak', 'Medium', 'Strong'])
21200      */
21201     // private    
21202     pwdStrengths: false,    
21203     // private
21204     strength: 0,
21205     // private
21206     _lastPwd: null,
21207     // private
21208     kCapitalLetter: 0,
21209     kSmallLetter: 1,
21210     kDigit: 2,
21211     kPunctuation: 3,
21212     
21213     insecure: false,
21214     // private
21215     initEvents: function ()
21216     {
21217         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21218
21219         if (this.el.is('input[type=password]') && Roo.isSafari) {
21220             this.el.on('keydown', this.SafariOnKeyDown, this);
21221         }
21222
21223         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21224     },
21225     // private
21226     onRender: function (ct, position)
21227     {
21228         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21229         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21230         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21231
21232         this.trigger.createChild({
21233                    cn: [
21234                     {
21235                     //id: 'PwdMeter',
21236                     tag: 'div',
21237                     cls: 'roo-password-meter-grey col-xs-12',
21238                     style: {
21239                         //width: 0,
21240                         //width: this.meterWidth + 'px'                                                
21241                         }
21242                     },
21243                     {                            
21244                          cls: 'roo-password-meter-text'                          
21245                     }
21246                 ]            
21247         });
21248
21249          
21250         if (this.hideTrigger) {
21251             this.trigger.setDisplayed(false);
21252         }
21253         this.setSize(this.width || '', this.height || '');
21254     },
21255     // private
21256     onDestroy: function ()
21257     {
21258         if (this.trigger) {
21259             this.trigger.removeAllListeners();
21260             this.trigger.remove();
21261         }
21262         if (this.wrap) {
21263             this.wrap.remove();
21264         }
21265         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21266     },
21267     // private
21268     checkStrength: function ()
21269     {
21270         var pwd = this.inputEl().getValue();
21271         if (pwd == this._lastPwd) {
21272             return;
21273         }
21274
21275         var strength;
21276         if (this.ClientSideStrongPassword(pwd)) {
21277             strength = 3;
21278         } else if (this.ClientSideMediumPassword(pwd)) {
21279             strength = 2;
21280         } else if (this.ClientSideWeakPassword(pwd)) {
21281             strength = 1;
21282         } else {
21283             strength = 0;
21284         }
21285         
21286         Roo.log('strength1: ' + strength);
21287         
21288         //var pm = this.trigger.child('div/div/div').dom;
21289         var pm = this.trigger.child('div/div');
21290         pm.removeClass(this.meterClass);
21291         pm.addClass(this.meterClass[strength]);
21292                 
21293         
21294         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21295                 
21296         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21297         
21298         this._lastPwd = pwd;
21299     },
21300     reset: function ()
21301     {
21302         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21303         
21304         this._lastPwd = '';
21305         
21306         var pm = this.trigger.child('div/div');
21307         pm.removeClass(this.meterClass);
21308         pm.addClass('roo-password-meter-grey');        
21309         
21310         
21311         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21312         
21313         pt.innerHTML = '';
21314         this.inputEl().dom.type='password';
21315     },
21316     // private
21317     validateValue: function (value)
21318     {
21319         
21320         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21321             return false;
21322         }
21323         if (value.length == 0) {
21324             if (this.allowBlank) {
21325                 this.clearInvalid();
21326                 return true;
21327             }
21328
21329             this.markInvalid(this.errors.PwdEmpty);
21330             this.errorMsg = this.errors.PwdEmpty;
21331             return false;
21332         }
21333         
21334         if(this.insecure){
21335             return true;
21336         }
21337         
21338         if ('[\x21-\x7e]*'.match(value)) {
21339             this.markInvalid(this.errors.PwdBadChar);
21340             this.errorMsg = this.errors.PwdBadChar;
21341             return false;
21342         }
21343         if (value.length < 6) {
21344             this.markInvalid(this.errors.PwdShort);
21345             this.errorMsg = this.errors.PwdShort;
21346             return false;
21347         }
21348         if (value.length > 16) {
21349             this.markInvalid(this.errors.PwdLong);
21350             this.errorMsg = this.errors.PwdLong;
21351             return false;
21352         }
21353         var strength;
21354         if (this.ClientSideStrongPassword(value)) {
21355             strength = 3;
21356         } else if (this.ClientSideMediumPassword(value)) {
21357             strength = 2;
21358         } else if (this.ClientSideWeakPassword(value)) {
21359             strength = 1;
21360         } else {
21361             strength = 0;
21362         }
21363
21364         
21365         if (strength < 2) {
21366             //this.markInvalid(this.errors.TooWeak);
21367             this.errorMsg = this.errors.TooWeak;
21368             //return false;
21369         }
21370         
21371         
21372         console.log('strength2: ' + strength);
21373         
21374         //var pm = this.trigger.child('div/div/div').dom;
21375         
21376         var pm = this.trigger.child('div/div');
21377         pm.removeClass(this.meterClass);
21378         pm.addClass(this.meterClass[strength]);
21379                 
21380         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21381                 
21382         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21383         
21384         this.errorMsg = ''; 
21385         return true;
21386     },
21387     // private
21388     CharacterSetChecks: function (type)
21389     {
21390         this.type = type;
21391         this.fResult = false;
21392     },
21393     // private
21394     isctype: function (character, type)
21395     {
21396         switch (type) {  
21397             case this.kCapitalLetter:
21398                 if (character >= 'A' && character <= 'Z') {
21399                     return true;
21400                 }
21401                 break;
21402             
21403             case this.kSmallLetter:
21404                 if (character >= 'a' && character <= 'z') {
21405                     return true;
21406                 }
21407                 break;
21408             
21409             case this.kDigit:
21410                 if (character >= '0' && character <= '9') {
21411                     return true;
21412                 }
21413                 break;
21414             
21415             case this.kPunctuation:
21416                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21417                     return true;
21418                 }
21419                 break;
21420             
21421             default:
21422                 return false;
21423         }
21424
21425     },
21426     // private
21427     IsLongEnough: function (pwd, size)
21428     {
21429         return !(pwd == null || isNaN(size) || pwd.length < size);
21430     },
21431     // private
21432     SpansEnoughCharacterSets: function (word, nb)
21433     {
21434         if (!this.IsLongEnough(word, nb))
21435         {
21436             return false;
21437         }
21438
21439         var characterSetChecks = new Array(
21440             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21441             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21442         );
21443         
21444         for (var index = 0; index < word.length; ++index) {
21445             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21446                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21447                     characterSetChecks[nCharSet].fResult = true;
21448                     break;
21449                 }
21450             }
21451         }
21452
21453         var nCharSets = 0;
21454         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21455             if (characterSetChecks[nCharSet].fResult) {
21456                 ++nCharSets;
21457             }
21458         }
21459
21460         if (nCharSets < nb) {
21461             return false;
21462         }
21463         return true;
21464     },
21465     // private
21466     ClientSideStrongPassword: function (pwd)
21467     {
21468         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21469     },
21470     // private
21471     ClientSideMediumPassword: function (pwd)
21472     {
21473         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21474     },
21475     // private
21476     ClientSideWeakPassword: function (pwd)
21477     {
21478         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21479     }
21480           
21481 })//<script type="text/javascript">
21482
21483 /*
21484  * Based  Ext JS Library 1.1.1
21485  * Copyright(c) 2006-2007, Ext JS, LLC.
21486  * LGPL
21487  *
21488  */
21489  
21490 /**
21491  * @class Roo.HtmlEditorCore
21492  * @extends Roo.Component
21493  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21494  *
21495  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21496  */
21497
21498 Roo.HtmlEditorCore = function(config){
21499     
21500     
21501     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21502     
21503     
21504     this.addEvents({
21505         /**
21506          * @event initialize
21507          * Fires when the editor is fully initialized (including the iframe)
21508          * @param {Roo.HtmlEditorCore} this
21509          */
21510         initialize: true,
21511         /**
21512          * @event activate
21513          * Fires when the editor is first receives the focus. Any insertion must wait
21514          * until after this event.
21515          * @param {Roo.HtmlEditorCore} this
21516          */
21517         activate: true,
21518          /**
21519          * @event beforesync
21520          * Fires before the textarea is updated with content from the editor iframe. Return false
21521          * to cancel the sync.
21522          * @param {Roo.HtmlEditorCore} this
21523          * @param {String} html
21524          */
21525         beforesync: true,
21526          /**
21527          * @event beforepush
21528          * Fires before the iframe editor is updated with content from the textarea. Return false
21529          * to cancel the push.
21530          * @param {Roo.HtmlEditorCore} this
21531          * @param {String} html
21532          */
21533         beforepush: true,
21534          /**
21535          * @event sync
21536          * Fires when the textarea is updated with content from the editor iframe.
21537          * @param {Roo.HtmlEditorCore} this
21538          * @param {String} html
21539          */
21540         sync: true,
21541          /**
21542          * @event push
21543          * Fires when the iframe editor is updated with content from the textarea.
21544          * @param {Roo.HtmlEditorCore} this
21545          * @param {String} html
21546          */
21547         push: true,
21548         
21549         /**
21550          * @event editorevent
21551          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21552          * @param {Roo.HtmlEditorCore} this
21553          */
21554         editorevent: true
21555         
21556     });
21557     
21558     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21559     
21560     // defaults : white / black...
21561     this.applyBlacklists();
21562     
21563     
21564     
21565 };
21566
21567
21568 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21569
21570
21571      /**
21572      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21573      */
21574     
21575     owner : false,
21576     
21577      /**
21578      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21579      *                        Roo.resizable.
21580      */
21581     resizable : false,
21582      /**
21583      * @cfg {Number} height (in pixels)
21584      */   
21585     height: 300,
21586    /**
21587      * @cfg {Number} width (in pixels)
21588      */   
21589     width: 500,
21590     
21591     /**
21592      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21593      * 
21594      */
21595     stylesheets: false,
21596     
21597     // id of frame..
21598     frameId: false,
21599     
21600     // private properties
21601     validationEvent : false,
21602     deferHeight: true,
21603     initialized : false,
21604     activated : false,
21605     sourceEditMode : false,
21606     onFocus : Roo.emptyFn,
21607     iframePad:3,
21608     hideMode:'offsets',
21609     
21610     clearUp: true,
21611     
21612     // blacklist + whitelisted elements..
21613     black: false,
21614     white: false,
21615      
21616     bodyCls : '',
21617
21618     /**
21619      * Protected method that will not generally be called directly. It
21620      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21621      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21622      */
21623     getDocMarkup : function(){
21624         // body styles..
21625         var st = '';
21626         
21627         // inherit styels from page...?? 
21628         if (this.stylesheets === false) {
21629             
21630             Roo.get(document.head).select('style').each(function(node) {
21631                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21632             });
21633             
21634             Roo.get(document.head).select('link').each(function(node) { 
21635                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21636             });
21637             
21638         } else if (!this.stylesheets.length) {
21639                 // simple..
21640                 st = '<style type="text/css">' +
21641                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21642                    '</style>';
21643         } else { 
21644             st = '<style type="text/css">' +
21645                     this.stylesheets +
21646                 '</style>';
21647         }
21648         
21649         st +=  '<style type="text/css">' +
21650             'IMG { cursor: pointer } ' +
21651         '</style>';
21652
21653         var cls = 'roo-htmleditor-body';
21654         
21655         if(this.bodyCls.length){
21656             cls += ' ' + this.bodyCls;
21657         }
21658         
21659         return '<html><head>' + st  +
21660             //<style type="text/css">' +
21661             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21662             //'</style>' +
21663             ' </head><body class="' +  cls + '"></body></html>';
21664     },
21665
21666     // private
21667     onRender : function(ct, position)
21668     {
21669         var _t = this;
21670         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21671         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21672         
21673         
21674         this.el.dom.style.border = '0 none';
21675         this.el.dom.setAttribute('tabIndex', -1);
21676         this.el.addClass('x-hidden hide');
21677         
21678         
21679         
21680         if(Roo.isIE){ // fix IE 1px bogus margin
21681             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21682         }
21683        
21684         
21685         this.frameId = Roo.id();
21686         
21687          
21688         
21689         var iframe = this.owner.wrap.createChild({
21690             tag: 'iframe',
21691             cls: 'form-control', // bootstrap..
21692             id: this.frameId,
21693             name: this.frameId,
21694             frameBorder : 'no',
21695             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21696         }, this.el
21697         );
21698         
21699         
21700         this.iframe = iframe.dom;
21701
21702          this.assignDocWin();
21703         
21704         this.doc.designMode = 'on';
21705        
21706         this.doc.open();
21707         this.doc.write(this.getDocMarkup());
21708         this.doc.close();
21709
21710         
21711         var task = { // must defer to wait for browser to be ready
21712             run : function(){
21713                 //console.log("run task?" + this.doc.readyState);
21714                 this.assignDocWin();
21715                 if(this.doc.body || this.doc.readyState == 'complete'){
21716                     try {
21717                         this.doc.designMode="on";
21718                     } catch (e) {
21719                         return;
21720                     }
21721                     Roo.TaskMgr.stop(task);
21722                     this.initEditor.defer(10, this);
21723                 }
21724             },
21725             interval : 10,
21726             duration: 10000,
21727             scope: this
21728         };
21729         Roo.TaskMgr.start(task);
21730
21731     },
21732
21733     // private
21734     onResize : function(w, h)
21735     {
21736          Roo.log('resize: ' +w + ',' + h );
21737         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21738         if(!this.iframe){
21739             return;
21740         }
21741         if(typeof w == 'number'){
21742             
21743             this.iframe.style.width = w + 'px';
21744         }
21745         if(typeof h == 'number'){
21746             
21747             this.iframe.style.height = h + 'px';
21748             if(this.doc){
21749                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21750             }
21751         }
21752         
21753     },
21754
21755     /**
21756      * Toggles the editor between standard and source edit mode.
21757      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21758      */
21759     toggleSourceEdit : function(sourceEditMode){
21760         
21761         this.sourceEditMode = sourceEditMode === true;
21762         
21763         if(this.sourceEditMode){
21764  
21765             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21766             
21767         }else{
21768             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21769             //this.iframe.className = '';
21770             this.deferFocus();
21771         }
21772         //this.setSize(this.owner.wrap.getSize());
21773         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21774     },
21775
21776     
21777   
21778
21779     /**
21780      * Protected method that will not generally be called directly. If you need/want
21781      * custom HTML cleanup, this is the method you should override.
21782      * @param {String} html The HTML to be cleaned
21783      * return {String} The cleaned HTML
21784      */
21785     cleanHtml : function(html){
21786         html = String(html);
21787         if(html.length > 5){
21788             if(Roo.isSafari){ // strip safari nonsense
21789                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21790             }
21791         }
21792         if(html == '&nbsp;'){
21793             html = '';
21794         }
21795         return html;
21796     },
21797
21798     /**
21799      * HTML Editor -> Textarea
21800      * Protected method that will not generally be called directly. Syncs the contents
21801      * of the editor iframe with the textarea.
21802      */
21803     syncValue : function(){
21804         if(this.initialized){
21805             var bd = (this.doc.body || this.doc.documentElement);
21806             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21807             var html = bd.innerHTML;
21808             if(Roo.isSafari){
21809                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21810                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21811                 if(m && m[1]){
21812                     html = '<div style="'+m[0]+'">' + html + '</div>';
21813                 }
21814             }
21815             html = this.cleanHtml(html);
21816             // fix up the special chars.. normaly like back quotes in word...
21817             // however we do not want to do this with chinese..
21818             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21819                 var cc = b.charCodeAt();
21820                 if (
21821                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21822                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21823                     (cc >= 0xf900 && cc < 0xfb00 )
21824                 ) {
21825                         return b;
21826                 }
21827                 return "&#"+cc+";" 
21828             });
21829             if(this.owner.fireEvent('beforesync', this, html) !== false){
21830                 this.el.dom.value = html;
21831                 this.owner.fireEvent('sync', this, html);
21832             }
21833         }
21834     },
21835
21836     /**
21837      * Protected method that will not generally be called directly. Pushes the value of the textarea
21838      * into the iframe editor.
21839      */
21840     pushValue : function(){
21841         if(this.initialized){
21842             var v = this.el.dom.value.trim();
21843             
21844 //            if(v.length < 1){
21845 //                v = '&#160;';
21846 //            }
21847             
21848             if(this.owner.fireEvent('beforepush', this, v) !== false){
21849                 var d = (this.doc.body || this.doc.documentElement);
21850                 d.innerHTML = v;
21851                 this.cleanUpPaste();
21852                 this.el.dom.value = d.innerHTML;
21853                 this.owner.fireEvent('push', this, v);
21854             }
21855         }
21856     },
21857
21858     // private
21859     deferFocus : function(){
21860         this.focus.defer(10, this);
21861     },
21862
21863     // doc'ed in Field
21864     focus : function(){
21865         if(this.win && !this.sourceEditMode){
21866             this.win.focus();
21867         }else{
21868             this.el.focus();
21869         }
21870     },
21871     
21872     assignDocWin: function()
21873     {
21874         var iframe = this.iframe;
21875         
21876          if(Roo.isIE){
21877             this.doc = iframe.contentWindow.document;
21878             this.win = iframe.contentWindow;
21879         } else {
21880 //            if (!Roo.get(this.frameId)) {
21881 //                return;
21882 //            }
21883 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21884 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21885             
21886             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21887                 return;
21888             }
21889             
21890             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21891             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21892         }
21893     },
21894     
21895     // private
21896     initEditor : function(){
21897         //console.log("INIT EDITOR");
21898         this.assignDocWin();
21899         
21900         
21901         
21902         this.doc.designMode="on";
21903         this.doc.open();
21904         this.doc.write(this.getDocMarkup());
21905         this.doc.close();
21906         
21907         var dbody = (this.doc.body || this.doc.documentElement);
21908         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21909         // this copies styles from the containing element into thsi one..
21910         // not sure why we need all of this..
21911         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21912         
21913         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21914         //ss['background-attachment'] = 'fixed'; // w3c
21915         dbody.bgProperties = 'fixed'; // ie
21916         //Roo.DomHelper.applyStyles(dbody, ss);
21917         Roo.EventManager.on(this.doc, {
21918             //'mousedown': this.onEditorEvent,
21919             'mouseup': this.onEditorEvent,
21920             'dblclick': this.onEditorEvent,
21921             'click': this.onEditorEvent,
21922             'keyup': this.onEditorEvent,
21923             buffer:100,
21924             scope: this
21925         });
21926         if(Roo.isGecko){
21927             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21928         }
21929         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21930             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21931         }
21932         this.initialized = true;
21933
21934         this.owner.fireEvent('initialize', this);
21935         this.pushValue();
21936     },
21937
21938     // private
21939     onDestroy : function(){
21940         
21941         
21942         
21943         if(this.rendered){
21944             
21945             //for (var i =0; i < this.toolbars.length;i++) {
21946             //    // fixme - ask toolbars for heights?
21947             //    this.toolbars[i].onDestroy();
21948            // }
21949             
21950             //this.wrap.dom.innerHTML = '';
21951             //this.wrap.remove();
21952         }
21953     },
21954
21955     // private
21956     onFirstFocus : function(){
21957         
21958         this.assignDocWin();
21959         
21960         
21961         this.activated = true;
21962          
21963     
21964         if(Roo.isGecko){ // prevent silly gecko errors
21965             this.win.focus();
21966             var s = this.win.getSelection();
21967             if(!s.focusNode || s.focusNode.nodeType != 3){
21968                 var r = s.getRangeAt(0);
21969                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21970                 r.collapse(true);
21971                 this.deferFocus();
21972             }
21973             try{
21974                 this.execCmd('useCSS', true);
21975                 this.execCmd('styleWithCSS', false);
21976             }catch(e){}
21977         }
21978         this.owner.fireEvent('activate', this);
21979     },
21980
21981     // private
21982     adjustFont: function(btn){
21983         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21984         //if(Roo.isSafari){ // safari
21985         //    adjust *= 2;
21986        // }
21987         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21988         if(Roo.isSafari){ // safari
21989             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21990             v =  (v < 10) ? 10 : v;
21991             v =  (v > 48) ? 48 : v;
21992             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21993             
21994         }
21995         
21996         
21997         v = Math.max(1, v+adjust);
21998         
21999         this.execCmd('FontSize', v  );
22000     },
22001
22002     onEditorEvent : function(e)
22003     {
22004         this.owner.fireEvent('editorevent', this, e);
22005       //  this.updateToolbar();
22006         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22007     },
22008
22009     insertTag : function(tg)
22010     {
22011         // could be a bit smarter... -> wrap the current selected tRoo..
22012         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22013             
22014             range = this.createRange(this.getSelection());
22015             var wrappingNode = this.doc.createElement(tg.toLowerCase());
22016             wrappingNode.appendChild(range.extractContents());
22017             range.insertNode(wrappingNode);
22018
22019             return;
22020             
22021             
22022             
22023         }
22024         this.execCmd("formatblock",   tg);
22025         
22026     },
22027     
22028     insertText : function(txt)
22029     {
22030         
22031         
22032         var range = this.createRange();
22033         range.deleteContents();
22034                //alert(Sender.getAttribute('label'));
22035                
22036         range.insertNode(this.doc.createTextNode(txt));
22037     } ,
22038     
22039      
22040
22041     /**
22042      * Executes a Midas editor command on the editor document and performs necessary focus and
22043      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22044      * @param {String} cmd The Midas command
22045      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22046      */
22047     relayCmd : function(cmd, value){
22048         this.win.focus();
22049         this.execCmd(cmd, value);
22050         this.owner.fireEvent('editorevent', this);
22051         //this.updateToolbar();
22052         this.owner.deferFocus();
22053     },
22054
22055     /**
22056      * Executes a Midas editor command directly on the editor document.
22057      * For visual commands, you should use {@link #relayCmd} instead.
22058      * <b>This should only be called after the editor is initialized.</b>
22059      * @param {String} cmd The Midas command
22060      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22061      */
22062     execCmd : function(cmd, value){
22063         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22064         this.syncValue();
22065     },
22066  
22067  
22068    
22069     /**
22070      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22071      * to insert tRoo.
22072      * @param {String} text | dom node.. 
22073      */
22074     insertAtCursor : function(text)
22075     {
22076         
22077         if(!this.activated){
22078             return;
22079         }
22080         /*
22081         if(Roo.isIE){
22082             this.win.focus();
22083             var r = this.doc.selection.createRange();
22084             if(r){
22085                 r.collapse(true);
22086                 r.pasteHTML(text);
22087                 this.syncValue();
22088                 this.deferFocus();
22089             
22090             }
22091             return;
22092         }
22093         */
22094         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22095             this.win.focus();
22096             
22097             
22098             // from jquery ui (MIT licenced)
22099             var range, node;
22100             var win = this.win;
22101             
22102             if (win.getSelection && win.getSelection().getRangeAt) {
22103                 range = win.getSelection().getRangeAt(0);
22104                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22105                 range.insertNode(node);
22106             } else if (win.document.selection && win.document.selection.createRange) {
22107                 // no firefox support
22108                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22109                 win.document.selection.createRange().pasteHTML(txt);
22110             } else {
22111                 // no firefox support
22112                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22113                 this.execCmd('InsertHTML', txt);
22114             } 
22115             
22116             this.syncValue();
22117             
22118             this.deferFocus();
22119         }
22120     },
22121  // private
22122     mozKeyPress : function(e){
22123         if(e.ctrlKey){
22124             var c = e.getCharCode(), cmd;
22125           
22126             if(c > 0){
22127                 c = String.fromCharCode(c).toLowerCase();
22128                 switch(c){
22129                     case 'b':
22130                         cmd = 'bold';
22131                         break;
22132                     case 'i':
22133                         cmd = 'italic';
22134                         break;
22135                     
22136                     case 'u':
22137                         cmd = 'underline';
22138                         break;
22139                     
22140                     case 'v':
22141                         this.cleanUpPaste.defer(100, this);
22142                         return;
22143                         
22144                 }
22145                 if(cmd){
22146                     this.win.focus();
22147                     this.execCmd(cmd);
22148                     this.deferFocus();
22149                     e.preventDefault();
22150                 }
22151                 
22152             }
22153         }
22154     },
22155
22156     // private
22157     fixKeys : function(){ // load time branching for fastest keydown performance
22158         if(Roo.isIE){
22159             return function(e){
22160                 var k = e.getKey(), r;
22161                 if(k == e.TAB){
22162                     e.stopEvent();
22163                     r = this.doc.selection.createRange();
22164                     if(r){
22165                         r.collapse(true);
22166                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22167                         this.deferFocus();
22168                     }
22169                     return;
22170                 }
22171                 
22172                 if(k == e.ENTER){
22173                     r = this.doc.selection.createRange();
22174                     if(r){
22175                         var target = r.parentElement();
22176                         if(!target || target.tagName.toLowerCase() != 'li'){
22177                             e.stopEvent();
22178                             r.pasteHTML('<br />');
22179                             r.collapse(false);
22180                             r.select();
22181                         }
22182                     }
22183                 }
22184                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22185                     this.cleanUpPaste.defer(100, this);
22186                     return;
22187                 }
22188                 
22189                 
22190             };
22191         }else if(Roo.isOpera){
22192             return function(e){
22193                 var k = e.getKey();
22194                 if(k == e.TAB){
22195                     e.stopEvent();
22196                     this.win.focus();
22197                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22198                     this.deferFocus();
22199                 }
22200                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22201                     this.cleanUpPaste.defer(100, this);
22202                     return;
22203                 }
22204                 
22205             };
22206         }else if(Roo.isSafari){
22207             return function(e){
22208                 var k = e.getKey();
22209                 
22210                 if(k == e.TAB){
22211                     e.stopEvent();
22212                     this.execCmd('InsertText','\t');
22213                     this.deferFocus();
22214                     return;
22215                 }
22216                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22217                     this.cleanUpPaste.defer(100, this);
22218                     return;
22219                 }
22220                 
22221              };
22222         }
22223     }(),
22224     
22225     getAllAncestors: function()
22226     {
22227         var p = this.getSelectedNode();
22228         var a = [];
22229         if (!p) {
22230             a.push(p); // push blank onto stack..
22231             p = this.getParentElement();
22232         }
22233         
22234         
22235         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22236             a.push(p);
22237             p = p.parentNode;
22238         }
22239         a.push(this.doc.body);
22240         return a;
22241     },
22242     lastSel : false,
22243     lastSelNode : false,
22244     
22245     
22246     getSelection : function() 
22247     {
22248         this.assignDocWin();
22249         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22250     },
22251     
22252     getSelectedNode: function() 
22253     {
22254         // this may only work on Gecko!!!
22255         
22256         // should we cache this!!!!
22257         
22258         
22259         
22260          
22261         var range = this.createRange(this.getSelection()).cloneRange();
22262         
22263         if (Roo.isIE) {
22264             var parent = range.parentElement();
22265             while (true) {
22266                 var testRange = range.duplicate();
22267                 testRange.moveToElementText(parent);
22268                 if (testRange.inRange(range)) {
22269                     break;
22270                 }
22271                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22272                     break;
22273                 }
22274                 parent = parent.parentElement;
22275             }
22276             return parent;
22277         }
22278         
22279         // is ancestor a text element.
22280         var ac =  range.commonAncestorContainer;
22281         if (ac.nodeType == 3) {
22282             ac = ac.parentNode;
22283         }
22284         
22285         var ar = ac.childNodes;
22286          
22287         var nodes = [];
22288         var other_nodes = [];
22289         var has_other_nodes = false;
22290         for (var i=0;i<ar.length;i++) {
22291             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22292                 continue;
22293             }
22294             // fullly contained node.
22295             
22296             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22297                 nodes.push(ar[i]);
22298                 continue;
22299             }
22300             
22301             // probably selected..
22302             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22303                 other_nodes.push(ar[i]);
22304                 continue;
22305             }
22306             // outer..
22307             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22308                 continue;
22309             }
22310             
22311             
22312             has_other_nodes = true;
22313         }
22314         if (!nodes.length && other_nodes.length) {
22315             nodes= other_nodes;
22316         }
22317         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22318             return false;
22319         }
22320         
22321         return nodes[0];
22322     },
22323     createRange: function(sel)
22324     {
22325         // this has strange effects when using with 
22326         // top toolbar - not sure if it's a great idea.
22327         //this.editor.contentWindow.focus();
22328         if (typeof sel != "undefined") {
22329             try {
22330                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22331             } catch(e) {
22332                 return this.doc.createRange();
22333             }
22334         } else {
22335             return this.doc.createRange();
22336         }
22337     },
22338     getParentElement: function()
22339     {
22340         
22341         this.assignDocWin();
22342         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22343         
22344         var range = this.createRange(sel);
22345          
22346         try {
22347             var p = range.commonAncestorContainer;
22348             while (p.nodeType == 3) { // text node
22349                 p = p.parentNode;
22350             }
22351             return p;
22352         } catch (e) {
22353             return null;
22354         }
22355     
22356     },
22357     /***
22358      *
22359      * Range intersection.. the hard stuff...
22360      *  '-1' = before
22361      *  '0' = hits..
22362      *  '1' = after.
22363      *         [ -- selected range --- ]
22364      *   [fail]                        [fail]
22365      *
22366      *    basically..
22367      *      if end is before start or  hits it. fail.
22368      *      if start is after end or hits it fail.
22369      *
22370      *   if either hits (but other is outside. - then it's not 
22371      *   
22372      *    
22373      **/
22374     
22375     
22376     // @see http://www.thismuchiknow.co.uk/?p=64.
22377     rangeIntersectsNode : function(range, node)
22378     {
22379         var nodeRange = node.ownerDocument.createRange();
22380         try {
22381             nodeRange.selectNode(node);
22382         } catch (e) {
22383             nodeRange.selectNodeContents(node);
22384         }
22385     
22386         var rangeStartRange = range.cloneRange();
22387         rangeStartRange.collapse(true);
22388     
22389         var rangeEndRange = range.cloneRange();
22390         rangeEndRange.collapse(false);
22391     
22392         var nodeStartRange = nodeRange.cloneRange();
22393         nodeStartRange.collapse(true);
22394     
22395         var nodeEndRange = nodeRange.cloneRange();
22396         nodeEndRange.collapse(false);
22397     
22398         return rangeStartRange.compareBoundaryPoints(
22399                  Range.START_TO_START, nodeEndRange) == -1 &&
22400                rangeEndRange.compareBoundaryPoints(
22401                  Range.START_TO_START, nodeStartRange) == 1;
22402         
22403          
22404     },
22405     rangeCompareNode : function(range, node)
22406     {
22407         var nodeRange = node.ownerDocument.createRange();
22408         try {
22409             nodeRange.selectNode(node);
22410         } catch (e) {
22411             nodeRange.selectNodeContents(node);
22412         }
22413         
22414         
22415         range.collapse(true);
22416     
22417         nodeRange.collapse(true);
22418      
22419         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22420         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22421          
22422         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22423         
22424         var nodeIsBefore   =  ss == 1;
22425         var nodeIsAfter    = ee == -1;
22426         
22427         if (nodeIsBefore && nodeIsAfter) {
22428             return 0; // outer
22429         }
22430         if (!nodeIsBefore && nodeIsAfter) {
22431             return 1; //right trailed.
22432         }
22433         
22434         if (nodeIsBefore && !nodeIsAfter) {
22435             return 2;  // left trailed.
22436         }
22437         // fully contined.
22438         return 3;
22439     },
22440
22441     // private? - in a new class?
22442     cleanUpPaste :  function()
22443     {
22444         // cleans up the whole document..
22445         Roo.log('cleanuppaste');
22446         
22447         this.cleanUpChildren(this.doc.body);
22448         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22449         if (clean != this.doc.body.innerHTML) {
22450             this.doc.body.innerHTML = clean;
22451         }
22452         
22453     },
22454     
22455     cleanWordChars : function(input) {// change the chars to hex code
22456         var he = Roo.HtmlEditorCore;
22457         
22458         var output = input;
22459         Roo.each(he.swapCodes, function(sw) { 
22460             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22461             
22462             output = output.replace(swapper, sw[1]);
22463         });
22464         
22465         return output;
22466     },
22467     
22468     
22469     cleanUpChildren : function (n)
22470     {
22471         if (!n.childNodes.length) {
22472             return;
22473         }
22474         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22475            this.cleanUpChild(n.childNodes[i]);
22476         }
22477     },
22478     
22479     
22480         
22481     
22482     cleanUpChild : function (node)
22483     {
22484         var ed = this;
22485         //console.log(node);
22486         if (node.nodeName == "#text") {
22487             // clean up silly Windows -- stuff?
22488             return; 
22489         }
22490         if (node.nodeName == "#comment") {
22491             node.parentNode.removeChild(node);
22492             // clean up silly Windows -- stuff?
22493             return; 
22494         }
22495         var lcname = node.tagName.toLowerCase();
22496         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22497         // whitelist of tags..
22498         
22499         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22500             // remove node.
22501             node.parentNode.removeChild(node);
22502             return;
22503             
22504         }
22505         
22506         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22507         
22508         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22509         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22510         
22511         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22512         //    remove_keep_children = true;
22513         //}
22514         
22515         if (remove_keep_children) {
22516             this.cleanUpChildren(node);
22517             // inserts everything just before this node...
22518             while (node.childNodes.length) {
22519                 var cn = node.childNodes[0];
22520                 node.removeChild(cn);
22521                 node.parentNode.insertBefore(cn, node);
22522             }
22523             node.parentNode.removeChild(node);
22524             return;
22525         }
22526         
22527         if (!node.attributes || !node.attributes.length) {
22528             this.cleanUpChildren(node);
22529             return;
22530         }
22531         
22532         function cleanAttr(n,v)
22533         {
22534             
22535             if (v.match(/^\./) || v.match(/^\//)) {
22536                 return;
22537             }
22538             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22539                 return;
22540             }
22541             if (v.match(/^#/)) {
22542                 return;
22543             }
22544 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22545             node.removeAttribute(n);
22546             
22547         }
22548         
22549         var cwhite = this.cwhite;
22550         var cblack = this.cblack;
22551             
22552         function cleanStyle(n,v)
22553         {
22554             if (v.match(/expression/)) { //XSS?? should we even bother..
22555                 node.removeAttribute(n);
22556                 return;
22557             }
22558             
22559             var parts = v.split(/;/);
22560             var clean = [];
22561             
22562             Roo.each(parts, function(p) {
22563                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22564                 if (!p.length) {
22565                     return true;
22566                 }
22567                 var l = p.split(':').shift().replace(/\s+/g,'');
22568                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22569                 
22570                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22571 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22572                     //node.removeAttribute(n);
22573                     return true;
22574                 }
22575                 //Roo.log()
22576                 // only allow 'c whitelisted system attributes'
22577                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22578 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22579                     //node.removeAttribute(n);
22580                     return true;
22581                 }
22582                 
22583                 
22584                  
22585                 
22586                 clean.push(p);
22587                 return true;
22588             });
22589             if (clean.length) { 
22590                 node.setAttribute(n, clean.join(';'));
22591             } else {
22592                 node.removeAttribute(n);
22593             }
22594             
22595         }
22596         
22597         
22598         for (var i = node.attributes.length-1; i > -1 ; i--) {
22599             var a = node.attributes[i];
22600             //console.log(a);
22601             
22602             if (a.name.toLowerCase().substr(0,2)=='on')  {
22603                 node.removeAttribute(a.name);
22604                 continue;
22605             }
22606             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22607                 node.removeAttribute(a.name);
22608                 continue;
22609             }
22610             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22611                 cleanAttr(a.name,a.value); // fixme..
22612                 continue;
22613             }
22614             if (a.name == 'style') {
22615                 cleanStyle(a.name,a.value);
22616                 continue;
22617             }
22618             /// clean up MS crap..
22619             // tecnically this should be a list of valid class'es..
22620             
22621             
22622             if (a.name == 'class') {
22623                 if (a.value.match(/^Mso/)) {
22624                     node.className = '';
22625                 }
22626                 
22627                 if (a.value.match(/^body$/)) {
22628                     node.className = '';
22629                 }
22630                 continue;
22631             }
22632             
22633             // style cleanup!?
22634             // class cleanup?
22635             
22636         }
22637         
22638         
22639         this.cleanUpChildren(node);
22640         
22641         
22642     },
22643     
22644     /**
22645      * Clean up MS wordisms...
22646      */
22647     cleanWord : function(node)
22648     {
22649         
22650         
22651         if (!node) {
22652             this.cleanWord(this.doc.body);
22653             return;
22654         }
22655         if (node.nodeName == "#text") {
22656             // clean up silly Windows -- stuff?
22657             return; 
22658         }
22659         if (node.nodeName == "#comment") {
22660             node.parentNode.removeChild(node);
22661             // clean up silly Windows -- stuff?
22662             return; 
22663         }
22664         
22665         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22666             node.parentNode.removeChild(node);
22667             return;
22668         }
22669         
22670         // remove - but keep children..
22671         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22672             while (node.childNodes.length) {
22673                 var cn = node.childNodes[0];
22674                 node.removeChild(cn);
22675                 node.parentNode.insertBefore(cn, node);
22676             }
22677             node.parentNode.removeChild(node);
22678             this.iterateChildren(node, this.cleanWord);
22679             return;
22680         }
22681         // clean styles
22682         if (node.className.length) {
22683             
22684             var cn = node.className.split(/\W+/);
22685             var cna = [];
22686             Roo.each(cn, function(cls) {
22687                 if (cls.match(/Mso[a-zA-Z]+/)) {
22688                     return;
22689                 }
22690                 cna.push(cls);
22691             });
22692             node.className = cna.length ? cna.join(' ') : '';
22693             if (!cna.length) {
22694                 node.removeAttribute("class");
22695             }
22696         }
22697         
22698         if (node.hasAttribute("lang")) {
22699             node.removeAttribute("lang");
22700         }
22701         
22702         if (node.hasAttribute("style")) {
22703             
22704             var styles = node.getAttribute("style").split(";");
22705             var nstyle = [];
22706             Roo.each(styles, function(s) {
22707                 if (!s.match(/:/)) {
22708                     return;
22709                 }
22710                 var kv = s.split(":");
22711                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22712                     return;
22713                 }
22714                 // what ever is left... we allow.
22715                 nstyle.push(s);
22716             });
22717             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22718             if (!nstyle.length) {
22719                 node.removeAttribute('style');
22720             }
22721         }
22722         this.iterateChildren(node, this.cleanWord);
22723         
22724         
22725         
22726     },
22727     /**
22728      * iterateChildren of a Node, calling fn each time, using this as the scole..
22729      * @param {DomNode} node node to iterate children of.
22730      * @param {Function} fn method of this class to call on each item.
22731      */
22732     iterateChildren : function(node, fn)
22733     {
22734         if (!node.childNodes.length) {
22735                 return;
22736         }
22737         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22738            fn.call(this, node.childNodes[i])
22739         }
22740     },
22741     
22742     
22743     /**
22744      * cleanTableWidths.
22745      *
22746      * Quite often pasting from word etc.. results in tables with column and widths.
22747      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22748      *
22749      */
22750     cleanTableWidths : function(node)
22751     {
22752          
22753          
22754         if (!node) {
22755             this.cleanTableWidths(this.doc.body);
22756             return;
22757         }
22758         
22759         // ignore list...
22760         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22761             return; 
22762         }
22763         Roo.log(node.tagName);
22764         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22765             this.iterateChildren(node, this.cleanTableWidths);
22766             return;
22767         }
22768         if (node.hasAttribute('width')) {
22769             node.removeAttribute('width');
22770         }
22771         
22772          
22773         if (node.hasAttribute("style")) {
22774             // pretty basic...
22775             
22776             var styles = node.getAttribute("style").split(";");
22777             var nstyle = [];
22778             Roo.each(styles, function(s) {
22779                 if (!s.match(/:/)) {
22780                     return;
22781                 }
22782                 var kv = s.split(":");
22783                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22784                     return;
22785                 }
22786                 // what ever is left... we allow.
22787                 nstyle.push(s);
22788             });
22789             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22790             if (!nstyle.length) {
22791                 node.removeAttribute('style');
22792             }
22793         }
22794         
22795         this.iterateChildren(node, this.cleanTableWidths);
22796         
22797         
22798     },
22799     
22800     
22801     
22802     
22803     domToHTML : function(currentElement, depth, nopadtext) {
22804         
22805         depth = depth || 0;
22806         nopadtext = nopadtext || false;
22807     
22808         if (!currentElement) {
22809             return this.domToHTML(this.doc.body);
22810         }
22811         
22812         //Roo.log(currentElement);
22813         var j;
22814         var allText = false;
22815         var nodeName = currentElement.nodeName;
22816         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22817         
22818         if  (nodeName == '#text') {
22819             
22820             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22821         }
22822         
22823         
22824         var ret = '';
22825         if (nodeName != 'BODY') {
22826              
22827             var i = 0;
22828             // Prints the node tagName, such as <A>, <IMG>, etc
22829             if (tagName) {
22830                 var attr = [];
22831                 for(i = 0; i < currentElement.attributes.length;i++) {
22832                     // quoting?
22833                     var aname = currentElement.attributes.item(i).name;
22834                     if (!currentElement.attributes.item(i).value.length) {
22835                         continue;
22836                     }
22837                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22838                 }
22839                 
22840                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22841             } 
22842             else {
22843                 
22844                 // eack
22845             }
22846         } else {
22847             tagName = false;
22848         }
22849         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22850             return ret;
22851         }
22852         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22853             nopadtext = true;
22854         }
22855         
22856         
22857         // Traverse the tree
22858         i = 0;
22859         var currentElementChild = currentElement.childNodes.item(i);
22860         var allText = true;
22861         var innerHTML  = '';
22862         lastnode = '';
22863         while (currentElementChild) {
22864             // Formatting code (indent the tree so it looks nice on the screen)
22865             var nopad = nopadtext;
22866             if (lastnode == 'SPAN') {
22867                 nopad  = true;
22868             }
22869             // text
22870             if  (currentElementChild.nodeName == '#text') {
22871                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22872                 toadd = nopadtext ? toadd : toadd.trim();
22873                 if (!nopad && toadd.length > 80) {
22874                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22875                 }
22876                 innerHTML  += toadd;
22877                 
22878                 i++;
22879                 currentElementChild = currentElement.childNodes.item(i);
22880                 lastNode = '';
22881                 continue;
22882             }
22883             allText = false;
22884             
22885             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22886                 
22887             // Recursively traverse the tree structure of the child node
22888             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22889             lastnode = currentElementChild.nodeName;
22890             i++;
22891             currentElementChild=currentElement.childNodes.item(i);
22892         }
22893         
22894         ret += innerHTML;
22895         
22896         if (!allText) {
22897                 // The remaining code is mostly for formatting the tree
22898             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22899         }
22900         
22901         
22902         if (tagName) {
22903             ret+= "</"+tagName+">";
22904         }
22905         return ret;
22906         
22907     },
22908         
22909     applyBlacklists : function()
22910     {
22911         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22912         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22913         
22914         this.white = [];
22915         this.black = [];
22916         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22917             if (b.indexOf(tag) > -1) {
22918                 return;
22919             }
22920             this.white.push(tag);
22921             
22922         }, this);
22923         
22924         Roo.each(w, function(tag) {
22925             if (b.indexOf(tag) > -1) {
22926                 return;
22927             }
22928             if (this.white.indexOf(tag) > -1) {
22929                 return;
22930             }
22931             this.white.push(tag);
22932             
22933         }, this);
22934         
22935         
22936         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22937             if (w.indexOf(tag) > -1) {
22938                 return;
22939             }
22940             this.black.push(tag);
22941             
22942         }, this);
22943         
22944         Roo.each(b, function(tag) {
22945             if (w.indexOf(tag) > -1) {
22946                 return;
22947             }
22948             if (this.black.indexOf(tag) > -1) {
22949                 return;
22950             }
22951             this.black.push(tag);
22952             
22953         }, this);
22954         
22955         
22956         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22957         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22958         
22959         this.cwhite = [];
22960         this.cblack = [];
22961         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22962             if (b.indexOf(tag) > -1) {
22963                 return;
22964             }
22965             this.cwhite.push(tag);
22966             
22967         }, this);
22968         
22969         Roo.each(w, function(tag) {
22970             if (b.indexOf(tag) > -1) {
22971                 return;
22972             }
22973             if (this.cwhite.indexOf(tag) > -1) {
22974                 return;
22975             }
22976             this.cwhite.push(tag);
22977             
22978         }, this);
22979         
22980         
22981         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22982             if (w.indexOf(tag) > -1) {
22983                 return;
22984             }
22985             this.cblack.push(tag);
22986             
22987         }, this);
22988         
22989         Roo.each(b, function(tag) {
22990             if (w.indexOf(tag) > -1) {
22991                 return;
22992             }
22993             if (this.cblack.indexOf(tag) > -1) {
22994                 return;
22995             }
22996             this.cblack.push(tag);
22997             
22998         }, this);
22999     },
23000     
23001     setStylesheets : function(stylesheets)
23002     {
23003         if(typeof(stylesheets) == 'string'){
23004             Roo.get(this.iframe.contentDocument.head).createChild({
23005                 tag : 'link',
23006                 rel : 'stylesheet',
23007                 type : 'text/css',
23008                 href : stylesheets
23009             });
23010             
23011             return;
23012         }
23013         var _this = this;
23014      
23015         Roo.each(stylesheets, function(s) {
23016             if(!s.length){
23017                 return;
23018             }
23019             
23020             Roo.get(_this.iframe.contentDocument.head).createChild({
23021                 tag : 'link',
23022                 rel : 'stylesheet',
23023                 type : 'text/css',
23024                 href : s
23025             });
23026         });
23027
23028         
23029     },
23030     
23031     removeStylesheets : function()
23032     {
23033         var _this = this;
23034         
23035         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23036             s.remove();
23037         });
23038     },
23039     
23040     setStyle : function(style)
23041     {
23042         Roo.get(this.iframe.contentDocument.head).createChild({
23043             tag : 'style',
23044             type : 'text/css',
23045             html : style
23046         });
23047
23048         return;
23049     }
23050     
23051     // hide stuff that is not compatible
23052     /**
23053      * @event blur
23054      * @hide
23055      */
23056     /**
23057      * @event change
23058      * @hide
23059      */
23060     /**
23061      * @event focus
23062      * @hide
23063      */
23064     /**
23065      * @event specialkey
23066      * @hide
23067      */
23068     /**
23069      * @cfg {String} fieldClass @hide
23070      */
23071     /**
23072      * @cfg {String} focusClass @hide
23073      */
23074     /**
23075      * @cfg {String} autoCreate @hide
23076      */
23077     /**
23078      * @cfg {String} inputType @hide
23079      */
23080     /**
23081      * @cfg {String} invalidClass @hide
23082      */
23083     /**
23084      * @cfg {String} invalidText @hide
23085      */
23086     /**
23087      * @cfg {String} msgFx @hide
23088      */
23089     /**
23090      * @cfg {String} validateOnBlur @hide
23091      */
23092 });
23093
23094 Roo.HtmlEditorCore.white = [
23095         'area', 'br', 'img', 'input', 'hr', 'wbr',
23096         
23097        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23098        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23099        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23100        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23101        'table',   'ul',         'xmp', 
23102        
23103        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23104       'thead',   'tr', 
23105      
23106       'dir', 'menu', 'ol', 'ul', 'dl',
23107        
23108       'embed',  'object'
23109 ];
23110
23111
23112 Roo.HtmlEditorCore.black = [
23113     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23114         'applet', // 
23115         'base',   'basefont', 'bgsound', 'blink',  'body', 
23116         'frame',  'frameset', 'head',    'html',   'ilayer', 
23117         'iframe', 'layer',  'link',     'meta',    'object',   
23118         'script', 'style' ,'title',  'xml' // clean later..
23119 ];
23120 Roo.HtmlEditorCore.clean = [
23121     'script', 'style', 'title', 'xml'
23122 ];
23123 Roo.HtmlEditorCore.remove = [
23124     'font'
23125 ];
23126 // attributes..
23127
23128 Roo.HtmlEditorCore.ablack = [
23129     'on'
23130 ];
23131     
23132 Roo.HtmlEditorCore.aclean = [ 
23133     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23134 ];
23135
23136 // protocols..
23137 Roo.HtmlEditorCore.pwhite= [
23138         'http',  'https',  'mailto'
23139 ];
23140
23141 // white listed style attributes.
23142 Roo.HtmlEditorCore.cwhite= [
23143       //  'text-align', /// default is to allow most things..
23144       
23145          
23146 //        'font-size'//??
23147 ];
23148
23149 // black listed style attributes.
23150 Roo.HtmlEditorCore.cblack= [
23151       //  'font-size' -- this can be set by the project 
23152 ];
23153
23154
23155 Roo.HtmlEditorCore.swapCodes   =[ 
23156     [    8211, "--" ], 
23157     [    8212, "--" ], 
23158     [    8216,  "'" ],  
23159     [    8217, "'" ],  
23160     [    8220, '"' ],  
23161     [    8221, '"' ],  
23162     [    8226, "*" ],  
23163     [    8230, "..." ]
23164 ]; 
23165
23166     /*
23167  * - LGPL
23168  *
23169  * HtmlEditor
23170  * 
23171  */
23172
23173 /**
23174  * @class Roo.bootstrap.HtmlEditor
23175  * @extends Roo.bootstrap.TextArea
23176  * Bootstrap HtmlEditor class
23177
23178  * @constructor
23179  * Create a new HtmlEditor
23180  * @param {Object} config The config object
23181  */
23182
23183 Roo.bootstrap.HtmlEditor = function(config){
23184     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23185     if (!this.toolbars) {
23186         this.toolbars = [];
23187     }
23188     
23189     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23190     this.addEvents({
23191             /**
23192              * @event initialize
23193              * Fires when the editor is fully initialized (including the iframe)
23194              * @param {HtmlEditor} this
23195              */
23196             initialize: true,
23197             /**
23198              * @event activate
23199              * Fires when the editor is first receives the focus. Any insertion must wait
23200              * until after this event.
23201              * @param {HtmlEditor} this
23202              */
23203             activate: true,
23204              /**
23205              * @event beforesync
23206              * Fires before the textarea is updated with content from the editor iframe. Return false
23207              * to cancel the sync.
23208              * @param {HtmlEditor} this
23209              * @param {String} html
23210              */
23211             beforesync: true,
23212              /**
23213              * @event beforepush
23214              * Fires before the iframe editor is updated with content from the textarea. Return false
23215              * to cancel the push.
23216              * @param {HtmlEditor} this
23217              * @param {String} html
23218              */
23219             beforepush: true,
23220              /**
23221              * @event sync
23222              * Fires when the textarea is updated with content from the editor iframe.
23223              * @param {HtmlEditor} this
23224              * @param {String} html
23225              */
23226             sync: true,
23227              /**
23228              * @event push
23229              * Fires when the iframe editor is updated with content from the textarea.
23230              * @param {HtmlEditor} this
23231              * @param {String} html
23232              */
23233             push: true,
23234              /**
23235              * @event editmodechange
23236              * Fires when the editor switches edit modes
23237              * @param {HtmlEditor} this
23238              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23239              */
23240             editmodechange: true,
23241             /**
23242              * @event editorevent
23243              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23244              * @param {HtmlEditor} this
23245              */
23246             editorevent: true,
23247             /**
23248              * @event firstfocus
23249              * Fires when on first focus - needed by toolbars..
23250              * @param {HtmlEditor} this
23251              */
23252             firstfocus: true,
23253             /**
23254              * @event autosave
23255              * Auto save the htmlEditor value as a file into Events
23256              * @param {HtmlEditor} this
23257              */
23258             autosave: true,
23259             /**
23260              * @event savedpreview
23261              * preview the saved version of htmlEditor
23262              * @param {HtmlEditor} this
23263              */
23264             savedpreview: true
23265         });
23266 };
23267
23268
23269 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23270     
23271     
23272       /**
23273      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23274      */
23275     toolbars : false,
23276     
23277      /**
23278     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23279     */
23280     btns : [],
23281    
23282      /**
23283      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23284      *                        Roo.resizable.
23285      */
23286     resizable : false,
23287      /**
23288      * @cfg {Number} height (in pixels)
23289      */   
23290     height: 300,
23291    /**
23292      * @cfg {Number} width (in pixels)
23293      */   
23294     width: false,
23295     
23296     /**
23297      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23298      * 
23299      */
23300     stylesheets: false,
23301     
23302     // id of frame..
23303     frameId: false,
23304     
23305     // private properties
23306     validationEvent : false,
23307     deferHeight: true,
23308     initialized : false,
23309     activated : false,
23310     
23311     onFocus : Roo.emptyFn,
23312     iframePad:3,
23313     hideMode:'offsets',
23314     
23315     tbContainer : false,
23316     
23317     bodyCls : '',
23318     
23319     toolbarContainer :function() {
23320         return this.wrap.select('.x-html-editor-tb',true).first();
23321     },
23322
23323     /**
23324      * Protected method that will not generally be called directly. It
23325      * is called when the editor creates its toolbar. Override this method if you need to
23326      * add custom toolbar buttons.
23327      * @param {HtmlEditor} editor
23328      */
23329     createToolbar : function(){
23330         Roo.log('renewing');
23331         Roo.log("create toolbars");
23332         
23333         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23334         this.toolbars[0].render(this.toolbarContainer());
23335         
23336         return;
23337         
23338 //        if (!editor.toolbars || !editor.toolbars.length) {
23339 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23340 //        }
23341 //        
23342 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23343 //            editor.toolbars[i] = Roo.factory(
23344 //                    typeof(editor.toolbars[i]) == 'string' ?
23345 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23346 //                Roo.bootstrap.HtmlEditor);
23347 //            editor.toolbars[i].init(editor);
23348 //        }
23349     },
23350
23351      
23352     // private
23353     onRender : function(ct, position)
23354     {
23355        // Roo.log("Call onRender: " + this.xtype);
23356         var _t = this;
23357         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23358       
23359         this.wrap = this.inputEl().wrap({
23360             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23361         });
23362         
23363         this.editorcore.onRender(ct, position);
23364          
23365         if (this.resizable) {
23366             this.resizeEl = new Roo.Resizable(this.wrap, {
23367                 pinned : true,
23368                 wrap: true,
23369                 dynamic : true,
23370                 minHeight : this.height,
23371                 height: this.height,
23372                 handles : this.resizable,
23373                 width: this.width,
23374                 listeners : {
23375                     resize : function(r, w, h) {
23376                         _t.onResize(w,h); // -something
23377                     }
23378                 }
23379             });
23380             
23381         }
23382         this.createToolbar(this);
23383        
23384         
23385         if(!this.width && this.resizable){
23386             this.setSize(this.wrap.getSize());
23387         }
23388         if (this.resizeEl) {
23389             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23390             // should trigger onReize..
23391         }
23392         
23393     },
23394
23395     // private
23396     onResize : function(w, h)
23397     {
23398         Roo.log('resize: ' +w + ',' + h );
23399         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23400         var ew = false;
23401         var eh = false;
23402         
23403         if(this.inputEl() ){
23404             if(typeof w == 'number'){
23405                 var aw = w - this.wrap.getFrameWidth('lr');
23406                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23407                 ew = aw;
23408             }
23409             if(typeof h == 'number'){
23410                  var tbh = -11;  // fixme it needs to tool bar size!
23411                 for (var i =0; i < this.toolbars.length;i++) {
23412                     // fixme - ask toolbars for heights?
23413                     tbh += this.toolbars[i].el.getHeight();
23414                     //if (this.toolbars[i].footer) {
23415                     //    tbh += this.toolbars[i].footer.el.getHeight();
23416                     //}
23417                 }
23418               
23419                 
23420                 
23421                 
23422                 
23423                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23424                 ah -= 5; // knock a few pixes off for look..
23425                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23426                 var eh = ah;
23427             }
23428         }
23429         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23430         this.editorcore.onResize(ew,eh);
23431         
23432     },
23433
23434     /**
23435      * Toggles the editor between standard and source edit mode.
23436      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23437      */
23438     toggleSourceEdit : function(sourceEditMode)
23439     {
23440         this.editorcore.toggleSourceEdit(sourceEditMode);
23441         
23442         if(this.editorcore.sourceEditMode){
23443             Roo.log('editor - showing textarea');
23444             
23445 //            Roo.log('in');
23446 //            Roo.log(this.syncValue());
23447             this.syncValue();
23448             this.inputEl().removeClass(['hide', 'x-hidden']);
23449             this.inputEl().dom.removeAttribute('tabIndex');
23450             this.inputEl().focus();
23451         }else{
23452             Roo.log('editor - hiding textarea');
23453 //            Roo.log('out')
23454 //            Roo.log(this.pushValue()); 
23455             this.pushValue();
23456             
23457             this.inputEl().addClass(['hide', 'x-hidden']);
23458             this.inputEl().dom.setAttribute('tabIndex', -1);
23459             //this.deferFocus();
23460         }
23461          
23462         if(this.resizable){
23463             this.setSize(this.wrap.getSize());
23464         }
23465         
23466         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23467     },
23468  
23469     // private (for BoxComponent)
23470     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23471
23472     // private (for BoxComponent)
23473     getResizeEl : function(){
23474         return this.wrap;
23475     },
23476
23477     // private (for BoxComponent)
23478     getPositionEl : function(){
23479         return this.wrap;
23480     },
23481
23482     // private
23483     initEvents : function(){
23484         this.originalValue = this.getValue();
23485     },
23486
23487 //    /**
23488 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23489 //     * @method
23490 //     */
23491 //    markInvalid : Roo.emptyFn,
23492 //    /**
23493 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23494 //     * @method
23495 //     */
23496 //    clearInvalid : Roo.emptyFn,
23497
23498     setValue : function(v){
23499         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23500         this.editorcore.pushValue();
23501     },
23502
23503      
23504     // private
23505     deferFocus : function(){
23506         this.focus.defer(10, this);
23507     },
23508
23509     // doc'ed in Field
23510     focus : function(){
23511         this.editorcore.focus();
23512         
23513     },
23514       
23515
23516     // private
23517     onDestroy : function(){
23518         
23519         
23520         
23521         if(this.rendered){
23522             
23523             for (var i =0; i < this.toolbars.length;i++) {
23524                 // fixme - ask toolbars for heights?
23525                 this.toolbars[i].onDestroy();
23526             }
23527             
23528             this.wrap.dom.innerHTML = '';
23529             this.wrap.remove();
23530         }
23531     },
23532
23533     // private
23534     onFirstFocus : function(){
23535         //Roo.log("onFirstFocus");
23536         this.editorcore.onFirstFocus();
23537          for (var i =0; i < this.toolbars.length;i++) {
23538             this.toolbars[i].onFirstFocus();
23539         }
23540         
23541     },
23542     
23543     // private
23544     syncValue : function()
23545     {   
23546         this.editorcore.syncValue();
23547     },
23548     
23549     pushValue : function()
23550     {   
23551         this.editorcore.pushValue();
23552     }
23553      
23554     
23555     // hide stuff that is not compatible
23556     /**
23557      * @event blur
23558      * @hide
23559      */
23560     /**
23561      * @event change
23562      * @hide
23563      */
23564     /**
23565      * @event focus
23566      * @hide
23567      */
23568     /**
23569      * @event specialkey
23570      * @hide
23571      */
23572     /**
23573      * @cfg {String} fieldClass @hide
23574      */
23575     /**
23576      * @cfg {String} focusClass @hide
23577      */
23578     /**
23579      * @cfg {String} autoCreate @hide
23580      */
23581     /**
23582      * @cfg {String} inputType @hide
23583      */
23584     /**
23585      * @cfg {String} invalidClass @hide
23586      */
23587     /**
23588      * @cfg {String} invalidText @hide
23589      */
23590     /**
23591      * @cfg {String} msgFx @hide
23592      */
23593     /**
23594      * @cfg {String} validateOnBlur @hide
23595      */
23596 });
23597  
23598     
23599    
23600    
23601    
23602       
23603 Roo.namespace('Roo.bootstrap.htmleditor');
23604 /**
23605  * @class Roo.bootstrap.HtmlEditorToolbar1
23606  * Basic Toolbar
23607  * 
23608  * Usage:
23609  *
23610  new Roo.bootstrap.HtmlEditor({
23611     ....
23612     toolbars : [
23613         new Roo.bootstrap.HtmlEditorToolbar1({
23614             disable : { fonts: 1 , format: 1, ..., ... , ...],
23615             btns : [ .... ]
23616         })
23617     }
23618      
23619  * 
23620  * @cfg {Object} disable List of elements to disable..
23621  * @cfg {Array} btns List of additional buttons.
23622  * 
23623  * 
23624  * NEEDS Extra CSS? 
23625  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23626  */
23627  
23628 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23629 {
23630     
23631     Roo.apply(this, config);
23632     
23633     // default disabled, based on 'good practice'..
23634     this.disable = this.disable || {};
23635     Roo.applyIf(this.disable, {
23636         fontSize : true,
23637         colors : true,
23638         specialElements : true
23639     });
23640     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23641     
23642     this.editor = config.editor;
23643     this.editorcore = config.editor.editorcore;
23644     
23645     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23646     
23647     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23648     // dont call parent... till later.
23649 }
23650 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23651      
23652     bar : true,
23653     
23654     editor : false,
23655     editorcore : false,
23656     
23657     
23658     formats : [
23659         "p" ,  
23660         "h1","h2","h3","h4","h5","h6", 
23661         "pre", "code", 
23662         "abbr", "acronym", "address", "cite", "samp", "var",
23663         'div','span'
23664     ],
23665     
23666     onRender : function(ct, position)
23667     {
23668        // Roo.log("Call onRender: " + this.xtype);
23669         
23670        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23671        Roo.log(this.el);
23672        this.el.dom.style.marginBottom = '0';
23673        var _this = this;
23674        var editorcore = this.editorcore;
23675        var editor= this.editor;
23676        
23677        var children = [];
23678        var btn = function(id,cmd , toggle, handler, html){
23679        
23680             var  event = toggle ? 'toggle' : 'click';
23681        
23682             var a = {
23683                 size : 'sm',
23684                 xtype: 'Button',
23685                 xns: Roo.bootstrap,
23686                 glyphicon : id,
23687                 cmd : id || cmd,
23688                 enableToggle:toggle !== false,
23689                 html : html || '',
23690                 pressed : toggle ? false : null,
23691                 listeners : {}
23692             };
23693             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23694                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23695             };
23696             children.push(a);
23697             return a;
23698        }
23699        
23700     //    var cb_box = function...
23701         
23702         var style = {
23703                 xtype: 'Button',
23704                 size : 'sm',
23705                 xns: Roo.bootstrap,
23706                 glyphicon : 'font',
23707                 //html : 'submit'
23708                 menu : {
23709                     xtype: 'Menu',
23710                     xns: Roo.bootstrap,
23711                     items:  []
23712                 }
23713         };
23714         Roo.each(this.formats, function(f) {
23715             style.menu.items.push({
23716                 xtype :'MenuItem',
23717                 xns: Roo.bootstrap,
23718                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23719                 tagname : f,
23720                 listeners : {
23721                     click : function()
23722                     {
23723                         editorcore.insertTag(this.tagname);
23724                         editor.focus();
23725                     }
23726                 }
23727                 
23728             });
23729         });
23730         children.push(style);   
23731         
23732         btn('bold',false,true);
23733         btn('italic',false,true);
23734         btn('align-left', 'justifyleft',true);
23735         btn('align-center', 'justifycenter',true);
23736         btn('align-right' , 'justifyright',true);
23737         btn('link', false, false, function(btn) {
23738             //Roo.log("create link?");
23739             var url = prompt(this.createLinkText, this.defaultLinkValue);
23740             if(url && url != 'http:/'+'/'){
23741                 this.editorcore.relayCmd('createlink', url);
23742             }
23743         }),
23744         btn('list','insertunorderedlist',true);
23745         btn('pencil', false,true, function(btn){
23746                 Roo.log(this);
23747                 this.toggleSourceEdit(btn.pressed);
23748         });
23749         
23750         if (this.editor.btns.length > 0) {
23751             for (var i = 0; i<this.editor.btns.length; i++) {
23752                 children.push(this.editor.btns[i]);
23753             }
23754         }
23755         
23756         /*
23757         var cog = {
23758                 xtype: 'Button',
23759                 size : 'sm',
23760                 xns: Roo.bootstrap,
23761                 glyphicon : 'cog',
23762                 //html : 'submit'
23763                 menu : {
23764                     xtype: 'Menu',
23765                     xns: Roo.bootstrap,
23766                     items:  []
23767                 }
23768         };
23769         
23770         cog.menu.items.push({
23771             xtype :'MenuItem',
23772             xns: Roo.bootstrap,
23773             html : Clean styles,
23774             tagname : f,
23775             listeners : {
23776                 click : function()
23777                 {
23778                     editorcore.insertTag(this.tagname);
23779                     editor.focus();
23780                 }
23781             }
23782             
23783         });
23784        */
23785         
23786          
23787        this.xtype = 'NavSimplebar';
23788         
23789         for(var i=0;i< children.length;i++) {
23790             
23791             this.buttons.add(this.addxtypeChild(children[i]));
23792             
23793         }
23794         
23795         editor.on('editorevent', this.updateToolbar, this);
23796     },
23797     onBtnClick : function(id)
23798     {
23799        this.editorcore.relayCmd(id);
23800        this.editorcore.focus();
23801     },
23802     
23803     /**
23804      * Protected method that will not generally be called directly. It triggers
23805      * a toolbar update by reading the markup state of the current selection in the editor.
23806      */
23807     updateToolbar: function(){
23808
23809         if(!this.editorcore.activated){
23810             this.editor.onFirstFocus(); // is this neeed?
23811             return;
23812         }
23813
23814         var btns = this.buttons; 
23815         var doc = this.editorcore.doc;
23816         btns.get('bold').setActive(doc.queryCommandState('bold'));
23817         btns.get('italic').setActive(doc.queryCommandState('italic'));
23818         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23819         
23820         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23821         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23822         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23823         
23824         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23825         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23826          /*
23827         
23828         var ans = this.editorcore.getAllAncestors();
23829         if (this.formatCombo) {
23830             
23831             
23832             var store = this.formatCombo.store;
23833             this.formatCombo.setValue("");
23834             for (var i =0; i < ans.length;i++) {
23835                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23836                     // select it..
23837                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23838                     break;
23839                 }
23840             }
23841         }
23842         
23843         
23844         
23845         // hides menus... - so this cant be on a menu...
23846         Roo.bootstrap.MenuMgr.hideAll();
23847         */
23848         Roo.bootstrap.MenuMgr.hideAll();
23849         //this.editorsyncValue();
23850     },
23851     onFirstFocus: function() {
23852         this.buttons.each(function(item){
23853            item.enable();
23854         });
23855     },
23856     toggleSourceEdit : function(sourceEditMode){
23857         
23858           
23859         if(sourceEditMode){
23860             Roo.log("disabling buttons");
23861            this.buttons.each( function(item){
23862                 if(item.cmd != 'pencil'){
23863                     item.disable();
23864                 }
23865             });
23866           
23867         }else{
23868             Roo.log("enabling buttons");
23869             if(this.editorcore.initialized){
23870                 this.buttons.each( function(item){
23871                     item.enable();
23872                 });
23873             }
23874             
23875         }
23876         Roo.log("calling toggole on editor");
23877         // tell the editor that it's been pressed..
23878         this.editor.toggleSourceEdit(sourceEditMode);
23879        
23880     }
23881 });
23882
23883
23884
23885
23886
23887 /**
23888  * @class Roo.bootstrap.Table.AbstractSelectionModel
23889  * @extends Roo.util.Observable
23890  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23891  * implemented by descendant classes.  This class should not be directly instantiated.
23892  * @constructor
23893  */
23894 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23895     this.locked = false;
23896     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23897 };
23898
23899
23900 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23901     /** @ignore Called by the grid automatically. Do not call directly. */
23902     init : function(grid){
23903         this.grid = grid;
23904         this.initEvents();
23905     },
23906
23907     /**
23908      * Locks the selections.
23909      */
23910     lock : function(){
23911         this.locked = true;
23912     },
23913
23914     /**
23915      * Unlocks the selections.
23916      */
23917     unlock : function(){
23918         this.locked = false;
23919     },
23920
23921     /**
23922      * Returns true if the selections are locked.
23923      * @return {Boolean}
23924      */
23925     isLocked : function(){
23926         return this.locked;
23927     }
23928 });
23929 /**
23930  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23931  * @class Roo.bootstrap.Table.RowSelectionModel
23932  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23933  * It supports multiple selections and keyboard selection/navigation. 
23934  * @constructor
23935  * @param {Object} config
23936  */
23937
23938 Roo.bootstrap.Table.RowSelectionModel = function(config){
23939     Roo.apply(this, config);
23940     this.selections = new Roo.util.MixedCollection(false, function(o){
23941         return o.id;
23942     });
23943
23944     this.last = false;
23945     this.lastActive = false;
23946
23947     this.addEvents({
23948         /**
23949              * @event selectionchange
23950              * Fires when the selection changes
23951              * @param {SelectionModel} this
23952              */
23953             "selectionchange" : true,
23954         /**
23955              * @event afterselectionchange
23956              * Fires after the selection changes (eg. by key press or clicking)
23957              * @param {SelectionModel} this
23958              */
23959             "afterselectionchange" : true,
23960         /**
23961              * @event beforerowselect
23962              * Fires when a row is selected being selected, return false to cancel.
23963              * @param {SelectionModel} this
23964              * @param {Number} rowIndex The selected index
23965              * @param {Boolean} keepExisting False if other selections will be cleared
23966              */
23967             "beforerowselect" : true,
23968         /**
23969              * @event rowselect
23970              * Fires when a row is selected.
23971              * @param {SelectionModel} this
23972              * @param {Number} rowIndex The selected index
23973              * @param {Roo.data.Record} r The record
23974              */
23975             "rowselect" : true,
23976         /**
23977              * @event rowdeselect
23978              * Fires when a row is deselected.
23979              * @param {SelectionModel} this
23980              * @param {Number} rowIndex The selected index
23981              */
23982         "rowdeselect" : true
23983     });
23984     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23985     this.locked = false;
23986  };
23987
23988 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23989     /**
23990      * @cfg {Boolean} singleSelect
23991      * True to allow selection of only one row at a time (defaults to false)
23992      */
23993     singleSelect : false,
23994
23995     // private
23996     initEvents : function()
23997     {
23998
23999         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24000         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
24001         //}else{ // allow click to work like normal
24002          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
24003         //}
24004         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24005         this.grid.on("rowclick", this.handleMouseDown, this);
24006         
24007         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24008             "up" : function(e){
24009                 if(!e.shiftKey){
24010                     this.selectPrevious(e.shiftKey);
24011                 }else if(this.last !== false && this.lastActive !== false){
24012                     var last = this.last;
24013                     this.selectRange(this.last,  this.lastActive-1);
24014                     this.grid.getView().focusRow(this.lastActive);
24015                     if(last !== false){
24016                         this.last = last;
24017                     }
24018                 }else{
24019                     this.selectFirstRow();
24020                 }
24021                 this.fireEvent("afterselectionchange", this);
24022             },
24023             "down" : function(e){
24024                 if(!e.shiftKey){
24025                     this.selectNext(e.shiftKey);
24026                 }else if(this.last !== false && this.lastActive !== false){
24027                     var last = this.last;
24028                     this.selectRange(this.last,  this.lastActive+1);
24029                     this.grid.getView().focusRow(this.lastActive);
24030                     if(last !== false){
24031                         this.last = last;
24032                     }
24033                 }else{
24034                     this.selectFirstRow();
24035                 }
24036                 this.fireEvent("afterselectionchange", this);
24037             },
24038             scope: this
24039         });
24040         this.grid.store.on('load', function(){
24041             this.selections.clear();
24042         },this);
24043         /*
24044         var view = this.grid.view;
24045         view.on("refresh", this.onRefresh, this);
24046         view.on("rowupdated", this.onRowUpdated, this);
24047         view.on("rowremoved", this.onRemove, this);
24048         */
24049     },
24050
24051     // private
24052     onRefresh : function()
24053     {
24054         var ds = this.grid.store, i, v = this.grid.view;
24055         var s = this.selections;
24056         s.each(function(r){
24057             if((i = ds.indexOfId(r.id)) != -1){
24058                 v.onRowSelect(i);
24059             }else{
24060                 s.remove(r);
24061             }
24062         });
24063     },
24064
24065     // private
24066     onRemove : function(v, index, r){
24067         this.selections.remove(r);
24068     },
24069
24070     // private
24071     onRowUpdated : function(v, index, r){
24072         if(this.isSelected(r)){
24073             v.onRowSelect(index);
24074         }
24075     },
24076
24077     /**
24078      * Select records.
24079      * @param {Array} records The records to select
24080      * @param {Boolean} keepExisting (optional) True to keep existing selections
24081      */
24082     selectRecords : function(records, keepExisting)
24083     {
24084         if(!keepExisting){
24085             this.clearSelections();
24086         }
24087             var ds = this.grid.store;
24088         for(var i = 0, len = records.length; i < len; i++){
24089             this.selectRow(ds.indexOf(records[i]), true);
24090         }
24091     },
24092
24093     /**
24094      * Gets the number of selected rows.
24095      * @return {Number}
24096      */
24097     getCount : function(){
24098         return this.selections.length;
24099     },
24100
24101     /**
24102      * Selects the first row in the grid.
24103      */
24104     selectFirstRow : function(){
24105         this.selectRow(0);
24106     },
24107
24108     /**
24109      * Select the last row.
24110      * @param {Boolean} keepExisting (optional) True to keep existing selections
24111      */
24112     selectLastRow : function(keepExisting){
24113         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24114         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24115     },
24116
24117     /**
24118      * Selects the row immediately following the last selected row.
24119      * @param {Boolean} keepExisting (optional) True to keep existing selections
24120      */
24121     selectNext : function(keepExisting)
24122     {
24123             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24124             this.selectRow(this.last+1, keepExisting);
24125             this.grid.getView().focusRow(this.last);
24126         }
24127     },
24128
24129     /**
24130      * Selects the row that precedes the last selected row.
24131      * @param {Boolean} keepExisting (optional) True to keep existing selections
24132      */
24133     selectPrevious : function(keepExisting){
24134         if(this.last){
24135             this.selectRow(this.last-1, keepExisting);
24136             this.grid.getView().focusRow(this.last);
24137         }
24138     },
24139
24140     /**
24141      * Returns the selected records
24142      * @return {Array} Array of selected records
24143      */
24144     getSelections : function(){
24145         return [].concat(this.selections.items);
24146     },
24147
24148     /**
24149      * Returns the first selected record.
24150      * @return {Record}
24151      */
24152     getSelected : function(){
24153         return this.selections.itemAt(0);
24154     },
24155
24156
24157     /**
24158      * Clears all selections.
24159      */
24160     clearSelections : function(fast)
24161     {
24162         if(this.locked) {
24163             return;
24164         }
24165         if(fast !== true){
24166                 var ds = this.grid.store;
24167             var s = this.selections;
24168             s.each(function(r){
24169                 this.deselectRow(ds.indexOfId(r.id));
24170             }, this);
24171             s.clear();
24172         }else{
24173             this.selections.clear();
24174         }
24175         this.last = false;
24176     },
24177
24178
24179     /**
24180      * Selects all rows.
24181      */
24182     selectAll : function(){
24183         if(this.locked) {
24184             return;
24185         }
24186         this.selections.clear();
24187         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24188             this.selectRow(i, true);
24189         }
24190     },
24191
24192     /**
24193      * Returns True if there is a selection.
24194      * @return {Boolean}
24195      */
24196     hasSelection : function(){
24197         return this.selections.length > 0;
24198     },
24199
24200     /**
24201      * Returns True if the specified row is selected.
24202      * @param {Number/Record} record The record or index of the record to check
24203      * @return {Boolean}
24204      */
24205     isSelected : function(index){
24206             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24207         return (r && this.selections.key(r.id) ? true : false);
24208     },
24209
24210     /**
24211      * Returns True if the specified record id is selected.
24212      * @param {String} id The id of record to check
24213      * @return {Boolean}
24214      */
24215     isIdSelected : function(id){
24216         return (this.selections.key(id) ? true : false);
24217     },
24218
24219
24220     // private
24221     handleMouseDBClick : function(e, t){
24222         
24223     },
24224     // private
24225     handleMouseDown : function(e, t)
24226     {
24227             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24228         if(this.isLocked() || rowIndex < 0 ){
24229             return;
24230         };
24231         if(e.shiftKey && this.last !== false){
24232             var last = this.last;
24233             this.selectRange(last, rowIndex, e.ctrlKey);
24234             this.last = last; // reset the last
24235             t.focus();
24236     
24237         }else{
24238             var isSelected = this.isSelected(rowIndex);
24239             //Roo.log("select row:" + rowIndex);
24240             if(isSelected){
24241                 this.deselectRow(rowIndex);
24242             } else {
24243                         this.selectRow(rowIndex, true);
24244             }
24245     
24246             /*
24247                 if(e.button !== 0 && isSelected){
24248                 alert('rowIndex 2: ' + rowIndex);
24249                     view.focusRow(rowIndex);
24250                 }else if(e.ctrlKey && isSelected){
24251                     this.deselectRow(rowIndex);
24252                 }else if(!isSelected){
24253                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24254                     view.focusRow(rowIndex);
24255                 }
24256             */
24257         }
24258         this.fireEvent("afterselectionchange", this);
24259     },
24260     // private
24261     handleDragableRowClick :  function(grid, rowIndex, e) 
24262     {
24263         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24264             this.selectRow(rowIndex, false);
24265             grid.view.focusRow(rowIndex);
24266              this.fireEvent("afterselectionchange", this);
24267         }
24268     },
24269     
24270     /**
24271      * Selects multiple rows.
24272      * @param {Array} rows Array of the indexes of the row to select
24273      * @param {Boolean} keepExisting (optional) True to keep existing selections
24274      */
24275     selectRows : function(rows, keepExisting){
24276         if(!keepExisting){
24277             this.clearSelections();
24278         }
24279         for(var i = 0, len = rows.length; i < len; i++){
24280             this.selectRow(rows[i], true);
24281         }
24282     },
24283
24284     /**
24285      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24286      * @param {Number} startRow The index of the first row in the range
24287      * @param {Number} endRow The index of the last row in the range
24288      * @param {Boolean} keepExisting (optional) True to retain existing selections
24289      */
24290     selectRange : function(startRow, endRow, keepExisting){
24291         if(this.locked) {
24292             return;
24293         }
24294         if(!keepExisting){
24295             this.clearSelections();
24296         }
24297         if(startRow <= endRow){
24298             for(var i = startRow; i <= endRow; i++){
24299                 this.selectRow(i, true);
24300             }
24301         }else{
24302             for(var i = startRow; i >= endRow; i--){
24303                 this.selectRow(i, true);
24304             }
24305         }
24306     },
24307
24308     /**
24309      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24310      * @param {Number} startRow The index of the first row in the range
24311      * @param {Number} endRow The index of the last row in the range
24312      */
24313     deselectRange : function(startRow, endRow, preventViewNotify){
24314         if(this.locked) {
24315             return;
24316         }
24317         for(var i = startRow; i <= endRow; i++){
24318             this.deselectRow(i, preventViewNotify);
24319         }
24320     },
24321
24322     /**
24323      * Selects a row.
24324      * @param {Number} row The index of the row to select
24325      * @param {Boolean} keepExisting (optional) True to keep existing selections
24326      */
24327     selectRow : function(index, keepExisting, preventViewNotify)
24328     {
24329             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24330             return;
24331         }
24332         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24333             if(!keepExisting || this.singleSelect){
24334                 this.clearSelections();
24335             }
24336             
24337             var r = this.grid.store.getAt(index);
24338             //console.log('selectRow - record id :' + r.id);
24339             
24340             this.selections.add(r);
24341             this.last = this.lastActive = index;
24342             if(!preventViewNotify){
24343                 var proxy = new Roo.Element(
24344                                 this.grid.getRowDom(index)
24345                 );
24346                 proxy.addClass('bg-info info');
24347             }
24348             this.fireEvent("rowselect", this, index, r);
24349             this.fireEvent("selectionchange", this);
24350         }
24351     },
24352
24353     /**
24354      * Deselects a row.
24355      * @param {Number} row The index of the row to deselect
24356      */
24357     deselectRow : function(index, preventViewNotify)
24358     {
24359         if(this.locked) {
24360             return;
24361         }
24362         if(this.last == index){
24363             this.last = false;
24364         }
24365         if(this.lastActive == index){
24366             this.lastActive = false;
24367         }
24368         
24369         var r = this.grid.store.getAt(index);
24370         if (!r) {
24371             return;
24372         }
24373         
24374         this.selections.remove(r);
24375         //.console.log('deselectRow - record id :' + r.id);
24376         if(!preventViewNotify){
24377         
24378             var proxy = new Roo.Element(
24379                 this.grid.getRowDom(index)
24380             );
24381             proxy.removeClass('bg-info info');
24382         }
24383         this.fireEvent("rowdeselect", this, index);
24384         this.fireEvent("selectionchange", this);
24385     },
24386
24387     // private
24388     restoreLast : function(){
24389         if(this._last){
24390             this.last = this._last;
24391         }
24392     },
24393
24394     // private
24395     acceptsNav : function(row, col, cm){
24396         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24397     },
24398
24399     // private
24400     onEditorKey : function(field, e){
24401         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24402         if(k == e.TAB){
24403             e.stopEvent();
24404             ed.completeEdit();
24405             if(e.shiftKey){
24406                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24407             }else{
24408                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24409             }
24410         }else if(k == e.ENTER && !e.ctrlKey){
24411             e.stopEvent();
24412             ed.completeEdit();
24413             if(e.shiftKey){
24414                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24415             }else{
24416                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24417             }
24418         }else if(k == e.ESC){
24419             ed.cancelEdit();
24420         }
24421         if(newCell){
24422             g.startEditing(newCell[0], newCell[1]);
24423         }
24424     }
24425 });
24426 /*
24427  * Based on:
24428  * Ext JS Library 1.1.1
24429  * Copyright(c) 2006-2007, Ext JS, LLC.
24430  *
24431  * Originally Released Under LGPL - original licence link has changed is not relivant.
24432  *
24433  * Fork - LGPL
24434  * <script type="text/javascript">
24435  */
24436  
24437 /**
24438  * @class Roo.bootstrap.PagingToolbar
24439  * @extends Roo.bootstrap.NavSimplebar
24440  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24441  * @constructor
24442  * Create a new PagingToolbar
24443  * @param {Object} config The config object
24444  * @param {Roo.data.Store} store
24445  */
24446 Roo.bootstrap.PagingToolbar = function(config)
24447 {
24448     // old args format still supported... - xtype is prefered..
24449         // created from xtype...
24450     
24451     this.ds = config.dataSource;
24452     
24453     if (config.store && !this.ds) {
24454         this.store= Roo.factory(config.store, Roo.data);
24455         this.ds = this.store;
24456         this.ds.xmodule = this.xmodule || false;
24457     }
24458     
24459     this.toolbarItems = [];
24460     if (config.items) {
24461         this.toolbarItems = config.items;
24462     }
24463     
24464     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24465     
24466     this.cursor = 0;
24467     
24468     if (this.ds) { 
24469         this.bind(this.ds);
24470     }
24471     
24472     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24473     
24474 };
24475
24476 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24477     /**
24478      * @cfg {Roo.data.Store} dataSource
24479      * The underlying data store providing the paged data
24480      */
24481     /**
24482      * @cfg {String/HTMLElement/Element} container
24483      * container The id or element that will contain the toolbar
24484      */
24485     /**
24486      * @cfg {Boolean} displayInfo
24487      * True to display the displayMsg (defaults to false)
24488      */
24489     /**
24490      * @cfg {Number} pageSize
24491      * The number of records to display per page (defaults to 20)
24492      */
24493     pageSize: 20,
24494     /**
24495      * @cfg {String} displayMsg
24496      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24497      */
24498     displayMsg : 'Displaying {0} - {1} of {2}',
24499     /**
24500      * @cfg {String} emptyMsg
24501      * The message to display when no records are found (defaults to "No data to display")
24502      */
24503     emptyMsg : 'No data to display',
24504     /**
24505      * Customizable piece of the default paging text (defaults to "Page")
24506      * @type String
24507      */
24508     beforePageText : "Page",
24509     /**
24510      * Customizable piece of the default paging text (defaults to "of %0")
24511      * @type String
24512      */
24513     afterPageText : "of {0}",
24514     /**
24515      * Customizable piece of the default paging text (defaults to "First Page")
24516      * @type String
24517      */
24518     firstText : "First Page",
24519     /**
24520      * Customizable piece of the default paging text (defaults to "Previous Page")
24521      * @type String
24522      */
24523     prevText : "Previous Page",
24524     /**
24525      * Customizable piece of the default paging text (defaults to "Next Page")
24526      * @type String
24527      */
24528     nextText : "Next Page",
24529     /**
24530      * Customizable piece of the default paging text (defaults to "Last Page")
24531      * @type String
24532      */
24533     lastText : "Last Page",
24534     /**
24535      * Customizable piece of the default paging text (defaults to "Refresh")
24536      * @type String
24537      */
24538     refreshText : "Refresh",
24539
24540     buttons : false,
24541     // private
24542     onRender : function(ct, position) 
24543     {
24544         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24545         this.navgroup.parentId = this.id;
24546         this.navgroup.onRender(this.el, null);
24547         // add the buttons to the navgroup
24548         
24549         if(this.displayInfo){
24550             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24551             this.displayEl = this.el.select('.x-paging-info', true).first();
24552 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24553 //            this.displayEl = navel.el.select('span',true).first();
24554         }
24555         
24556         var _this = this;
24557         
24558         if(this.buttons){
24559             Roo.each(_this.buttons, function(e){ // this might need to use render????
24560                Roo.factory(e).render(_this.el);
24561             });
24562         }
24563             
24564         Roo.each(_this.toolbarItems, function(e) {
24565             _this.navgroup.addItem(e);
24566         });
24567         
24568         
24569         this.first = this.navgroup.addItem({
24570             tooltip: this.firstText,
24571             cls: "prev",
24572             icon : 'fa fa-backward',
24573             disabled: true,
24574             preventDefault: true,
24575             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24576         });
24577         
24578         this.prev =  this.navgroup.addItem({
24579             tooltip: this.prevText,
24580             cls: "prev",
24581             icon : 'fa fa-step-backward',
24582             disabled: true,
24583             preventDefault: true,
24584             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24585         });
24586     //this.addSeparator();
24587         
24588         
24589         var field = this.navgroup.addItem( {
24590             tagtype : 'span',
24591             cls : 'x-paging-position',
24592             
24593             html : this.beforePageText  +
24594                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24595                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24596          } ); //?? escaped?
24597         
24598         this.field = field.el.select('input', true).first();
24599         this.field.on("keydown", this.onPagingKeydown, this);
24600         this.field.on("focus", function(){this.dom.select();});
24601     
24602     
24603         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24604         //this.field.setHeight(18);
24605         //this.addSeparator();
24606         this.next = this.navgroup.addItem({
24607             tooltip: this.nextText,
24608             cls: "next",
24609             html : ' <i class="fa fa-step-forward">',
24610             disabled: true,
24611             preventDefault: true,
24612             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24613         });
24614         this.last = this.navgroup.addItem({
24615             tooltip: this.lastText,
24616             icon : 'fa fa-forward',
24617             cls: "next",
24618             disabled: true,
24619             preventDefault: true,
24620             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24621         });
24622     //this.addSeparator();
24623         this.loading = this.navgroup.addItem({
24624             tooltip: this.refreshText,
24625             icon: 'fa fa-refresh',
24626             preventDefault: true,
24627             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24628         });
24629         
24630     },
24631
24632     // private
24633     updateInfo : function(){
24634         if(this.displayEl){
24635             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24636             var msg = count == 0 ?
24637                 this.emptyMsg :
24638                 String.format(
24639                     this.displayMsg,
24640                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24641                 );
24642             this.displayEl.update(msg);
24643         }
24644     },
24645
24646     // private
24647     onLoad : function(ds, r, o)
24648     {
24649         this.cursor = o.params.start ? o.params.start : 0;
24650         
24651         var d = this.getPageData(),
24652             ap = d.activePage,
24653             ps = d.pages;
24654         
24655         
24656         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24657         this.field.dom.value = ap;
24658         this.first.setDisabled(ap == 1);
24659         this.prev.setDisabled(ap == 1);
24660         this.next.setDisabled(ap == ps);
24661         this.last.setDisabled(ap == ps);
24662         this.loading.enable();
24663         this.updateInfo();
24664     },
24665
24666     // private
24667     getPageData : function(){
24668         var total = this.ds.getTotalCount();
24669         return {
24670             total : total,
24671             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24672             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24673         };
24674     },
24675
24676     // private
24677     onLoadError : function(){
24678         this.loading.enable();
24679     },
24680
24681     // private
24682     onPagingKeydown : function(e){
24683         var k = e.getKey();
24684         var d = this.getPageData();
24685         if(k == e.RETURN){
24686             var v = this.field.dom.value, pageNum;
24687             if(!v || isNaN(pageNum = parseInt(v, 10))){
24688                 this.field.dom.value = d.activePage;
24689                 return;
24690             }
24691             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24692             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24693             e.stopEvent();
24694         }
24695         else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
24696         {
24697           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24698           this.field.dom.value = pageNum;
24699           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24700           e.stopEvent();
24701         }
24702         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24703         {
24704           var v = this.field.dom.value, pageNum; 
24705           var increment = (e.shiftKey) ? 10 : 1;
24706           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24707                 increment *= -1;
24708           }
24709           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24710             this.field.dom.value = d.activePage;
24711             return;
24712           }
24713           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24714           {
24715             this.field.dom.value = parseInt(v, 10) + increment;
24716             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24717             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24718           }
24719           e.stopEvent();
24720         }
24721     },
24722
24723     // private
24724     beforeLoad : function(){
24725         if(this.loading){
24726             this.loading.disable();
24727         }
24728     },
24729
24730     // private
24731     onClick : function(which){
24732         
24733         var ds = this.ds;
24734         if (!ds) {
24735             return;
24736         }
24737         
24738         switch(which){
24739             case "first":
24740                 ds.load({params:{start: 0, limit: this.pageSize}});
24741             break;
24742             case "prev":
24743                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24744             break;
24745             case "next":
24746                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24747             break;
24748             case "last":
24749                 var total = ds.getTotalCount();
24750                 var extra = total % this.pageSize;
24751                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24752                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24753             break;
24754             case "refresh":
24755                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24756             break;
24757         }
24758     },
24759
24760     /**
24761      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24762      * @param {Roo.data.Store} store The data store to unbind
24763      */
24764     unbind : function(ds){
24765         ds.un("beforeload", this.beforeLoad, this);
24766         ds.un("load", this.onLoad, this);
24767         ds.un("loadexception", this.onLoadError, this);
24768         ds.un("remove", this.updateInfo, this);
24769         ds.un("add", this.updateInfo, this);
24770         this.ds = undefined;
24771     },
24772
24773     /**
24774      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24775      * @param {Roo.data.Store} store The data store to bind
24776      */
24777     bind : function(ds){
24778         ds.on("beforeload", this.beforeLoad, this);
24779         ds.on("load", this.onLoad, this);
24780         ds.on("loadexception", this.onLoadError, this);
24781         ds.on("remove", this.updateInfo, this);
24782         ds.on("add", this.updateInfo, this);
24783         this.ds = ds;
24784     }
24785 });/*
24786  * - LGPL
24787  *
24788  * element
24789  * 
24790  */
24791
24792 /**
24793  * @class Roo.bootstrap.MessageBar
24794  * @extends Roo.bootstrap.Component
24795  * Bootstrap MessageBar class
24796  * @cfg {String} html contents of the MessageBar
24797  * @cfg {String} weight (info | success | warning | danger) default info
24798  * @cfg {String} beforeClass insert the bar before the given class
24799  * @cfg {Boolean} closable (true | false) default false
24800  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24801  * 
24802  * @constructor
24803  * Create a new Element
24804  * @param {Object} config The config object
24805  */
24806
24807 Roo.bootstrap.MessageBar = function(config){
24808     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24809 };
24810
24811 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24812     
24813     html: '',
24814     weight: 'info',
24815     closable: false,
24816     fixed: false,
24817     beforeClass: 'bootstrap-sticky-wrap',
24818     
24819     getAutoCreate : function(){
24820         
24821         var cfg = {
24822             tag: 'div',
24823             cls: 'alert alert-dismissable alert-' + this.weight,
24824             cn: [
24825                 {
24826                     tag: 'span',
24827                     cls: 'message',
24828                     html: this.html || ''
24829                 }
24830             ]
24831         };
24832         
24833         if(this.fixed){
24834             cfg.cls += ' alert-messages-fixed';
24835         }
24836         
24837         if(this.closable){
24838             cfg.cn.push({
24839                 tag: 'button',
24840                 cls: 'close',
24841                 html: 'x'
24842             });
24843         }
24844         
24845         return cfg;
24846     },
24847     
24848     onRender : function(ct, position)
24849     {
24850         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24851         
24852         if(!this.el){
24853             var cfg = Roo.apply({},  this.getAutoCreate());
24854             cfg.id = Roo.id();
24855             
24856             if (this.cls) {
24857                 cfg.cls += ' ' + this.cls;
24858             }
24859             if (this.style) {
24860                 cfg.style = this.style;
24861             }
24862             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24863             
24864             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24865         }
24866         
24867         this.el.select('>button.close').on('click', this.hide, this);
24868         
24869     },
24870     
24871     show : function()
24872     {
24873         if (!this.rendered) {
24874             this.render();
24875         }
24876         
24877         this.el.show();
24878         
24879         this.fireEvent('show', this);
24880         
24881     },
24882     
24883     hide : function()
24884     {
24885         if (!this.rendered) {
24886             this.render();
24887         }
24888         
24889         this.el.hide();
24890         
24891         this.fireEvent('hide', this);
24892     },
24893     
24894     update : function()
24895     {
24896 //        var e = this.el.dom.firstChild;
24897 //        
24898 //        if(this.closable){
24899 //            e = e.nextSibling;
24900 //        }
24901 //        
24902 //        e.data = this.html || '';
24903
24904         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24905     }
24906    
24907 });
24908
24909  
24910
24911      /*
24912  * - LGPL
24913  *
24914  * Graph
24915  * 
24916  */
24917
24918
24919 /**
24920  * @class Roo.bootstrap.Graph
24921  * @extends Roo.bootstrap.Component
24922  * Bootstrap Graph class
24923 > Prameters
24924  -sm {number} sm 4
24925  -md {number} md 5
24926  @cfg {String} graphtype  bar | vbar | pie
24927  @cfg {number} g_x coodinator | centre x (pie)
24928  @cfg {number} g_y coodinator | centre y (pie)
24929  @cfg {number} g_r radius (pie)
24930  @cfg {number} g_height height of the chart (respected by all elements in the set)
24931  @cfg {number} g_width width of the chart (respected by all elements in the set)
24932  @cfg {Object} title The title of the chart
24933     
24934  -{Array}  values
24935  -opts (object) options for the chart 
24936      o {
24937      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24938      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24939      o vgutter (number)
24940      o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
24941      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24942      o to
24943      o stretch (boolean)
24944      o }
24945  -opts (object) options for the pie
24946      o{
24947      o cut
24948      o startAngle (number)
24949      o endAngle (number)
24950      } 
24951  *
24952  * @constructor
24953  * Create a new Input
24954  * @param {Object} config The config object
24955  */
24956
24957 Roo.bootstrap.Graph = function(config){
24958     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24959     
24960     this.addEvents({
24961         // img events
24962         /**
24963          * @event click
24964          * The img click event for the img.
24965          * @param {Roo.EventObject} e
24966          */
24967         "click" : true
24968     });
24969 };
24970
24971 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24972     
24973     sm: 4,
24974     md: 5,
24975     graphtype: 'bar',
24976     g_height: 250,
24977     g_width: 400,
24978     g_x: 50,
24979     g_y: 50,
24980     g_r: 30,
24981     opts:{
24982         //g_colors: this.colors,
24983         g_type: 'soft',
24984         g_gutter: '20%'
24985
24986     },
24987     title : false,
24988
24989     getAutoCreate : function(){
24990         
24991         var cfg = {
24992             tag: 'div',
24993             html : null
24994         };
24995         
24996         
24997         return  cfg;
24998     },
24999
25000     onRender : function(ct,position){
25001         
25002         
25003         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25004         
25005         if (typeof(Raphael) == 'undefined') {
25006             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25007             return;
25008         }
25009         
25010         this.raphael = Raphael(this.el.dom);
25011         
25012                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25013                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25014                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25015                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25016                 /*
25017                 r.text(160, 10, "Single Series Chart").attr(txtattr);
25018                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25019                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25020                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25021                 
25022                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25023                 r.barchart(330, 10, 300, 220, data1);
25024                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25025                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25026                 */
25027                 
25028                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25029                 // r.barchart(30, 30, 560, 250,  xdata, {
25030                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25031                 //     axis : "0 0 1 1",
25032                 //     axisxlabels :  xdata
25033                 //     //yvalues : cols,
25034                    
25035                 // });
25036 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25037 //        
25038 //        this.load(null,xdata,{
25039 //                axis : "0 0 1 1",
25040 //                axisxlabels :  xdata
25041 //                });
25042
25043     },
25044
25045     load : function(graphtype,xdata,opts)
25046     {
25047         this.raphael.clear();
25048         if(!graphtype) {
25049             graphtype = this.graphtype;
25050         }
25051         if(!opts){
25052             opts = this.opts;
25053         }
25054         var r = this.raphael,
25055             fin = function () {
25056                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25057             },
25058             fout = function () {
25059                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25060             },
25061             pfin = function() {
25062                 this.sector.stop();
25063                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25064
25065                 if (this.label) {
25066                     this.label[0].stop();
25067                     this.label[0].attr({ r: 7.5 });
25068                     this.label[1].attr({ "font-weight": 800 });
25069                 }
25070             },
25071             pfout = function() {
25072                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25073
25074                 if (this.label) {
25075                     this.label[0].animate({ r: 5 }, 500, "bounce");
25076                     this.label[1].attr({ "font-weight": 400 });
25077                 }
25078             };
25079
25080         switch(graphtype){
25081             case 'bar':
25082                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25083                 break;
25084             case 'hbar':
25085                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25086                 break;
25087             case 'pie':
25088 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25089 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25090 //            
25091                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25092                 
25093                 break;
25094
25095         }
25096         
25097         if(this.title){
25098             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25099         }
25100         
25101     },
25102     
25103     setTitle: function(o)
25104     {
25105         this.title = o;
25106     },
25107     
25108     initEvents: function() {
25109         
25110         if(!this.href){
25111             this.el.on('click', this.onClick, this);
25112         }
25113     },
25114     
25115     onClick : function(e)
25116     {
25117         Roo.log('img onclick');
25118         this.fireEvent('click', this, e);
25119     }
25120    
25121 });
25122
25123  
25124 /*
25125  * - LGPL
25126  *
25127  * numberBox
25128  * 
25129  */
25130 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25131
25132 /**
25133  * @class Roo.bootstrap.dash.NumberBox
25134  * @extends Roo.bootstrap.Component
25135  * Bootstrap NumberBox class
25136  * @cfg {String} headline Box headline
25137  * @cfg {String} content Box content
25138  * @cfg {String} icon Box icon
25139  * @cfg {String} footer Footer text
25140  * @cfg {String} fhref Footer href
25141  * 
25142  * @constructor
25143  * Create a new NumberBox
25144  * @param {Object} config The config object
25145  */
25146
25147
25148 Roo.bootstrap.dash.NumberBox = function(config){
25149     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25150     
25151 };
25152
25153 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25154     
25155     headline : '',
25156     content : '',
25157     icon : '',
25158     footer : '',
25159     fhref : '',
25160     ficon : '',
25161     
25162     getAutoCreate : function(){
25163         
25164         var cfg = {
25165             tag : 'div',
25166             cls : 'small-box ',
25167             cn : [
25168                 {
25169                     tag : 'div',
25170                     cls : 'inner',
25171                     cn :[
25172                         {
25173                             tag : 'h3',
25174                             cls : 'roo-headline',
25175                             html : this.headline
25176                         },
25177                         {
25178                             tag : 'p',
25179                             cls : 'roo-content',
25180                             html : this.content
25181                         }
25182                     ]
25183                 }
25184             ]
25185         };
25186         
25187         if(this.icon){
25188             cfg.cn.push({
25189                 tag : 'div',
25190                 cls : 'icon',
25191                 cn :[
25192                     {
25193                         tag : 'i',
25194                         cls : 'ion ' + this.icon
25195                     }
25196                 ]
25197             });
25198         }
25199         
25200         if(this.footer){
25201             var footer = {
25202                 tag : 'a',
25203                 cls : 'small-box-footer',
25204                 href : this.fhref || '#',
25205                 html : this.footer
25206             };
25207             
25208             cfg.cn.push(footer);
25209             
25210         }
25211         
25212         return  cfg;
25213     },
25214
25215     onRender : function(ct,position){
25216         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25217
25218
25219        
25220                 
25221     },
25222
25223     setHeadline: function (value)
25224     {
25225         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25226     },
25227     
25228     setFooter: function (value, href)
25229     {
25230         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25231         
25232         if(href){
25233             this.el.select('a.small-box-footer',true).first().attr('href', href);
25234         }
25235         
25236     },
25237
25238     setContent: function (value)
25239     {
25240         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25241     },
25242
25243     initEvents: function() 
25244     {   
25245         
25246     }
25247     
25248 });
25249
25250  
25251 /*
25252  * - LGPL
25253  *
25254  * TabBox
25255  * 
25256  */
25257 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25258
25259 /**
25260  * @class Roo.bootstrap.dash.TabBox
25261  * @extends Roo.bootstrap.Component
25262  * Bootstrap TabBox class
25263  * @cfg {String} title Title of the TabBox
25264  * @cfg {String} icon Icon of the TabBox
25265  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25266  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25267  * 
25268  * @constructor
25269  * Create a new TabBox
25270  * @param {Object} config The config object
25271  */
25272
25273
25274 Roo.bootstrap.dash.TabBox = function(config){
25275     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25276     this.addEvents({
25277         // raw events
25278         /**
25279          * @event addpane
25280          * When a pane is added
25281          * @param {Roo.bootstrap.dash.TabPane} pane
25282          */
25283         "addpane" : true,
25284         /**
25285          * @event activatepane
25286          * When a pane is activated
25287          * @param {Roo.bootstrap.dash.TabPane} pane
25288          */
25289         "activatepane" : true
25290         
25291          
25292     });
25293     
25294     this.panes = [];
25295 };
25296
25297 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25298
25299     title : '',
25300     icon : false,
25301     showtabs : true,
25302     tabScrollable : false,
25303     
25304     getChildContainer : function()
25305     {
25306         return this.el.select('.tab-content', true).first();
25307     },
25308     
25309     getAutoCreate : function(){
25310         
25311         var header = {
25312             tag: 'li',
25313             cls: 'pull-left header',
25314             html: this.title,
25315             cn : []
25316         };
25317         
25318         if(this.icon){
25319             header.cn.push({
25320                 tag: 'i',
25321                 cls: 'fa ' + this.icon
25322             });
25323         }
25324         
25325         var h = {
25326             tag: 'ul',
25327             cls: 'nav nav-tabs pull-right',
25328             cn: [
25329                 header
25330             ]
25331         };
25332         
25333         if(this.tabScrollable){
25334             h = {
25335                 tag: 'div',
25336                 cls: 'tab-header',
25337                 cn: [
25338                     {
25339                         tag: 'ul',
25340                         cls: 'nav nav-tabs pull-right',
25341                         cn: [
25342                             header
25343                         ]
25344                     }
25345                 ]
25346             };
25347         }
25348         
25349         var cfg = {
25350             tag: 'div',
25351             cls: 'nav-tabs-custom',
25352             cn: [
25353                 h,
25354                 {
25355                     tag: 'div',
25356                     cls: 'tab-content no-padding',
25357                     cn: []
25358                 }
25359             ]
25360         };
25361
25362         return  cfg;
25363     },
25364     initEvents : function()
25365     {
25366         //Roo.log('add add pane handler');
25367         this.on('addpane', this.onAddPane, this);
25368     },
25369      /**
25370      * Updates the box title
25371      * @param {String} html to set the title to.
25372      */
25373     setTitle : function(value)
25374     {
25375         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25376     },
25377     onAddPane : function(pane)
25378     {
25379         this.panes.push(pane);
25380         //Roo.log('addpane');
25381         //Roo.log(pane);
25382         // tabs are rendere left to right..
25383         if(!this.showtabs){
25384             return;
25385         }
25386         
25387         var ctr = this.el.select('.nav-tabs', true).first();
25388          
25389          
25390         var existing = ctr.select('.nav-tab',true);
25391         var qty = existing.getCount();;
25392         
25393         
25394         var tab = ctr.createChild({
25395             tag : 'li',
25396             cls : 'nav-tab' + (qty ? '' : ' active'),
25397             cn : [
25398                 {
25399                     tag : 'a',
25400                     href:'#',
25401                     html : pane.title
25402                 }
25403             ]
25404         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25405         pane.tab = tab;
25406         
25407         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25408         if (!qty) {
25409             pane.el.addClass('active');
25410         }
25411         
25412                 
25413     },
25414     onTabClick : function(ev,un,ob,pane)
25415     {
25416         //Roo.log('tab - prev default');
25417         ev.preventDefault();
25418         
25419         
25420         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25421         pane.tab.addClass('active');
25422         //Roo.log(pane.title);
25423         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25424         // technically we should have a deactivate event.. but maybe add later.
25425         // and it should not de-activate the selected tab...
25426         this.fireEvent('activatepane', pane);
25427         pane.el.addClass('active');
25428         pane.fireEvent('activate');
25429         
25430         
25431     },
25432     
25433     getActivePane : function()
25434     {
25435         var r = false;
25436         Roo.each(this.panes, function(p) {
25437             if(p.el.hasClass('active')){
25438                 r = p;
25439                 return false;
25440             }
25441             
25442             return;
25443         });
25444         
25445         return r;
25446     }
25447     
25448     
25449 });
25450
25451  
25452 /*
25453  * - LGPL
25454  *
25455  * Tab pane
25456  * 
25457  */
25458 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25459 /**
25460  * @class Roo.bootstrap.TabPane
25461  * @extends Roo.bootstrap.Component
25462  * Bootstrap TabPane class
25463  * @cfg {Boolean} active (false | true) Default false
25464  * @cfg {String} title title of panel
25465
25466  * 
25467  * @constructor
25468  * Create a new TabPane
25469  * @param {Object} config The config object
25470  */
25471
25472 Roo.bootstrap.dash.TabPane = function(config){
25473     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25474     
25475     this.addEvents({
25476         // raw events
25477         /**
25478          * @event activate
25479          * When a pane is activated
25480          * @param {Roo.bootstrap.dash.TabPane} pane
25481          */
25482         "activate" : true
25483          
25484     });
25485 };
25486
25487 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25488     
25489     active : false,
25490     title : '',
25491     
25492     // the tabBox that this is attached to.
25493     tab : false,
25494      
25495     getAutoCreate : function() 
25496     {
25497         var cfg = {
25498             tag: 'div',
25499             cls: 'tab-pane'
25500         };
25501         
25502         if(this.active){
25503             cfg.cls += ' active';
25504         }
25505         
25506         return cfg;
25507     },
25508     initEvents  : function()
25509     {
25510         //Roo.log('trigger add pane handler');
25511         this.parent().fireEvent('addpane', this)
25512     },
25513     
25514      /**
25515      * Updates the tab title 
25516      * @param {String} html to set the title to.
25517      */
25518     setTitle: function(str)
25519     {
25520         if (!this.tab) {
25521             return;
25522         }
25523         this.title = str;
25524         this.tab.select('a', true).first().dom.innerHTML = str;
25525         
25526     }
25527     
25528     
25529     
25530 });
25531
25532  
25533
25534
25535  /*
25536  * - LGPL
25537  *
25538  * menu
25539  * 
25540  */
25541 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25542
25543 /**
25544  * @class Roo.bootstrap.menu.Menu
25545  * @extends Roo.bootstrap.Component
25546  * Bootstrap Menu class - container for Menu
25547  * @cfg {String} html Text of the menu
25548  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25549  * @cfg {String} icon Font awesome icon
25550  * @cfg {String} pos Menu align to (top | bottom) default bottom
25551  * 
25552  * 
25553  * @constructor
25554  * Create a new Menu
25555  * @param {Object} config The config object
25556  */
25557
25558
25559 Roo.bootstrap.menu.Menu = function(config){
25560     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25561     
25562     this.addEvents({
25563         /**
25564          * @event beforeshow
25565          * Fires before this menu is displayed
25566          * @param {Roo.bootstrap.menu.Menu} this
25567          */
25568         beforeshow : true,
25569         /**
25570          * @event beforehide
25571          * Fires before this menu is hidden
25572          * @param {Roo.bootstrap.menu.Menu} this
25573          */
25574         beforehide : true,
25575         /**
25576          * @event show
25577          * Fires after this menu is displayed
25578          * @param {Roo.bootstrap.menu.Menu} this
25579          */
25580         show : true,
25581         /**
25582          * @event hide
25583          * Fires after this menu is hidden
25584          * @param {Roo.bootstrap.menu.Menu} this
25585          */
25586         hide : true,
25587         /**
25588          * @event click
25589          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25590          * @param {Roo.bootstrap.menu.Menu} this
25591          * @param {Roo.EventObject} e
25592          */
25593         click : true
25594     });
25595     
25596 };
25597
25598 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25599     
25600     submenu : false,
25601     html : '',
25602     weight : 'default',
25603     icon : false,
25604     pos : 'bottom',
25605     
25606     
25607     getChildContainer : function() {
25608         if(this.isSubMenu){
25609             return this.el;
25610         }
25611         
25612         return this.el.select('ul.dropdown-menu', true).first();  
25613     },
25614     
25615     getAutoCreate : function()
25616     {
25617         var text = [
25618             {
25619                 tag : 'span',
25620                 cls : 'roo-menu-text',
25621                 html : this.html
25622             }
25623         ];
25624         
25625         if(this.icon){
25626             text.unshift({
25627                 tag : 'i',
25628                 cls : 'fa ' + this.icon
25629             })
25630         }
25631         
25632         
25633         var cfg = {
25634             tag : 'div',
25635             cls : 'btn-group',
25636             cn : [
25637                 {
25638                     tag : 'button',
25639                     cls : 'dropdown-button btn btn-' + this.weight,
25640                     cn : text
25641                 },
25642                 {
25643                     tag : 'button',
25644                     cls : 'dropdown-toggle btn btn-' + this.weight,
25645                     cn : [
25646                         {
25647                             tag : 'span',
25648                             cls : 'caret'
25649                         }
25650                     ]
25651                 },
25652                 {
25653                     tag : 'ul',
25654                     cls : 'dropdown-menu'
25655                 }
25656             ]
25657             
25658         };
25659         
25660         if(this.pos == 'top'){
25661             cfg.cls += ' dropup';
25662         }
25663         
25664         if(this.isSubMenu){
25665             cfg = {
25666                 tag : 'ul',
25667                 cls : 'dropdown-menu'
25668             }
25669         }
25670         
25671         return cfg;
25672     },
25673     
25674     onRender : function(ct, position)
25675     {
25676         this.isSubMenu = ct.hasClass('dropdown-submenu');
25677         
25678         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25679     },
25680     
25681     initEvents : function() 
25682     {
25683         if(this.isSubMenu){
25684             return;
25685         }
25686         
25687         this.hidden = true;
25688         
25689         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25690         this.triggerEl.on('click', this.onTriggerPress, this);
25691         
25692         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25693         this.buttonEl.on('click', this.onClick, this);
25694         
25695     },
25696     
25697     list : function()
25698     {
25699         if(this.isSubMenu){
25700             return this.el;
25701         }
25702         
25703         return this.el.select('ul.dropdown-menu', true).first();
25704     },
25705     
25706     onClick : function(e)
25707     {
25708         this.fireEvent("click", this, e);
25709     },
25710     
25711     onTriggerPress  : function(e)
25712     {   
25713         if (this.isVisible()) {
25714             this.hide();
25715         } else {
25716             this.show();
25717         }
25718     },
25719     
25720     isVisible : function(){
25721         return !this.hidden;
25722     },
25723     
25724     show : function()
25725     {
25726         this.fireEvent("beforeshow", this);
25727         
25728         this.hidden = false;
25729         this.el.addClass('open');
25730         
25731         Roo.get(document).on("mouseup", this.onMouseUp, this);
25732         
25733         this.fireEvent("show", this);
25734         
25735         
25736     },
25737     
25738     hide : function()
25739     {
25740         this.fireEvent("beforehide", this);
25741         
25742         this.hidden = true;
25743         this.el.removeClass('open');
25744         
25745         Roo.get(document).un("mouseup", this.onMouseUp);
25746         
25747         this.fireEvent("hide", this);
25748     },
25749     
25750     onMouseUp : function()
25751     {
25752         this.hide();
25753     }
25754     
25755 });
25756
25757  
25758  /*
25759  * - LGPL
25760  *
25761  * menu item
25762  * 
25763  */
25764 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25765
25766 /**
25767  * @class Roo.bootstrap.menu.Item
25768  * @extends Roo.bootstrap.Component
25769  * Bootstrap MenuItem class
25770  * @cfg {Boolean} submenu (true | false) default false
25771  * @cfg {String} html text of the item
25772  * @cfg {String} href the link
25773  * @cfg {Boolean} disable (true | false) default false
25774  * @cfg {Boolean} preventDefault (true | false) default true
25775  * @cfg {String} icon Font awesome icon
25776  * @cfg {String} pos Submenu align to (left | right) default right 
25777  * 
25778  * 
25779  * @constructor
25780  * Create a new Item
25781  * @param {Object} config The config object
25782  */
25783
25784
25785 Roo.bootstrap.menu.Item = function(config){
25786     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25787     this.addEvents({
25788         /**
25789          * @event mouseover
25790          * Fires when the mouse is hovering over this menu
25791          * @param {Roo.bootstrap.menu.Item} this
25792          * @param {Roo.EventObject} e
25793          */
25794         mouseover : true,
25795         /**
25796          * @event mouseout
25797          * Fires when the mouse exits this menu
25798          * @param {Roo.bootstrap.menu.Item} this
25799          * @param {Roo.EventObject} e
25800          */
25801         mouseout : true,
25802         // raw events
25803         /**
25804          * @event click
25805          * The raw click event for the entire grid.
25806          * @param {Roo.EventObject} e
25807          */
25808         click : true
25809     });
25810 };
25811
25812 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25813     
25814     submenu : false,
25815     href : '',
25816     html : '',
25817     preventDefault: true,
25818     disable : false,
25819     icon : false,
25820     pos : 'right',
25821     
25822     getAutoCreate : function()
25823     {
25824         var text = [
25825             {
25826                 tag : 'span',
25827                 cls : 'roo-menu-item-text',
25828                 html : this.html
25829             }
25830         ];
25831         
25832         if(this.icon){
25833             text.unshift({
25834                 tag : 'i',
25835                 cls : 'fa ' + this.icon
25836             })
25837         }
25838         
25839         var cfg = {
25840             tag : 'li',
25841             cn : [
25842                 {
25843                     tag : 'a',
25844                     href : this.href || '#',
25845                     cn : text
25846                 }
25847             ]
25848         };
25849         
25850         if(this.disable){
25851             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25852         }
25853         
25854         if(this.submenu){
25855             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25856             
25857             if(this.pos == 'left'){
25858                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25859             }
25860         }
25861         
25862         return cfg;
25863     },
25864     
25865     initEvents : function() 
25866     {
25867         this.el.on('mouseover', this.onMouseOver, this);
25868         this.el.on('mouseout', this.onMouseOut, this);
25869         
25870         this.el.select('a', true).first().on('click', this.onClick, this);
25871         
25872     },
25873     
25874     onClick : function(e)
25875     {
25876         if(this.preventDefault){
25877             e.preventDefault();
25878         }
25879         
25880         this.fireEvent("click", this, e);
25881     },
25882     
25883     onMouseOver : function(e)
25884     {
25885         if(this.submenu && this.pos == 'left'){
25886             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25887         }
25888         
25889         this.fireEvent("mouseover", this, e);
25890     },
25891     
25892     onMouseOut : function(e)
25893     {
25894         this.fireEvent("mouseout", this, e);
25895     }
25896 });
25897
25898  
25899
25900  /*
25901  * - LGPL
25902  *
25903  * menu separator
25904  * 
25905  */
25906 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25907
25908 /**
25909  * @class Roo.bootstrap.menu.Separator
25910  * @extends Roo.bootstrap.Component
25911  * Bootstrap Separator class
25912  * 
25913  * @constructor
25914  * Create a new Separator
25915  * @param {Object} config The config object
25916  */
25917
25918
25919 Roo.bootstrap.menu.Separator = function(config){
25920     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25921 };
25922
25923 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25924     
25925     getAutoCreate : function(){
25926         var cfg = {
25927             tag : 'li',
25928             cls: 'divider'
25929         };
25930         
25931         return cfg;
25932     }
25933    
25934 });
25935
25936  
25937
25938  /*
25939  * - LGPL
25940  *
25941  * Tooltip
25942  * 
25943  */
25944
25945 /**
25946  * @class Roo.bootstrap.Tooltip
25947  * Bootstrap Tooltip class
25948  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25949  * to determine which dom element triggers the tooltip.
25950  * 
25951  * It needs to add support for additional attributes like tooltip-position
25952  * 
25953  * @constructor
25954  * Create a new Toolti
25955  * @param {Object} config The config object
25956  */
25957
25958 Roo.bootstrap.Tooltip = function(config){
25959     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25960     
25961     this.alignment = Roo.bootstrap.Tooltip.alignment;
25962     
25963     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25964         this.alignment = config.alignment;
25965     }
25966     
25967 };
25968
25969 Roo.apply(Roo.bootstrap.Tooltip, {
25970     /**
25971      * @function init initialize tooltip monitoring.
25972      * @static
25973      */
25974     currentEl : false,
25975     currentTip : false,
25976     currentRegion : false,
25977     
25978     //  init : delay?
25979     
25980     init : function()
25981     {
25982         Roo.get(document).on('mouseover', this.enter ,this);
25983         Roo.get(document).on('mouseout', this.leave, this);
25984          
25985         
25986         this.currentTip = new Roo.bootstrap.Tooltip();
25987     },
25988     
25989     enter : function(ev)
25990     {
25991         var dom = ev.getTarget();
25992         
25993         //Roo.log(['enter',dom]);
25994         var el = Roo.fly(dom);
25995         if (this.currentEl) {
25996             //Roo.log(dom);
25997             //Roo.log(this.currentEl);
25998             //Roo.log(this.currentEl.contains(dom));
25999             if (this.currentEl == el) {
26000                 return;
26001             }
26002             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26003                 return;
26004             }
26005
26006         }
26007         
26008         if (this.currentTip.el) {
26009             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26010         }    
26011         //Roo.log(ev);
26012         
26013         if(!el || el.dom == document){
26014             return;
26015         }
26016         
26017         var bindEl = el;
26018         
26019         // you can not look for children, as if el is the body.. then everythign is the child..
26020         if (!el.attr('tooltip')) { //
26021             if (!el.select("[tooltip]").elements.length) {
26022                 return;
26023             }
26024             // is the mouse over this child...?
26025             bindEl = el.select("[tooltip]").first();
26026             var xy = ev.getXY();
26027             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26028                 //Roo.log("not in region.");
26029                 return;
26030             }
26031             //Roo.log("child element over..");
26032             
26033         }
26034         this.currentEl = bindEl;
26035         this.currentTip.bind(bindEl);
26036         this.currentRegion = Roo.lib.Region.getRegion(dom);
26037         this.currentTip.enter();
26038         
26039     },
26040     leave : function(ev)
26041     {
26042         var dom = ev.getTarget();
26043         //Roo.log(['leave',dom]);
26044         if (!this.currentEl) {
26045             return;
26046         }
26047         
26048         
26049         if (dom != this.currentEl.dom) {
26050             return;
26051         }
26052         var xy = ev.getXY();
26053         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26054             return;
26055         }
26056         // only activate leave if mouse cursor is outside... bounding box..
26057         
26058         
26059         
26060         
26061         if (this.currentTip) {
26062             this.currentTip.leave();
26063         }
26064         //Roo.log('clear currentEl');
26065         this.currentEl = false;
26066         
26067         
26068     },
26069     alignment : {
26070         'left' : ['r-l', [-2,0], 'right'],
26071         'right' : ['l-r', [2,0], 'left'],
26072         'bottom' : ['t-b', [0,2], 'top'],
26073         'top' : [ 'b-t', [0,-2], 'bottom']
26074     }
26075     
26076 });
26077
26078
26079 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26080     
26081     
26082     bindEl : false,
26083     
26084     delay : null, // can be { show : 300 , hide: 500}
26085     
26086     timeout : null,
26087     
26088     hoverState : null, //???
26089     
26090     placement : 'bottom', 
26091     
26092     alignment : false,
26093     
26094     getAutoCreate : function(){
26095     
26096         var cfg = {
26097            cls : 'tooltip',
26098            role : 'tooltip',
26099            cn : [
26100                 {
26101                     cls : 'tooltip-arrow'
26102                 },
26103                 {
26104                     cls : 'tooltip-inner'
26105                 }
26106            ]
26107         };
26108         
26109         return cfg;
26110     },
26111     bind : function(el)
26112     {
26113         this.bindEl = el;
26114     },
26115       
26116     
26117     enter : function () {
26118        
26119         if (this.timeout != null) {
26120             clearTimeout(this.timeout);
26121         }
26122         
26123         this.hoverState = 'in';
26124          //Roo.log("enter - show");
26125         if (!this.delay || !this.delay.show) {
26126             this.show();
26127             return;
26128         }
26129         var _t = this;
26130         this.timeout = setTimeout(function () {
26131             if (_t.hoverState == 'in') {
26132                 _t.show();
26133             }
26134         }, this.delay.show);
26135     },
26136     leave : function()
26137     {
26138         clearTimeout(this.timeout);
26139     
26140         this.hoverState = 'out';
26141          if (!this.delay || !this.delay.hide) {
26142             this.hide();
26143             return;
26144         }
26145        
26146         var _t = this;
26147         this.timeout = setTimeout(function () {
26148             //Roo.log("leave - timeout");
26149             
26150             if (_t.hoverState == 'out') {
26151                 _t.hide();
26152                 Roo.bootstrap.Tooltip.currentEl = false;
26153             }
26154         }, delay);
26155     },
26156     
26157     show : function (msg)
26158     {
26159         if (!this.el) {
26160             this.render(document.body);
26161         }
26162         // set content.
26163         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26164         
26165         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26166         
26167         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26168         
26169         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26170         
26171         var placement = typeof this.placement == 'function' ?
26172             this.placement.call(this, this.el, on_el) :
26173             this.placement;
26174             
26175         var autoToken = /\s?auto?\s?/i;
26176         var autoPlace = autoToken.test(placement);
26177         if (autoPlace) {
26178             placement = placement.replace(autoToken, '') || 'top';
26179         }
26180         
26181         //this.el.detach()
26182         //this.el.setXY([0,0]);
26183         this.el.show();
26184         //this.el.dom.style.display='block';
26185         
26186         //this.el.appendTo(on_el);
26187         
26188         var p = this.getPosition();
26189         var box = this.el.getBox();
26190         
26191         if (autoPlace) {
26192             // fixme..
26193         }
26194         
26195         var align = this.alignment[placement];
26196         
26197         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26198         
26199         if(placement == 'top' || placement == 'bottom'){
26200             if(xy[0] < 0){
26201                 placement = 'right';
26202             }
26203             
26204             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26205                 placement = 'left';
26206             }
26207             
26208             var scroll = Roo.select('body', true).first().getScroll();
26209             
26210             Roo.log(this.el.getHeight());
26211             
26212             if(xy[1] + this.el.getHeight() >= Roo.lib.Dom.getViewHeight() + scroll.top){
26213                 placement = 'top';
26214             }
26215             
26216         }
26217         
26218         this.el.alignTo(this.bindEl, align[0],align[1]);
26219         //var arrow = this.el.select('.arrow',true).first();
26220         //arrow.set(align[2], 
26221         
26222         this.el.addClass(placement);
26223         
26224         this.el.addClass('in fade');
26225         
26226         this.hoverState = null;
26227         
26228         if (this.el.hasClass('fade')) {
26229             // fade it?
26230         }
26231         
26232     },
26233     hide : function()
26234     {
26235          
26236         if (!this.el) {
26237             return;
26238         }
26239         //this.el.setXY([0,0]);
26240         this.el.removeClass('in');
26241         //this.el.hide();
26242         
26243     }
26244     
26245 });
26246  
26247
26248  /*
26249  * - LGPL
26250  *
26251  * Location Picker
26252  * 
26253  */
26254
26255 /**
26256  * @class Roo.bootstrap.LocationPicker
26257  * @extends Roo.bootstrap.Component
26258  * Bootstrap LocationPicker class
26259  * @cfg {Number} latitude Position when init default 0
26260  * @cfg {Number} longitude Position when init default 0
26261  * @cfg {Number} zoom default 15
26262  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26263  * @cfg {Boolean} mapTypeControl default false
26264  * @cfg {Boolean} disableDoubleClickZoom default false
26265  * @cfg {Boolean} scrollwheel default true
26266  * @cfg {Boolean} streetViewControl default false
26267  * @cfg {Number} radius default 0
26268  * @cfg {String} locationName
26269  * @cfg {Boolean} draggable default true
26270  * @cfg {Boolean} enableAutocomplete default false
26271  * @cfg {Boolean} enableReverseGeocode default true
26272  * @cfg {String} markerTitle
26273  * 
26274  * @constructor
26275  * Create a new LocationPicker
26276  * @param {Object} config The config object
26277  */
26278
26279
26280 Roo.bootstrap.LocationPicker = function(config){
26281     
26282     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26283     
26284     this.addEvents({
26285         /**
26286          * @event initial
26287          * Fires when the picker initialized.
26288          * @param {Roo.bootstrap.LocationPicker} this
26289          * @param {Google Location} location
26290          */
26291         initial : true,
26292         /**
26293          * @event positionchanged
26294          * Fires when the picker position changed.
26295          * @param {Roo.bootstrap.LocationPicker} this
26296          * @param {Google Location} location
26297          */
26298         positionchanged : true,
26299         /**
26300          * @event resize
26301          * Fires when the map resize.
26302          * @param {Roo.bootstrap.LocationPicker} this
26303          */
26304         resize : true,
26305         /**
26306          * @event show
26307          * Fires when the map show.
26308          * @param {Roo.bootstrap.LocationPicker} this
26309          */
26310         show : true,
26311         /**
26312          * @event hide
26313          * Fires when the map hide.
26314          * @param {Roo.bootstrap.LocationPicker} this
26315          */
26316         hide : true,
26317         /**
26318          * @event mapClick
26319          * Fires when click the map.
26320          * @param {Roo.bootstrap.LocationPicker} this
26321          * @param {Map event} e
26322          */
26323         mapClick : true,
26324         /**
26325          * @event mapRightClick
26326          * Fires when right click the map.
26327          * @param {Roo.bootstrap.LocationPicker} this
26328          * @param {Map event} e
26329          */
26330         mapRightClick : true,
26331         /**
26332          * @event markerClick
26333          * Fires when click the marker.
26334          * @param {Roo.bootstrap.LocationPicker} this
26335          * @param {Map event} e
26336          */
26337         markerClick : true,
26338         /**
26339          * @event markerRightClick
26340          * Fires when right click the marker.
26341          * @param {Roo.bootstrap.LocationPicker} this
26342          * @param {Map event} e
26343          */
26344         markerRightClick : true,
26345         /**
26346          * @event OverlayViewDraw
26347          * Fires when OverlayView Draw
26348          * @param {Roo.bootstrap.LocationPicker} this
26349          */
26350         OverlayViewDraw : true,
26351         /**
26352          * @event OverlayViewOnAdd
26353          * Fires when OverlayView Draw
26354          * @param {Roo.bootstrap.LocationPicker} this
26355          */
26356         OverlayViewOnAdd : true,
26357         /**
26358          * @event OverlayViewOnRemove
26359          * Fires when OverlayView Draw
26360          * @param {Roo.bootstrap.LocationPicker} this
26361          */
26362         OverlayViewOnRemove : true,
26363         /**
26364          * @event OverlayViewShow
26365          * Fires when OverlayView Draw
26366          * @param {Roo.bootstrap.LocationPicker} this
26367          * @param {Pixel} cpx
26368          */
26369         OverlayViewShow : true,
26370         /**
26371          * @event OverlayViewHide
26372          * Fires when OverlayView Draw
26373          * @param {Roo.bootstrap.LocationPicker} this
26374          */
26375         OverlayViewHide : true,
26376         /**
26377          * @event loadexception
26378          * Fires when load google lib failed.
26379          * @param {Roo.bootstrap.LocationPicker} this
26380          */
26381         loadexception : true
26382     });
26383         
26384 };
26385
26386 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26387     
26388     gMapContext: false,
26389     
26390     latitude: 0,
26391     longitude: 0,
26392     zoom: 15,
26393     mapTypeId: false,
26394     mapTypeControl: false,
26395     disableDoubleClickZoom: false,
26396     scrollwheel: true,
26397     streetViewControl: false,
26398     radius: 0,
26399     locationName: '',
26400     draggable: true,
26401     enableAutocomplete: false,
26402     enableReverseGeocode: true,
26403     markerTitle: '',
26404     
26405     getAutoCreate: function()
26406     {
26407
26408         var cfg = {
26409             tag: 'div',
26410             cls: 'roo-location-picker'
26411         };
26412         
26413         return cfg
26414     },
26415     
26416     initEvents: function(ct, position)
26417     {       
26418         if(!this.el.getWidth() || this.isApplied()){
26419             return;
26420         }
26421         
26422         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26423         
26424         this.initial();
26425     },
26426     
26427     initial: function()
26428     {
26429         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26430             this.fireEvent('loadexception', this);
26431             return;
26432         }
26433         
26434         if(!this.mapTypeId){
26435             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26436         }
26437         
26438         this.gMapContext = this.GMapContext();
26439         
26440         this.initOverlayView();
26441         
26442         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26443         
26444         var _this = this;
26445                 
26446         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26447             _this.setPosition(_this.gMapContext.marker.position);
26448         });
26449         
26450         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26451             _this.fireEvent('mapClick', this, event);
26452             
26453         });
26454
26455         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26456             _this.fireEvent('mapRightClick', this, event);
26457             
26458         });
26459         
26460         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26461             _this.fireEvent('markerClick', this, event);
26462             
26463         });
26464
26465         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26466             _this.fireEvent('markerRightClick', this, event);
26467             
26468         });
26469         
26470         this.setPosition(this.gMapContext.location);
26471         
26472         this.fireEvent('initial', this, this.gMapContext.location);
26473     },
26474     
26475     initOverlayView: function()
26476     {
26477         var _this = this;
26478         
26479         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26480             
26481             draw: function()
26482             {
26483                 _this.fireEvent('OverlayViewDraw', _this);
26484             },
26485             
26486             onAdd: function()
26487             {
26488                 _this.fireEvent('OverlayViewOnAdd', _this);
26489             },
26490             
26491             onRemove: function()
26492             {
26493                 _this.fireEvent('OverlayViewOnRemove', _this);
26494             },
26495             
26496             show: function(cpx)
26497             {
26498                 _this.fireEvent('OverlayViewShow', _this, cpx);
26499             },
26500             
26501             hide: function()
26502             {
26503                 _this.fireEvent('OverlayViewHide', _this);
26504             }
26505             
26506         });
26507     },
26508     
26509     fromLatLngToContainerPixel: function(event)
26510     {
26511         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26512     },
26513     
26514     isApplied: function() 
26515     {
26516         return this.getGmapContext() == false ? false : true;
26517     },
26518     
26519     getGmapContext: function() 
26520     {
26521         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26522     },
26523     
26524     GMapContext: function() 
26525     {
26526         var position = new google.maps.LatLng(this.latitude, this.longitude);
26527         
26528         var _map = new google.maps.Map(this.el.dom, {
26529             center: position,
26530             zoom: this.zoom,
26531             mapTypeId: this.mapTypeId,
26532             mapTypeControl: this.mapTypeControl,
26533             disableDoubleClickZoom: this.disableDoubleClickZoom,
26534             scrollwheel: this.scrollwheel,
26535             streetViewControl: this.streetViewControl,
26536             locationName: this.locationName,
26537             draggable: this.draggable,
26538             enableAutocomplete: this.enableAutocomplete,
26539             enableReverseGeocode: this.enableReverseGeocode
26540         });
26541         
26542         var _marker = new google.maps.Marker({
26543             position: position,
26544             map: _map,
26545             title: this.markerTitle,
26546             draggable: this.draggable
26547         });
26548         
26549         return {
26550             map: _map,
26551             marker: _marker,
26552             circle: null,
26553             location: position,
26554             radius: this.radius,
26555             locationName: this.locationName,
26556             addressComponents: {
26557                 formatted_address: null,
26558                 addressLine1: null,
26559                 addressLine2: null,
26560                 streetName: null,
26561                 streetNumber: null,
26562                 city: null,
26563                 district: null,
26564                 state: null,
26565                 stateOrProvince: null
26566             },
26567             settings: this,
26568             domContainer: this.el.dom,
26569             geodecoder: new google.maps.Geocoder()
26570         };
26571     },
26572     
26573     drawCircle: function(center, radius, options) 
26574     {
26575         if (this.gMapContext.circle != null) {
26576             this.gMapContext.circle.setMap(null);
26577         }
26578         if (radius > 0) {
26579             radius *= 1;
26580             options = Roo.apply({}, options, {
26581                 strokeColor: "#0000FF",
26582                 strokeOpacity: .35,
26583                 strokeWeight: 2,
26584                 fillColor: "#0000FF",
26585                 fillOpacity: .2
26586             });
26587             
26588             options.map = this.gMapContext.map;
26589             options.radius = radius;
26590             options.center = center;
26591             this.gMapContext.circle = new google.maps.Circle(options);
26592             return this.gMapContext.circle;
26593         }
26594         
26595         return null;
26596     },
26597     
26598     setPosition: function(location) 
26599     {
26600         this.gMapContext.location = location;
26601         this.gMapContext.marker.setPosition(location);
26602         this.gMapContext.map.panTo(location);
26603         this.drawCircle(location, this.gMapContext.radius, {});
26604         
26605         var _this = this;
26606         
26607         if (this.gMapContext.settings.enableReverseGeocode) {
26608             this.gMapContext.geodecoder.geocode({
26609                 latLng: this.gMapContext.location
26610             }, function(results, status) {
26611                 
26612                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26613                     _this.gMapContext.locationName = results[0].formatted_address;
26614                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26615                     
26616                     _this.fireEvent('positionchanged', this, location);
26617                 }
26618             });
26619             
26620             return;
26621         }
26622         
26623         this.fireEvent('positionchanged', this, location);
26624     },
26625     
26626     resize: function()
26627     {
26628         google.maps.event.trigger(this.gMapContext.map, "resize");
26629         
26630         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26631         
26632         this.fireEvent('resize', this);
26633     },
26634     
26635     setPositionByLatLng: function(latitude, longitude)
26636     {
26637         this.setPosition(new google.maps.LatLng(latitude, longitude));
26638     },
26639     
26640     getCurrentPosition: function() 
26641     {
26642         return {
26643             latitude: this.gMapContext.location.lat(),
26644             longitude: this.gMapContext.location.lng()
26645         };
26646     },
26647     
26648     getAddressName: function() 
26649     {
26650         return this.gMapContext.locationName;
26651     },
26652     
26653     getAddressComponents: function() 
26654     {
26655         return this.gMapContext.addressComponents;
26656     },
26657     
26658     address_component_from_google_geocode: function(address_components) 
26659     {
26660         var result = {};
26661         
26662         for (var i = 0; i < address_components.length; i++) {
26663             var component = address_components[i];
26664             if (component.types.indexOf("postal_code") >= 0) {
26665                 result.postalCode = component.short_name;
26666             } else if (component.types.indexOf("street_number") >= 0) {
26667                 result.streetNumber = component.short_name;
26668             } else if (component.types.indexOf("route") >= 0) {
26669                 result.streetName = component.short_name;
26670             } else if (component.types.indexOf("neighborhood") >= 0) {
26671                 result.city = component.short_name;
26672             } else if (component.types.indexOf("locality") >= 0) {
26673                 result.city = component.short_name;
26674             } else if (component.types.indexOf("sublocality") >= 0) {
26675                 result.district = component.short_name;
26676             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26677                 result.stateOrProvince = component.short_name;
26678             } else if (component.types.indexOf("country") >= 0) {
26679                 result.country = component.short_name;
26680             }
26681         }
26682         
26683         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26684         result.addressLine2 = "";
26685         return result;
26686     },
26687     
26688     setZoomLevel: function(zoom)
26689     {
26690         this.gMapContext.map.setZoom(zoom);
26691     },
26692     
26693     show: function()
26694     {
26695         if(!this.el){
26696             return;
26697         }
26698         
26699         this.el.show();
26700         
26701         this.resize();
26702         
26703         this.fireEvent('show', this);
26704     },
26705     
26706     hide: function()
26707     {
26708         if(!this.el){
26709             return;
26710         }
26711         
26712         this.el.hide();
26713         
26714         this.fireEvent('hide', this);
26715     }
26716     
26717 });
26718
26719 Roo.apply(Roo.bootstrap.LocationPicker, {
26720     
26721     OverlayView : function(map, options)
26722     {
26723         options = options || {};
26724         
26725         this.setMap(map);
26726     }
26727     
26728     
26729 });/*
26730  * - LGPL
26731  *
26732  * Alert
26733  * 
26734  */
26735
26736 /**
26737  * @class Roo.bootstrap.Alert
26738  * @extends Roo.bootstrap.Component
26739  * Bootstrap Alert class
26740  * @cfg {String} title The title of alert
26741  * @cfg {String} html The content of alert
26742  * @cfg {String} weight (  success | info | warning | danger )
26743  * @cfg {String} faicon font-awesomeicon
26744  * 
26745  * @constructor
26746  * Create a new alert
26747  * @param {Object} config The config object
26748  */
26749
26750
26751 Roo.bootstrap.Alert = function(config){
26752     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26753     
26754 };
26755
26756 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26757     
26758     title: '',
26759     html: '',
26760     weight: false,
26761     faicon: false,
26762     
26763     getAutoCreate : function()
26764     {
26765         
26766         var cfg = {
26767             tag : 'div',
26768             cls : 'alert',
26769             cn : [
26770                 {
26771                     tag : 'i',
26772                     cls : 'roo-alert-icon'
26773                     
26774                 },
26775                 {
26776                     tag : 'b',
26777                     cls : 'roo-alert-title',
26778                     html : this.title
26779                 },
26780                 {
26781                     tag : 'span',
26782                     cls : 'roo-alert-text',
26783                     html : this.html
26784                 }
26785             ]
26786         };
26787         
26788         if(this.faicon){
26789             cfg.cn[0].cls += ' fa ' + this.faicon;
26790         }
26791         
26792         if(this.weight){
26793             cfg.cls += ' alert-' + this.weight;
26794         }
26795         
26796         return cfg;
26797     },
26798     
26799     initEvents: function() 
26800     {
26801         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26802     },
26803     
26804     setTitle : function(str)
26805     {
26806         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26807     },
26808     
26809     setText : function(str)
26810     {
26811         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26812     },
26813     
26814     setWeight : function(weight)
26815     {
26816         if(this.weight){
26817             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26818         }
26819         
26820         this.weight = weight;
26821         
26822         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26823     },
26824     
26825     setIcon : function(icon)
26826     {
26827         if(this.faicon){
26828             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26829         }
26830         
26831         this.faicon = icon;
26832         
26833         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26834     },
26835     
26836     hide: function() 
26837     {
26838         this.el.hide();   
26839     },
26840     
26841     show: function() 
26842     {  
26843         this.el.show();   
26844     }
26845     
26846 });
26847
26848  
26849 /*
26850 * Licence: LGPL
26851 */
26852
26853 /**
26854  * @class Roo.bootstrap.UploadCropbox
26855  * @extends Roo.bootstrap.Component
26856  * Bootstrap UploadCropbox class
26857  * @cfg {String} emptyText show when image has been loaded
26858  * @cfg {String} rotateNotify show when image too small to rotate
26859  * @cfg {Number} errorTimeout default 3000
26860  * @cfg {Number} minWidth default 300
26861  * @cfg {Number} minHeight default 300
26862  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26863  * @cfg {Boolean} isDocument (true|false) default false
26864  * @cfg {String} url action url
26865  * @cfg {String} paramName default 'imageUpload'
26866  * @cfg {String} method default POST
26867  * @cfg {Boolean} loadMask (true|false) default true
26868  * @cfg {Boolean} loadingText default 'Loading...'
26869  * 
26870  * @constructor
26871  * Create a new UploadCropbox
26872  * @param {Object} config The config object
26873  */
26874
26875 Roo.bootstrap.UploadCropbox = function(config){
26876     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26877     
26878     this.addEvents({
26879         /**
26880          * @event beforeselectfile
26881          * Fire before select file
26882          * @param {Roo.bootstrap.UploadCropbox} this
26883          */
26884         "beforeselectfile" : true,
26885         /**
26886          * @event initial
26887          * Fire after initEvent
26888          * @param {Roo.bootstrap.UploadCropbox} this
26889          */
26890         "initial" : true,
26891         /**
26892          * @event crop
26893          * Fire after initEvent
26894          * @param {Roo.bootstrap.UploadCropbox} this
26895          * @param {String} data
26896          */
26897         "crop" : true,
26898         /**
26899          * @event prepare
26900          * Fire when preparing the file data
26901          * @param {Roo.bootstrap.UploadCropbox} this
26902          * @param {Object} file
26903          */
26904         "prepare" : true,
26905         /**
26906          * @event exception
26907          * Fire when get exception
26908          * @param {Roo.bootstrap.UploadCropbox} this
26909          * @param {XMLHttpRequest} xhr
26910          */
26911         "exception" : true,
26912         /**
26913          * @event beforeloadcanvas
26914          * Fire before load the canvas
26915          * @param {Roo.bootstrap.UploadCropbox} this
26916          * @param {String} src
26917          */
26918         "beforeloadcanvas" : true,
26919         /**
26920          * @event trash
26921          * Fire when trash image
26922          * @param {Roo.bootstrap.UploadCropbox} this
26923          */
26924         "trash" : true,
26925         /**
26926          * @event download
26927          * Fire when download the image
26928          * @param {Roo.bootstrap.UploadCropbox} this
26929          */
26930         "download" : true,
26931         /**
26932          * @event footerbuttonclick
26933          * Fire when footerbuttonclick
26934          * @param {Roo.bootstrap.UploadCropbox} this
26935          * @param {String} type
26936          */
26937         "footerbuttonclick" : true,
26938         /**
26939          * @event resize
26940          * Fire when resize
26941          * @param {Roo.bootstrap.UploadCropbox} this
26942          */
26943         "resize" : true,
26944         /**
26945          * @event rotate
26946          * Fire when rotate the image
26947          * @param {Roo.bootstrap.UploadCropbox} this
26948          * @param {String} pos
26949          */
26950         "rotate" : true,
26951         /**
26952          * @event inspect
26953          * Fire when inspect the file
26954          * @param {Roo.bootstrap.UploadCropbox} this
26955          * @param {Object} file
26956          */
26957         "inspect" : true,
26958         /**
26959          * @event upload
26960          * Fire when xhr upload the file
26961          * @param {Roo.bootstrap.UploadCropbox} this
26962          * @param {Object} data
26963          */
26964         "upload" : true,
26965         /**
26966          * @event arrange
26967          * Fire when arrange the file data
26968          * @param {Roo.bootstrap.UploadCropbox} this
26969          * @param {Object} formData
26970          */
26971         "arrange" : true
26972     });
26973     
26974     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26975 };
26976
26977 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26978     
26979     emptyText : 'Click to upload image',
26980     rotateNotify : 'Image is too small to rotate',
26981     errorTimeout : 3000,
26982     scale : 0,
26983     baseScale : 1,
26984     rotate : 0,
26985     dragable : false,
26986     pinching : false,
26987     mouseX : 0,
26988     mouseY : 0,
26989     cropData : false,
26990     minWidth : 300,
26991     minHeight : 300,
26992     file : false,
26993     exif : {},
26994     baseRotate : 1,
26995     cropType : 'image/jpeg',
26996     buttons : false,
26997     canvasLoaded : false,
26998     isDocument : false,
26999     method : 'POST',
27000     paramName : 'imageUpload',
27001     loadMask : true,
27002     loadingText : 'Loading...',
27003     maskEl : false,
27004     
27005     getAutoCreate : function()
27006     {
27007         var cfg = {
27008             tag : 'div',
27009             cls : 'roo-upload-cropbox',
27010             cn : [
27011                 {
27012                     tag : 'input',
27013                     cls : 'roo-upload-cropbox-selector',
27014                     type : 'file'
27015                 },
27016                 {
27017                     tag : 'div',
27018                     cls : 'roo-upload-cropbox-body',
27019                     style : 'cursor:pointer',
27020                     cn : [
27021                         {
27022                             tag : 'div',
27023                             cls : 'roo-upload-cropbox-preview'
27024                         },
27025                         {
27026                             tag : 'div',
27027                             cls : 'roo-upload-cropbox-thumb'
27028                         },
27029                         {
27030                             tag : 'div',
27031                             cls : 'roo-upload-cropbox-empty-notify',
27032                             html : this.emptyText
27033                         },
27034                         {
27035                             tag : 'div',
27036                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27037                             html : this.rotateNotify
27038                         }
27039                     ]
27040                 },
27041                 {
27042                     tag : 'div',
27043                     cls : 'roo-upload-cropbox-footer',
27044                     cn : {
27045                         tag : 'div',
27046                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27047                         cn : []
27048                     }
27049                 }
27050             ]
27051         };
27052         
27053         return cfg;
27054     },
27055     
27056     onRender : function(ct, position)
27057     {
27058         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27059         
27060         if (this.buttons.length) {
27061             
27062             Roo.each(this.buttons, function(bb) {
27063                 
27064                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27065                 
27066                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27067                 
27068             }, this);
27069         }
27070         
27071         if(this.loadMask){
27072             this.maskEl = this.el;
27073         }
27074     },
27075     
27076     initEvents : function()
27077     {
27078         this.urlAPI = (window.createObjectURL && window) || 
27079                                 (window.URL && URL.revokeObjectURL && URL) || 
27080                                 (window.webkitURL && webkitURL);
27081                         
27082         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27083         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27084         
27085         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27086         this.selectorEl.hide();
27087         
27088         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27089         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27090         
27091         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27092         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27093         this.thumbEl.hide();
27094         
27095         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27096         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27097         
27098         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27099         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27100         this.errorEl.hide();
27101         
27102         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27103         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27104         this.footerEl.hide();
27105         
27106         this.setThumbBoxSize();
27107         
27108         this.bind();
27109         
27110         this.resize();
27111         
27112         this.fireEvent('initial', this);
27113     },
27114
27115     bind : function()
27116     {
27117         var _this = this;
27118         
27119         window.addEventListener("resize", function() { _this.resize(); } );
27120         
27121         this.bodyEl.on('click', this.beforeSelectFile, this);
27122         
27123         if(Roo.isTouch){
27124             this.bodyEl.on('touchstart', this.onTouchStart, this);
27125             this.bodyEl.on('touchmove', this.onTouchMove, this);
27126             this.bodyEl.on('touchend', this.onTouchEnd, this);
27127         }
27128         
27129         if(!Roo.isTouch){
27130             this.bodyEl.on('mousedown', this.onMouseDown, this);
27131             this.bodyEl.on('mousemove', this.onMouseMove, this);
27132             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27133             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27134             Roo.get(document).on('mouseup', this.onMouseUp, this);
27135         }
27136         
27137         this.selectorEl.on('change', this.onFileSelected, this);
27138     },
27139     
27140     reset : function()
27141     {    
27142         this.scale = 0;
27143         this.baseScale = 1;
27144         this.rotate = 0;
27145         this.baseRotate = 1;
27146         this.dragable = false;
27147         this.pinching = false;
27148         this.mouseX = 0;
27149         this.mouseY = 0;
27150         this.cropData = false;
27151         this.notifyEl.dom.innerHTML = this.emptyText;
27152         
27153         this.selectorEl.dom.value = '';
27154         
27155     },
27156     
27157     resize : function()
27158     {
27159         if(this.fireEvent('resize', this) != false){
27160             this.setThumbBoxPosition();
27161             this.setCanvasPosition();
27162         }
27163     },
27164     
27165     onFooterButtonClick : function(e, el, o, type)
27166     {
27167         switch (type) {
27168             case 'rotate-left' :
27169                 this.onRotateLeft(e);
27170                 break;
27171             case 'rotate-right' :
27172                 this.onRotateRight(e);
27173                 break;
27174             case 'picture' :
27175                 this.beforeSelectFile(e);
27176                 break;
27177             case 'trash' :
27178                 this.trash(e);
27179                 break;
27180             case 'crop' :
27181                 this.crop(e);
27182                 break;
27183             case 'download' :
27184                 this.download(e);
27185                 break;
27186             default :
27187                 break;
27188         }
27189         
27190         this.fireEvent('footerbuttonclick', this, type);
27191     },
27192     
27193     beforeSelectFile : function(e)
27194     {
27195         e.preventDefault();
27196         
27197         if(this.fireEvent('beforeselectfile', this) != false){
27198             this.selectorEl.dom.click();
27199         }
27200     },
27201     
27202     onFileSelected : function(e)
27203     {
27204         e.preventDefault();
27205         
27206         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27207             return;
27208         }
27209         
27210         var file = this.selectorEl.dom.files[0];
27211         
27212         if(this.fireEvent('inspect', this, file) != false){
27213             this.prepare(file);
27214         }
27215         
27216     },
27217     
27218     trash : function(e)
27219     {
27220         this.fireEvent('trash', this);
27221     },
27222     
27223     download : function(e)
27224     {
27225         this.fireEvent('download', this);
27226     },
27227     
27228     loadCanvas : function(src)
27229     {   
27230         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27231             
27232             this.reset();
27233             
27234             this.imageEl = document.createElement('img');
27235             
27236             var _this = this;
27237             
27238             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27239             
27240             this.imageEl.src = src;
27241         }
27242     },
27243     
27244     onLoadCanvas : function()
27245     {   
27246         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27247         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27248         
27249         this.bodyEl.un('click', this.beforeSelectFile, this);
27250         
27251         this.notifyEl.hide();
27252         this.thumbEl.show();
27253         this.footerEl.show();
27254         
27255         this.baseRotateLevel();
27256         
27257         if(this.isDocument){
27258             this.setThumbBoxSize();
27259         }
27260         
27261         this.setThumbBoxPosition();
27262         
27263         this.baseScaleLevel();
27264         
27265         this.draw();
27266         
27267         this.resize();
27268         
27269         this.canvasLoaded = true;
27270         
27271         if(this.loadMask){
27272             this.maskEl.unmask();
27273         }
27274         
27275     },
27276     
27277     setCanvasPosition : function()
27278     {   
27279         if(!this.canvasEl){
27280             return;
27281         }
27282         
27283         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27284         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27285         
27286         this.previewEl.setLeft(pw);
27287         this.previewEl.setTop(ph);
27288         
27289     },
27290     
27291     onMouseDown : function(e)
27292     {   
27293         e.stopEvent();
27294         
27295         this.dragable = true;
27296         this.pinching = false;
27297         
27298         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27299             this.dragable = false;
27300             return;
27301         }
27302         
27303         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27304         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27305         
27306     },
27307     
27308     onMouseMove : function(e)
27309     {   
27310         e.stopEvent();
27311         
27312         if(!this.canvasLoaded){
27313             return;
27314         }
27315         
27316         if (!this.dragable){
27317             return;
27318         }
27319         
27320         var minX = Math.ceil(this.thumbEl.getLeft(true));
27321         var minY = Math.ceil(this.thumbEl.getTop(true));
27322         
27323         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27324         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27325         
27326         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27327         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27328         
27329         x = x - this.mouseX;
27330         y = y - this.mouseY;
27331         
27332         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27333         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27334         
27335         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27336         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27337         
27338         this.previewEl.setLeft(bgX);
27339         this.previewEl.setTop(bgY);
27340         
27341         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27342         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27343     },
27344     
27345     onMouseUp : function(e)
27346     {   
27347         e.stopEvent();
27348         
27349         this.dragable = false;
27350     },
27351     
27352     onMouseWheel : function(e)
27353     {   
27354         e.stopEvent();
27355         
27356         this.startScale = this.scale;
27357         
27358         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27359         
27360         if(!this.zoomable()){
27361             this.scale = this.startScale;
27362             return;
27363         }
27364         
27365         this.draw();
27366         
27367         return;
27368     },
27369     
27370     zoomable : function()
27371     {
27372         var minScale = this.thumbEl.getWidth() / this.minWidth;
27373         
27374         if(this.minWidth < this.minHeight){
27375             minScale = this.thumbEl.getHeight() / this.minHeight;
27376         }
27377         
27378         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27379         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27380         
27381         if(
27382                 this.isDocument &&
27383                 (this.rotate == 0 || this.rotate == 180) && 
27384                 (
27385                     width > this.imageEl.OriginWidth || 
27386                     height > this.imageEl.OriginHeight ||
27387                     (width < this.minWidth && height < this.minHeight)
27388                 )
27389         ){
27390             return false;
27391         }
27392         
27393         if(
27394                 this.isDocument &&
27395                 (this.rotate == 90 || this.rotate == 270) && 
27396                 (
27397                     width > this.imageEl.OriginWidth || 
27398                     height > this.imageEl.OriginHeight ||
27399                     (width < this.minHeight && height < this.minWidth)
27400                 )
27401         ){
27402             return false;
27403         }
27404         
27405         if(
27406                 !this.isDocument &&
27407                 (this.rotate == 0 || this.rotate == 180) && 
27408                 (
27409                     width < this.minWidth || 
27410                     width > this.imageEl.OriginWidth || 
27411                     height < this.minHeight || 
27412                     height > this.imageEl.OriginHeight
27413                 )
27414         ){
27415             return false;
27416         }
27417         
27418         if(
27419                 !this.isDocument &&
27420                 (this.rotate == 90 || this.rotate == 270) && 
27421                 (
27422                     width < this.minHeight || 
27423                     width > this.imageEl.OriginWidth || 
27424                     height < this.minWidth || 
27425                     height > this.imageEl.OriginHeight
27426                 )
27427         ){
27428             return false;
27429         }
27430         
27431         return true;
27432         
27433     },
27434     
27435     onRotateLeft : function(e)
27436     {   
27437         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27438             
27439             var minScale = this.thumbEl.getWidth() / this.minWidth;
27440             
27441             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27442             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27443             
27444             this.startScale = this.scale;
27445             
27446             while (this.getScaleLevel() < minScale){
27447             
27448                 this.scale = this.scale + 1;
27449                 
27450                 if(!this.zoomable()){
27451                     break;
27452                 }
27453                 
27454                 if(
27455                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27456                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27457                 ){
27458                     continue;
27459                 }
27460                 
27461                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27462
27463                 this.draw();
27464                 
27465                 return;
27466             }
27467             
27468             this.scale = this.startScale;
27469             
27470             this.onRotateFail();
27471             
27472             return false;
27473         }
27474         
27475         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27476
27477         if(this.isDocument){
27478             this.setThumbBoxSize();
27479             this.setThumbBoxPosition();
27480             this.setCanvasPosition();
27481         }
27482         
27483         this.draw();
27484         
27485         this.fireEvent('rotate', this, 'left');
27486         
27487     },
27488     
27489     onRotateRight : function(e)
27490     {
27491         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27492             
27493             var minScale = this.thumbEl.getWidth() / this.minWidth;
27494         
27495             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27496             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27497             
27498             this.startScale = this.scale;
27499             
27500             while (this.getScaleLevel() < minScale){
27501             
27502                 this.scale = this.scale + 1;
27503                 
27504                 if(!this.zoomable()){
27505                     break;
27506                 }
27507                 
27508                 if(
27509                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27510                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27511                 ){
27512                     continue;
27513                 }
27514                 
27515                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27516
27517                 this.draw();
27518                 
27519                 return;
27520             }
27521             
27522             this.scale = this.startScale;
27523             
27524             this.onRotateFail();
27525             
27526             return false;
27527         }
27528         
27529         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27530
27531         if(this.isDocument){
27532             this.setThumbBoxSize();
27533             this.setThumbBoxPosition();
27534             this.setCanvasPosition();
27535         }
27536         
27537         this.draw();
27538         
27539         this.fireEvent('rotate', this, 'right');
27540     },
27541     
27542     onRotateFail : function()
27543     {
27544         this.errorEl.show(true);
27545         
27546         var _this = this;
27547         
27548         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27549     },
27550     
27551     draw : function()
27552     {
27553         this.previewEl.dom.innerHTML = '';
27554         
27555         var canvasEl = document.createElement("canvas");
27556         
27557         var contextEl = canvasEl.getContext("2d");
27558         
27559         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27560         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27561         var center = this.imageEl.OriginWidth / 2;
27562         
27563         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27564             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27565             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27566             center = this.imageEl.OriginHeight / 2;
27567         }
27568         
27569         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27570         
27571         contextEl.translate(center, center);
27572         contextEl.rotate(this.rotate * Math.PI / 180);
27573
27574         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27575         
27576         this.canvasEl = document.createElement("canvas");
27577         
27578         this.contextEl = this.canvasEl.getContext("2d");
27579         
27580         switch (this.rotate) {
27581             case 0 :
27582                 
27583                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27584                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27585                 
27586                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27587                 
27588                 break;
27589             case 90 : 
27590                 
27591                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27592                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27593                 
27594                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27595                     this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27596                     break;
27597                 }
27598                 
27599                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27600                 
27601                 break;
27602             case 180 :
27603                 
27604                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27605                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27606                 
27607                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27608                     this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27609                     break;
27610                 }
27611                 
27612                 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27613                 
27614                 break;
27615             case 270 :
27616                 
27617                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27618                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27619         
27620                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27621                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27622                     break;
27623                 }
27624                 
27625                 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27626                 
27627                 break;
27628             default : 
27629                 break;
27630         }
27631         
27632         this.previewEl.appendChild(this.canvasEl);
27633         
27634         this.setCanvasPosition();
27635     },
27636     
27637     crop : function()
27638     {
27639         if(!this.canvasLoaded){
27640             return;
27641         }
27642         
27643         var imageCanvas = document.createElement("canvas");
27644         
27645         var imageContext = imageCanvas.getContext("2d");
27646         
27647         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27648         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27649         
27650         var center = imageCanvas.width / 2;
27651         
27652         imageContext.translate(center, center);
27653         
27654         imageContext.rotate(this.rotate * Math.PI / 180);
27655         
27656         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27657         
27658         var canvas = document.createElement("canvas");
27659         
27660         var context = canvas.getContext("2d");
27661                 
27662         canvas.width = this.minWidth;
27663         canvas.height = this.minHeight;
27664
27665         switch (this.rotate) {
27666             case 0 :
27667                 
27668                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27669                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27670                 
27671                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27672                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27673                 
27674                 var targetWidth = this.minWidth - 2 * x;
27675                 var targetHeight = this.minHeight - 2 * y;
27676                 
27677                 var scale = 1;
27678                 
27679                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27680                     scale = targetWidth / width;
27681                 }
27682                 
27683                 if(x > 0 && y == 0){
27684                     scale = targetHeight / height;
27685                 }
27686                 
27687                 if(x > 0 && y > 0){
27688                     scale = targetWidth / width;
27689                     
27690                     if(width < height){
27691                         scale = targetHeight / height;
27692                     }
27693                 }
27694                 
27695                 context.scale(scale, scale);
27696                 
27697                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27698                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27699
27700                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27701                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27702
27703                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27704                 
27705                 break;
27706             case 90 : 
27707                 
27708                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27709                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27710                 
27711                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27712                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27713                 
27714                 var targetWidth = this.minWidth - 2 * x;
27715                 var targetHeight = this.minHeight - 2 * y;
27716                 
27717                 var scale = 1;
27718                 
27719                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27720                     scale = targetWidth / width;
27721                 }
27722                 
27723                 if(x > 0 && y == 0){
27724                     scale = targetHeight / height;
27725                 }
27726                 
27727                 if(x > 0 && y > 0){
27728                     scale = targetWidth / width;
27729                     
27730                     if(width < height){
27731                         scale = targetHeight / height;
27732                     }
27733                 }
27734                 
27735                 context.scale(scale, scale);
27736                 
27737                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27738                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27739
27740                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27741                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27742                 
27743                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27744                 
27745                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27746                 
27747                 break;
27748             case 180 :
27749                 
27750                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27751                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27752                 
27753                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27754                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27755                 
27756                 var targetWidth = this.minWidth - 2 * x;
27757                 var targetHeight = this.minHeight - 2 * y;
27758                 
27759                 var scale = 1;
27760                 
27761                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27762                     scale = targetWidth / width;
27763                 }
27764                 
27765                 if(x > 0 && y == 0){
27766                     scale = targetHeight / height;
27767                 }
27768                 
27769                 if(x > 0 && y > 0){
27770                     scale = targetWidth / width;
27771                     
27772                     if(width < height){
27773                         scale = targetHeight / height;
27774                     }
27775                 }
27776                 
27777                 context.scale(scale, scale);
27778                 
27779                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27780                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27781
27782                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27783                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27784
27785                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27786                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27787                 
27788                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27789                 
27790                 break;
27791             case 270 :
27792                 
27793                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27794                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27795                 
27796                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27797                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27798                 
27799                 var targetWidth = this.minWidth - 2 * x;
27800                 var targetHeight = this.minHeight - 2 * y;
27801                 
27802                 var scale = 1;
27803                 
27804                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27805                     scale = targetWidth / width;
27806                 }
27807                 
27808                 if(x > 0 && y == 0){
27809                     scale = targetHeight / height;
27810                 }
27811                 
27812                 if(x > 0 && y > 0){
27813                     scale = targetWidth / width;
27814                     
27815                     if(width < height){
27816                         scale = targetHeight / height;
27817                     }
27818                 }
27819                 
27820                 context.scale(scale, scale);
27821                 
27822                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27823                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27824
27825                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27826                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27827                 
27828                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27829                 
27830                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27831                 
27832                 break;
27833             default : 
27834                 break;
27835         }
27836         
27837         this.cropData = canvas.toDataURL(this.cropType);
27838         
27839         if(this.fireEvent('crop', this, this.cropData) !== false){
27840             this.process(this.file, this.cropData);
27841         }
27842         
27843         return;
27844         
27845     },
27846     
27847     setThumbBoxSize : function()
27848     {
27849         var width, height;
27850         
27851         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27852             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27853             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27854             
27855             this.minWidth = width;
27856             this.minHeight = height;
27857             
27858             if(this.rotate == 90 || this.rotate == 270){
27859                 this.minWidth = height;
27860                 this.minHeight = width;
27861             }
27862         }
27863         
27864         height = 300;
27865         width = Math.ceil(this.minWidth * height / this.minHeight);
27866         
27867         if(this.minWidth > this.minHeight){
27868             width = 300;
27869             height = Math.ceil(this.minHeight * width / this.minWidth);
27870         }
27871         
27872         this.thumbEl.setStyle({
27873             width : width + 'px',
27874             height : height + 'px'
27875         });
27876
27877         return;
27878             
27879     },
27880     
27881     setThumbBoxPosition : function()
27882     {
27883         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27884         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27885         
27886         this.thumbEl.setLeft(x);
27887         this.thumbEl.setTop(y);
27888         
27889     },
27890     
27891     baseRotateLevel : function()
27892     {
27893         this.baseRotate = 1;
27894         
27895         if(
27896                 typeof(this.exif) != 'undefined' &&
27897                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27898                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27899         ){
27900             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27901         }
27902         
27903         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27904         
27905     },
27906     
27907     baseScaleLevel : function()
27908     {
27909         var width, height;
27910         
27911         if(this.isDocument){
27912             
27913             if(this.baseRotate == 6 || this.baseRotate == 8){
27914             
27915                 height = this.thumbEl.getHeight();
27916                 this.baseScale = height / this.imageEl.OriginWidth;
27917
27918                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27919                     width = this.thumbEl.getWidth();
27920                     this.baseScale = width / this.imageEl.OriginHeight;
27921                 }
27922
27923                 return;
27924             }
27925
27926             height = this.thumbEl.getHeight();
27927             this.baseScale = height / this.imageEl.OriginHeight;
27928
27929             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27930                 width = this.thumbEl.getWidth();
27931                 this.baseScale = width / this.imageEl.OriginWidth;
27932             }
27933
27934             return;
27935         }
27936         
27937         if(this.baseRotate == 6 || this.baseRotate == 8){
27938             
27939             width = this.thumbEl.getHeight();
27940             this.baseScale = width / this.imageEl.OriginHeight;
27941             
27942             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27943                 height = this.thumbEl.getWidth();
27944                 this.baseScale = height / this.imageEl.OriginHeight;
27945             }
27946             
27947             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27948                 height = this.thumbEl.getWidth();
27949                 this.baseScale = height / this.imageEl.OriginHeight;
27950                 
27951                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27952                     width = this.thumbEl.getHeight();
27953                     this.baseScale = width / this.imageEl.OriginWidth;
27954                 }
27955             }
27956             
27957             return;
27958         }
27959         
27960         width = this.thumbEl.getWidth();
27961         this.baseScale = width / this.imageEl.OriginWidth;
27962         
27963         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27964             height = this.thumbEl.getHeight();
27965             this.baseScale = height / this.imageEl.OriginHeight;
27966         }
27967         
27968         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27969             
27970             height = this.thumbEl.getHeight();
27971             this.baseScale = height / this.imageEl.OriginHeight;
27972             
27973             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27974                 width = this.thumbEl.getWidth();
27975                 this.baseScale = width / this.imageEl.OriginWidth;
27976             }
27977             
27978         }
27979         
27980         return;
27981     },
27982     
27983     getScaleLevel : function()
27984     {
27985         return this.baseScale * Math.pow(1.1, this.scale);
27986     },
27987     
27988     onTouchStart : function(e)
27989     {
27990         if(!this.canvasLoaded){
27991             this.beforeSelectFile(e);
27992             return;
27993         }
27994         
27995         var touches = e.browserEvent.touches;
27996         
27997         if(!touches){
27998             return;
27999         }
28000         
28001         if(touches.length == 1){
28002             this.onMouseDown(e);
28003             return;
28004         }
28005         
28006         if(touches.length != 2){
28007             return;
28008         }
28009         
28010         var coords = [];
28011         
28012         for(var i = 0, finger; finger = touches[i]; i++){
28013             coords.push(finger.pageX, finger.pageY);
28014         }
28015         
28016         var x = Math.pow(coords[0] - coords[2], 2);
28017         var y = Math.pow(coords[1] - coords[3], 2);
28018         
28019         this.startDistance = Math.sqrt(x + y);
28020         
28021         this.startScale = this.scale;
28022         
28023         this.pinching = true;
28024         this.dragable = false;
28025         
28026     },
28027     
28028     onTouchMove : function(e)
28029     {
28030         if(!this.pinching && !this.dragable){
28031             return;
28032         }
28033         
28034         var touches = e.browserEvent.touches;
28035         
28036         if(!touches){
28037             return;
28038         }
28039         
28040         if(this.dragable){
28041             this.onMouseMove(e);
28042             return;
28043         }
28044         
28045         var coords = [];
28046         
28047         for(var i = 0, finger; finger = touches[i]; i++){
28048             coords.push(finger.pageX, finger.pageY);
28049         }
28050         
28051         var x = Math.pow(coords[0] - coords[2], 2);
28052         var y = Math.pow(coords[1] - coords[3], 2);
28053         
28054         this.endDistance = Math.sqrt(x + y);
28055         
28056         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28057         
28058         if(!this.zoomable()){
28059             this.scale = this.startScale;
28060             return;
28061         }
28062         
28063         this.draw();
28064         
28065     },
28066     
28067     onTouchEnd : function(e)
28068     {
28069         this.pinching = false;
28070         this.dragable = false;
28071         
28072     },
28073     
28074     process : function(file, crop)
28075     {
28076         if(this.loadMask){
28077             this.maskEl.mask(this.loadingText);
28078         }
28079         
28080         this.xhr = new XMLHttpRequest();
28081         
28082         file.xhr = this.xhr;
28083
28084         this.xhr.open(this.method, this.url, true);
28085         
28086         var headers = {
28087             "Accept": "application/json",
28088             "Cache-Control": "no-cache",
28089             "X-Requested-With": "XMLHttpRequest"
28090         };
28091         
28092         for (var headerName in headers) {
28093             var headerValue = headers[headerName];
28094             if (headerValue) {
28095                 this.xhr.setRequestHeader(headerName, headerValue);
28096             }
28097         }
28098         
28099         var _this = this;
28100         
28101         this.xhr.onload = function()
28102         {
28103             _this.xhrOnLoad(_this.xhr);
28104         }
28105         
28106         this.xhr.onerror = function()
28107         {
28108             _this.xhrOnError(_this.xhr);
28109         }
28110         
28111         var formData = new FormData();
28112
28113         formData.append('returnHTML', 'NO');
28114         
28115         if(crop){
28116             formData.append('crop', crop);
28117         }
28118         
28119         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28120             formData.append(this.paramName, file, file.name);
28121         }
28122         
28123         if(typeof(file.filename) != 'undefined'){
28124             formData.append('filename', file.filename);
28125         }
28126         
28127         if(typeof(file.mimetype) != 'undefined'){
28128             formData.append('mimetype', file.mimetype);
28129         }
28130         
28131         if(this.fireEvent('arrange', this, formData) != false){
28132             this.xhr.send(formData);
28133         };
28134     },
28135     
28136     xhrOnLoad : function(xhr)
28137     {
28138         if(this.loadMask){
28139             this.maskEl.unmask();
28140         }
28141         
28142         if (xhr.readyState !== 4) {
28143             this.fireEvent('exception', this, xhr);
28144             return;
28145         }
28146
28147         var response = Roo.decode(xhr.responseText);
28148         
28149         if(!response.success){
28150             this.fireEvent('exception', this, xhr);
28151             return;
28152         }
28153         
28154         var response = Roo.decode(xhr.responseText);
28155         
28156         this.fireEvent('upload', this, response);
28157         
28158     },
28159     
28160     xhrOnError : function()
28161     {
28162         if(this.loadMask){
28163             this.maskEl.unmask();
28164         }
28165         
28166         Roo.log('xhr on error');
28167         
28168         var response = Roo.decode(xhr.responseText);
28169           
28170         Roo.log(response);
28171         
28172     },
28173     
28174     prepare : function(file)
28175     {   
28176         if(this.loadMask){
28177             this.maskEl.mask(this.loadingText);
28178         }
28179         
28180         this.file = false;
28181         this.exif = {};
28182         
28183         if(typeof(file) === 'string'){
28184             this.loadCanvas(file);
28185             return;
28186         }
28187         
28188         if(!file || !this.urlAPI){
28189             return;
28190         }
28191         
28192         this.file = file;
28193         this.cropType = file.type;
28194         
28195         var _this = this;
28196         
28197         if(this.fireEvent('prepare', this, this.file) != false){
28198             
28199             var reader = new FileReader();
28200             
28201             reader.onload = function (e) {
28202                 if (e.target.error) {
28203                     Roo.log(e.target.error);
28204                     return;
28205                 }
28206                 
28207                 var buffer = e.target.result,
28208                     dataView = new DataView(buffer),
28209                     offset = 2,
28210                     maxOffset = dataView.byteLength - 4,
28211                     markerBytes,
28212                     markerLength;
28213                 
28214                 if (dataView.getUint16(0) === 0xffd8) {
28215                     while (offset < maxOffset) {
28216                         markerBytes = dataView.getUint16(offset);
28217                         
28218                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28219                             markerLength = dataView.getUint16(offset + 2) + 2;
28220                             if (offset + markerLength > dataView.byteLength) {
28221                                 Roo.log('Invalid meta data: Invalid segment size.');
28222                                 break;
28223                             }
28224                             
28225                             if(markerBytes == 0xffe1){
28226                                 _this.parseExifData(
28227                                     dataView,
28228                                     offset,
28229                                     markerLength
28230                                 );
28231                             }
28232                             
28233                             offset += markerLength;
28234                             
28235                             continue;
28236                         }
28237                         
28238                         break;
28239                     }
28240                     
28241                 }
28242                 
28243                 var url = _this.urlAPI.createObjectURL(_this.file);
28244                 
28245                 _this.loadCanvas(url);
28246                 
28247                 return;
28248             }
28249             
28250             reader.readAsArrayBuffer(this.file);
28251             
28252         }
28253         
28254     },
28255     
28256     parseExifData : function(dataView, offset, length)
28257     {
28258         var tiffOffset = offset + 10,
28259             littleEndian,
28260             dirOffset;
28261     
28262         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28263             // No Exif data, might be XMP data instead
28264             return;
28265         }
28266         
28267         // Check for the ASCII code for "Exif" (0x45786966):
28268         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28269             // No Exif data, might be XMP data instead
28270             return;
28271         }
28272         if (tiffOffset + 8 > dataView.byteLength) {
28273             Roo.log('Invalid Exif data: Invalid segment size.');
28274             return;
28275         }
28276         // Check for the two null bytes:
28277         if (dataView.getUint16(offset + 8) !== 0x0000) {
28278             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28279             return;
28280         }
28281         // Check the byte alignment:
28282         switch (dataView.getUint16(tiffOffset)) {
28283         case 0x4949:
28284             littleEndian = true;
28285             break;
28286         case 0x4D4D:
28287             littleEndian = false;
28288             break;
28289         default:
28290             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28291             return;
28292         }
28293         // Check for the TIFF tag marker (0x002A):
28294         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28295             Roo.log('Invalid Exif data: Missing TIFF marker.');
28296             return;
28297         }
28298         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28299         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28300         
28301         this.parseExifTags(
28302             dataView,
28303             tiffOffset,
28304             tiffOffset + dirOffset,
28305             littleEndian
28306         );
28307     },
28308     
28309     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28310     {
28311         var tagsNumber,
28312             dirEndOffset,
28313             i;
28314         if (dirOffset + 6 > dataView.byteLength) {
28315             Roo.log('Invalid Exif data: Invalid directory offset.');
28316             return;
28317         }
28318         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28319         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28320         if (dirEndOffset + 4 > dataView.byteLength) {
28321             Roo.log('Invalid Exif data: Invalid directory size.');
28322             return;
28323         }
28324         for (i = 0; i < tagsNumber; i += 1) {
28325             this.parseExifTag(
28326                 dataView,
28327                 tiffOffset,
28328                 dirOffset + 2 + 12 * i, // tag offset
28329                 littleEndian
28330             );
28331         }
28332         // Return the offset to the next directory:
28333         return dataView.getUint32(dirEndOffset, littleEndian);
28334     },
28335     
28336     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28337     {
28338         var tag = dataView.getUint16(offset, littleEndian);
28339         
28340         this.exif[tag] = this.getExifValue(
28341             dataView,
28342             tiffOffset,
28343             offset,
28344             dataView.getUint16(offset + 2, littleEndian), // tag type
28345             dataView.getUint32(offset + 4, littleEndian), // tag length
28346             littleEndian
28347         );
28348     },
28349     
28350     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28351     {
28352         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28353             tagSize,
28354             dataOffset,
28355             values,
28356             i,
28357             str,
28358             c;
28359     
28360         if (!tagType) {
28361             Roo.log('Invalid Exif data: Invalid tag type.');
28362             return;
28363         }
28364         
28365         tagSize = tagType.size * length;
28366         // Determine if the value is contained in the dataOffset bytes,
28367         // or if the value at the dataOffset is a pointer to the actual data:
28368         dataOffset = tagSize > 4 ?
28369                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28370         if (dataOffset + tagSize > dataView.byteLength) {
28371             Roo.log('Invalid Exif data: Invalid data offset.');
28372             return;
28373         }
28374         if (length === 1) {
28375             return tagType.getValue(dataView, dataOffset, littleEndian);
28376         }
28377         values = [];
28378         for (i = 0; i < length; i += 1) {
28379             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28380         }
28381         
28382         if (tagType.ascii) {
28383             str = '';
28384             // Concatenate the chars:
28385             for (i = 0; i < values.length; i += 1) {
28386                 c = values[i];
28387                 // Ignore the terminating NULL byte(s):
28388                 if (c === '\u0000') {
28389                     break;
28390                 }
28391                 str += c;
28392             }
28393             return str;
28394         }
28395         return values;
28396     }
28397     
28398 });
28399
28400 Roo.apply(Roo.bootstrap.UploadCropbox, {
28401     tags : {
28402         'Orientation': 0x0112
28403     },
28404     
28405     Orientation: {
28406             1: 0, //'top-left',
28407 //            2: 'top-right',
28408             3: 180, //'bottom-right',
28409 //            4: 'bottom-left',
28410 //            5: 'left-top',
28411             6: 90, //'right-top',
28412 //            7: 'right-bottom',
28413             8: 270 //'left-bottom'
28414     },
28415     
28416     exifTagTypes : {
28417         // byte, 8-bit unsigned int:
28418         1: {
28419             getValue: function (dataView, dataOffset) {
28420                 return dataView.getUint8(dataOffset);
28421             },
28422             size: 1
28423         },
28424         // ascii, 8-bit byte:
28425         2: {
28426             getValue: function (dataView, dataOffset) {
28427                 return String.fromCharCode(dataView.getUint8(dataOffset));
28428             },
28429             size: 1,
28430             ascii: true
28431         },
28432         // short, 16 bit int:
28433         3: {
28434             getValue: function (dataView, dataOffset, littleEndian) {
28435                 return dataView.getUint16(dataOffset, littleEndian);
28436             },
28437             size: 2
28438         },
28439         // long, 32 bit int:
28440         4: {
28441             getValue: function (dataView, dataOffset, littleEndian) {
28442                 return dataView.getUint32(dataOffset, littleEndian);
28443             },
28444             size: 4
28445         },
28446         // rational = two long values, first is numerator, second is denominator:
28447         5: {
28448             getValue: function (dataView, dataOffset, littleEndian) {
28449                 return dataView.getUint32(dataOffset, littleEndian) /
28450                     dataView.getUint32(dataOffset + 4, littleEndian);
28451             },
28452             size: 8
28453         },
28454         // slong, 32 bit signed int:
28455         9: {
28456             getValue: function (dataView, dataOffset, littleEndian) {
28457                 return dataView.getInt32(dataOffset, littleEndian);
28458             },
28459             size: 4
28460         },
28461         // srational, two slongs, first is numerator, second is denominator:
28462         10: {
28463             getValue: function (dataView, dataOffset, littleEndian) {
28464                 return dataView.getInt32(dataOffset, littleEndian) /
28465                     dataView.getInt32(dataOffset + 4, littleEndian);
28466             },
28467             size: 8
28468         }
28469     },
28470     
28471     footer : {
28472         STANDARD : [
28473             {
28474                 tag : 'div',
28475                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28476                 action : 'rotate-left',
28477                 cn : [
28478                     {
28479                         tag : 'button',
28480                         cls : 'btn btn-default',
28481                         html : '<i class="fa fa-undo"></i>'
28482                     }
28483                 ]
28484             },
28485             {
28486                 tag : 'div',
28487                 cls : 'btn-group roo-upload-cropbox-picture',
28488                 action : 'picture',
28489                 cn : [
28490                     {
28491                         tag : 'button',
28492                         cls : 'btn btn-default',
28493                         html : '<i class="fa fa-picture-o"></i>'
28494                     }
28495                 ]
28496             },
28497             {
28498                 tag : 'div',
28499                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28500                 action : 'rotate-right',
28501                 cn : [
28502                     {
28503                         tag : 'button',
28504                         cls : 'btn btn-default',
28505                         html : '<i class="fa fa-repeat"></i>'
28506                     }
28507                 ]
28508             }
28509         ],
28510         DOCUMENT : [
28511             {
28512                 tag : 'div',
28513                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28514                 action : 'rotate-left',
28515                 cn : [
28516                     {
28517                         tag : 'button',
28518                         cls : 'btn btn-default',
28519                         html : '<i class="fa fa-undo"></i>'
28520                     }
28521                 ]
28522             },
28523             {
28524                 tag : 'div',
28525                 cls : 'btn-group roo-upload-cropbox-download',
28526                 action : 'download',
28527                 cn : [
28528                     {
28529                         tag : 'button',
28530                         cls : 'btn btn-default',
28531                         html : '<i class="fa fa-download"></i>'
28532                     }
28533                 ]
28534             },
28535             {
28536                 tag : 'div',
28537                 cls : 'btn-group roo-upload-cropbox-crop',
28538                 action : 'crop',
28539                 cn : [
28540                     {
28541                         tag : 'button',
28542                         cls : 'btn btn-default',
28543                         html : '<i class="fa fa-crop"></i>'
28544                     }
28545                 ]
28546             },
28547             {
28548                 tag : 'div',
28549                 cls : 'btn-group roo-upload-cropbox-trash',
28550                 action : 'trash',
28551                 cn : [
28552                     {
28553                         tag : 'button',
28554                         cls : 'btn btn-default',
28555                         html : '<i class="fa fa-trash"></i>'
28556                     }
28557                 ]
28558             },
28559             {
28560                 tag : 'div',
28561                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28562                 action : 'rotate-right',
28563                 cn : [
28564                     {
28565                         tag : 'button',
28566                         cls : 'btn btn-default',
28567                         html : '<i class="fa fa-repeat"></i>'
28568                     }
28569                 ]
28570             }
28571         ],
28572         ROTATOR : [
28573             {
28574                 tag : 'div',
28575                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28576                 action : 'rotate-left',
28577                 cn : [
28578                     {
28579                         tag : 'button',
28580                         cls : 'btn btn-default',
28581                         html : '<i class="fa fa-undo"></i>'
28582                     }
28583                 ]
28584             },
28585             {
28586                 tag : 'div',
28587                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28588                 action : 'rotate-right',
28589                 cn : [
28590                     {
28591                         tag : 'button',
28592                         cls : 'btn btn-default',
28593                         html : '<i class="fa fa-repeat"></i>'
28594                     }
28595                 ]
28596             }
28597         ]
28598     }
28599 });
28600
28601 /*
28602 * Licence: LGPL
28603 */
28604
28605 /**
28606  * @class Roo.bootstrap.DocumentManager
28607  * @extends Roo.bootstrap.Component
28608  * Bootstrap DocumentManager class
28609  * @cfg {String} paramName default 'imageUpload'
28610  * @cfg {String} toolTipName default 'filename'
28611  * @cfg {String} method default POST
28612  * @cfg {String} url action url
28613  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28614  * @cfg {Boolean} multiple multiple upload default true
28615  * @cfg {Number} thumbSize default 300
28616  * @cfg {String} fieldLabel
28617  * @cfg {Number} labelWidth default 4
28618  * @cfg {String} labelAlign (left|top) default left
28619  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28620 * @cfg {Number} labellg set the width of label (1-12)
28621  * @cfg {Number} labelmd set the width of label (1-12)
28622  * @cfg {Number} labelsm set the width of label (1-12)
28623  * @cfg {Number} labelxs set the width of label (1-12)
28624  * 
28625  * @constructor
28626  * Create a new DocumentManager
28627  * @param {Object} config The config object
28628  */
28629
28630 Roo.bootstrap.DocumentManager = function(config){
28631     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28632     
28633     this.files = [];
28634     this.delegates = [];
28635     
28636     this.addEvents({
28637         /**
28638          * @event initial
28639          * Fire when initial the DocumentManager
28640          * @param {Roo.bootstrap.DocumentManager} this
28641          */
28642         "initial" : true,
28643         /**
28644          * @event inspect
28645          * inspect selected file
28646          * @param {Roo.bootstrap.DocumentManager} this
28647          * @param {File} file
28648          */
28649         "inspect" : true,
28650         /**
28651          * @event exception
28652          * Fire when xhr load exception
28653          * @param {Roo.bootstrap.DocumentManager} this
28654          * @param {XMLHttpRequest} xhr
28655          */
28656         "exception" : true,
28657         /**
28658          * @event afterupload
28659          * Fire when xhr load exception
28660          * @param {Roo.bootstrap.DocumentManager} this
28661          * @param {XMLHttpRequest} xhr
28662          */
28663         "afterupload" : true,
28664         /**
28665          * @event prepare
28666          * prepare the form data
28667          * @param {Roo.bootstrap.DocumentManager} this
28668          * @param {Object} formData
28669          */
28670         "prepare" : true,
28671         /**
28672          * @event remove
28673          * Fire when remove the file
28674          * @param {Roo.bootstrap.DocumentManager} this
28675          * @param {Object} file
28676          */
28677         "remove" : true,
28678         /**
28679          * @event refresh
28680          * Fire after refresh the file
28681          * @param {Roo.bootstrap.DocumentManager} this
28682          */
28683         "refresh" : true,
28684         /**
28685          * @event click
28686          * Fire after click the image
28687          * @param {Roo.bootstrap.DocumentManager} this
28688          * @param {Object} file
28689          */
28690         "click" : true,
28691         /**
28692          * @event edit
28693          * Fire when upload a image and editable set to true
28694          * @param {Roo.bootstrap.DocumentManager} this
28695          * @param {Object} file
28696          */
28697         "edit" : true,
28698         /**
28699          * @event beforeselectfile
28700          * Fire before select file
28701          * @param {Roo.bootstrap.DocumentManager} this
28702          */
28703         "beforeselectfile" : true,
28704         /**
28705          * @event process
28706          * Fire before process file
28707          * @param {Roo.bootstrap.DocumentManager} this
28708          * @param {Object} file
28709          */
28710         "process" : true,
28711         /**
28712          * @event previewrendered
28713          * Fire when preview rendered
28714          * @param {Roo.bootstrap.DocumentManager} this
28715          * @param {Object} file
28716          */
28717         "previewrendered" : true,
28718         /**
28719          */
28720         "previewResize" : true
28721         
28722     });
28723 };
28724
28725 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28726     
28727     boxes : 0,
28728     inputName : '',
28729     thumbSize : 300,
28730     multiple : true,
28731     files : false,
28732     method : 'POST',
28733     url : '',
28734     paramName : 'imageUpload',
28735     toolTipName : 'filename',
28736     fieldLabel : '',
28737     labelWidth : 4,
28738     labelAlign : 'left',
28739     editable : true,
28740     delegates : false,
28741     xhr : false, 
28742     
28743     labellg : 0,
28744     labelmd : 0,
28745     labelsm : 0,
28746     labelxs : 0,
28747     
28748     getAutoCreate : function()
28749     {   
28750         var managerWidget = {
28751             tag : 'div',
28752             cls : 'roo-document-manager',
28753             cn : [
28754                 {
28755                     tag : 'input',
28756                     cls : 'roo-document-manager-selector',
28757                     type : 'file'
28758                 },
28759                 {
28760                     tag : 'div',
28761                     cls : 'roo-document-manager-uploader',
28762                     cn : [
28763                         {
28764                             tag : 'div',
28765                             cls : 'roo-document-manager-upload-btn',
28766                             html : '<i class="fa fa-plus"></i>'
28767                         }
28768                     ]
28769                     
28770                 }
28771             ]
28772         };
28773         
28774         var content = [
28775             {
28776                 tag : 'div',
28777                 cls : 'column col-md-12',
28778                 cn : managerWidget
28779             }
28780         ];
28781         
28782         if(this.fieldLabel.length){
28783             
28784             content = [
28785                 {
28786                     tag : 'div',
28787                     cls : 'column col-md-12',
28788                     html : this.fieldLabel
28789                 },
28790                 {
28791                     tag : 'div',
28792                     cls : 'column col-md-12',
28793                     cn : managerWidget
28794                 }
28795             ];
28796
28797             if(this.labelAlign == 'left'){
28798                 content = [
28799                     {
28800                         tag : 'div',
28801                         cls : 'column',
28802                         html : this.fieldLabel
28803                     },
28804                     {
28805                         tag : 'div',
28806                         cls : 'column',
28807                         cn : managerWidget
28808                     }
28809                 ];
28810                 
28811                 if(this.labelWidth > 12){
28812                     content[0].style = "width: " + this.labelWidth + 'px';
28813                 }
28814
28815                 if(this.labelWidth < 13 && this.labelmd == 0){
28816                     this.labelmd = this.labelWidth;
28817                 }
28818
28819                 if(this.labellg > 0){
28820                     content[0].cls += ' col-lg-' + this.labellg;
28821                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28822                 }
28823
28824                 if(this.labelmd > 0){
28825                     content[0].cls += ' col-md-' + this.labelmd;
28826                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28827                 }
28828
28829                 if(this.labelsm > 0){
28830                     content[0].cls += ' col-sm-' + this.labelsm;
28831                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28832                 }
28833
28834                 if(this.labelxs > 0){
28835                     content[0].cls += ' col-xs-' + this.labelxs;
28836                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28837                 }
28838                 
28839             }
28840         }
28841         
28842         var cfg = {
28843             tag : 'div',
28844             cls : 'row clearfix',
28845             cn : content
28846         };
28847         
28848         return cfg;
28849         
28850     },
28851     
28852     initEvents : function()
28853     {
28854         this.managerEl = this.el.select('.roo-document-manager', true).first();
28855         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28856         
28857         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28858         this.selectorEl.hide();
28859         
28860         if(this.multiple){
28861             this.selectorEl.attr('multiple', 'multiple');
28862         }
28863         
28864         this.selectorEl.on('change', this.onFileSelected, this);
28865         
28866         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28867         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28868         
28869         this.uploader.on('click', this.onUploaderClick, this);
28870         
28871         this.renderProgressDialog();
28872         
28873         var _this = this;
28874         
28875         window.addEventListener("resize", function() { _this.refresh(); } );
28876         
28877         this.fireEvent('initial', this);
28878     },
28879     
28880     renderProgressDialog : function()
28881     {
28882         var _this = this;
28883         
28884         this.progressDialog = new Roo.bootstrap.Modal({
28885             cls : 'roo-document-manager-progress-dialog',
28886             allow_close : false,
28887             title : '',
28888             buttons : [
28889                 {
28890                     name  :'cancel',
28891                     weight : 'danger',
28892                     html : 'Cancel'
28893                 }
28894             ], 
28895             listeners : { 
28896                 btnclick : function() {
28897                     _this.uploadCancel();
28898                     this.hide();
28899                 }
28900             }
28901         });
28902          
28903         this.progressDialog.render(Roo.get(document.body));
28904          
28905         this.progress = new Roo.bootstrap.Progress({
28906             cls : 'roo-document-manager-progress',
28907             active : true,
28908             striped : true
28909         });
28910         
28911         this.progress.render(this.progressDialog.getChildContainer());
28912         
28913         this.progressBar = new Roo.bootstrap.ProgressBar({
28914             cls : 'roo-document-manager-progress-bar',
28915             aria_valuenow : 0,
28916             aria_valuemin : 0,
28917             aria_valuemax : 12,
28918             panel : 'success'
28919         });
28920         
28921         this.progressBar.render(this.progress.getChildContainer());
28922     },
28923     
28924     onUploaderClick : function(e)
28925     {
28926         e.preventDefault();
28927      
28928         if(this.fireEvent('beforeselectfile', this) != false){
28929             this.selectorEl.dom.click();
28930         }
28931         
28932     },
28933     
28934     onFileSelected : function(e)
28935     {
28936         e.preventDefault();
28937         
28938         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28939             return;
28940         }
28941         
28942         Roo.each(this.selectorEl.dom.files, function(file){
28943             if(this.fireEvent('inspect', this, file) != false){
28944                 this.files.push(file);
28945             }
28946         }, this);
28947         
28948         this.queue();
28949         
28950     },
28951     
28952     queue : function()
28953     {
28954         this.selectorEl.dom.value = '';
28955         
28956         if(!this.files || !this.files.length){
28957             return;
28958         }
28959         
28960         if(this.boxes > 0 && this.files.length > this.boxes){
28961             this.files = this.files.slice(0, this.boxes);
28962         }
28963         
28964         this.uploader.show();
28965         
28966         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28967             this.uploader.hide();
28968         }
28969         
28970         var _this = this;
28971         
28972         var files = [];
28973         
28974         var docs = [];
28975         
28976         Roo.each(this.files, function(file){
28977             
28978             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28979                 var f = this.renderPreview(file);
28980                 files.push(f);
28981                 return;
28982             }
28983             
28984             if(file.type.indexOf('image') != -1){
28985                 this.delegates.push(
28986                     (function(){
28987                         _this.process(file);
28988                     }).createDelegate(this)
28989                 );
28990         
28991                 return;
28992             }
28993             
28994             docs.push(
28995                 (function(){
28996                     _this.process(file);
28997                 }).createDelegate(this)
28998             );
28999             
29000         }, this);
29001         
29002         this.files = files;
29003         
29004         this.delegates = this.delegates.concat(docs);
29005         
29006         if(!this.delegates.length){
29007             this.refresh();
29008             return;
29009         }
29010         
29011         this.progressBar.aria_valuemax = this.delegates.length;
29012         
29013         this.arrange();
29014         
29015         return;
29016     },
29017     
29018     arrange : function()
29019     {
29020         if(!this.delegates.length){
29021             this.progressDialog.hide();
29022             this.refresh();
29023             return;
29024         }
29025         
29026         var delegate = this.delegates.shift();
29027         
29028         this.progressDialog.show();
29029         
29030         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29031         
29032         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29033         
29034         delegate();
29035     },
29036     
29037     refresh : function()
29038     {
29039         this.uploader.show();
29040         
29041         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29042             this.uploader.hide();
29043         }
29044         
29045         Roo.isTouch ? this.closable(false) : this.closable(true);
29046         
29047         this.fireEvent('refresh', this);
29048     },
29049     
29050     onRemove : function(e, el, o)
29051     {
29052         e.preventDefault();
29053         
29054         this.fireEvent('remove', this, o);
29055         
29056     },
29057     
29058     remove : function(o)
29059     {
29060         var files = [];
29061         
29062         Roo.each(this.files, function(file){
29063             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29064                 files.push(file);
29065                 return;
29066             }
29067
29068             o.target.remove();
29069
29070         }, this);
29071         
29072         this.files = files;
29073         
29074         this.refresh();
29075     },
29076     
29077     clear : function()
29078     {
29079         Roo.each(this.files, function(file){
29080             if(!file.target){
29081                 return;
29082             }
29083             
29084             file.target.remove();
29085
29086         }, this);
29087         
29088         this.files = [];
29089         
29090         this.refresh();
29091     },
29092     
29093     onClick : function(e, el, o)
29094     {
29095         e.preventDefault();
29096         
29097         this.fireEvent('click', this, o);
29098         
29099     },
29100     
29101     closable : function(closable)
29102     {
29103         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29104             
29105             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29106             
29107             if(closable){
29108                 el.show();
29109                 return;
29110             }
29111             
29112             el.hide();
29113             
29114         }, this);
29115     },
29116     
29117     xhrOnLoad : function(xhr)
29118     {
29119         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29120             el.remove();
29121         }, this);
29122         
29123         if (xhr.readyState !== 4) {
29124             this.arrange();
29125             this.fireEvent('exception', this, xhr);
29126             return;
29127         }
29128
29129         var response = Roo.decode(xhr.responseText);
29130         
29131         if(!response.success){
29132             this.arrange();
29133             this.fireEvent('exception', this, xhr);
29134             return;
29135         }
29136         
29137         var file = this.renderPreview(response.data);
29138         
29139         this.files.push(file);
29140         
29141         this.arrange();
29142         
29143         this.fireEvent('afterupload', this, xhr);
29144         
29145     },
29146     
29147     xhrOnError : function(xhr)
29148     {
29149         Roo.log('xhr on error');
29150         
29151         var response = Roo.decode(xhr.responseText);
29152           
29153         Roo.log(response);
29154         
29155         this.arrange();
29156     },
29157     
29158     process : function(file)
29159     {
29160         if(this.fireEvent('process', this, file) !== false){
29161             if(this.editable && file.type.indexOf('image') != -1){
29162                 this.fireEvent('edit', this, file);
29163                 return;
29164             }
29165
29166             this.uploadStart(file, false);
29167
29168             return;
29169         }
29170         
29171     },
29172     
29173     uploadStart : function(file, crop)
29174     {
29175         this.xhr = new XMLHttpRequest();
29176         
29177         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29178             this.arrange();
29179             return;
29180         }
29181         
29182         file.xhr = this.xhr;
29183             
29184         this.managerEl.createChild({
29185             tag : 'div',
29186             cls : 'roo-document-manager-loading',
29187             cn : [
29188                 {
29189                     tag : 'div',
29190                     tooltip : file.name,
29191                     cls : 'roo-document-manager-thumb',
29192                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29193                 }
29194             ]
29195
29196         });
29197
29198         this.xhr.open(this.method, this.url, true);
29199         
29200         var headers = {
29201             "Accept": "application/json",
29202             "Cache-Control": "no-cache",
29203             "X-Requested-With": "XMLHttpRequest"
29204         };
29205         
29206         for (var headerName in headers) {
29207             var headerValue = headers[headerName];
29208             if (headerValue) {
29209                 this.xhr.setRequestHeader(headerName, headerValue);
29210             }
29211         }
29212         
29213         var _this = this;
29214         
29215         this.xhr.onload = function()
29216         {
29217             _this.xhrOnLoad(_this.xhr);
29218         }
29219         
29220         this.xhr.onerror = function()
29221         {
29222             _this.xhrOnError(_this.xhr);
29223         }
29224         
29225         var formData = new FormData();
29226
29227         formData.append('returnHTML', 'NO');
29228         
29229         if(crop){
29230             formData.append('crop', crop);
29231         }
29232         
29233         formData.append(this.paramName, file, file.name);
29234         
29235         var options = {
29236             file : file, 
29237             manually : false
29238         };
29239         
29240         if(this.fireEvent('prepare', this, formData, options) != false){
29241             
29242             if(options.manually){
29243                 return;
29244             }
29245             
29246             this.xhr.send(formData);
29247             return;
29248         };
29249         
29250         this.uploadCancel();
29251     },
29252     
29253     uploadCancel : function()
29254     {
29255         if (this.xhr) {
29256             this.xhr.abort();
29257         }
29258         
29259         this.delegates = [];
29260         
29261         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29262             el.remove();
29263         }, this);
29264         
29265         this.arrange();
29266     },
29267     
29268     renderPreview : function(file)
29269     {
29270         if(typeof(file.target) != 'undefined' && file.target){
29271             return file;
29272         }
29273         
29274         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29275         
29276         var previewEl = this.managerEl.createChild({
29277             tag : 'div',
29278             cls : 'roo-document-manager-preview',
29279             cn : [
29280                 {
29281                     tag : 'div',
29282                     tooltip : file[this.toolTipName],
29283                     cls : 'roo-document-manager-thumb',
29284                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29285                 },
29286                 {
29287                     tag : 'button',
29288                     cls : 'close',
29289                     html : '<i class="fa fa-times-circle"></i>'
29290                 }
29291             ]
29292         });
29293
29294         var close = previewEl.select('button.close', true).first();
29295
29296         close.on('click', this.onRemove, this, file);
29297
29298         file.target = previewEl;
29299
29300         var image = previewEl.select('img', true).first();
29301         
29302         var _this = this;
29303         
29304         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29305         
29306         image.on('click', this.onClick, this, file);
29307         
29308         this.fireEvent('previewrendered', this, file);
29309         
29310         return file;
29311         
29312     },
29313     
29314     onPreviewLoad : function(file, image)
29315     {
29316         if(typeof(file.target) == 'undefined' || !file.target){
29317             return;
29318         }
29319         
29320         var width = image.dom.naturalWidth || image.dom.width;
29321         var height = image.dom.naturalHeight || image.dom.height;
29322         
29323         if(!this.previewResize) {
29324             return;
29325         }
29326         
29327         if(width > height){
29328             file.target.addClass('wide');
29329             return;
29330         }
29331         
29332         file.target.addClass('tall');
29333         return;
29334         
29335     },
29336     
29337     uploadFromSource : function(file, crop)
29338     {
29339         this.xhr = new XMLHttpRequest();
29340         
29341         this.managerEl.createChild({
29342             tag : 'div',
29343             cls : 'roo-document-manager-loading',
29344             cn : [
29345                 {
29346                     tag : 'div',
29347                     tooltip : file.name,
29348                     cls : 'roo-document-manager-thumb',
29349                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29350                 }
29351             ]
29352
29353         });
29354
29355         this.xhr.open(this.method, this.url, true);
29356         
29357         var headers = {
29358             "Accept": "application/json",
29359             "Cache-Control": "no-cache",
29360             "X-Requested-With": "XMLHttpRequest"
29361         };
29362         
29363         for (var headerName in headers) {
29364             var headerValue = headers[headerName];
29365             if (headerValue) {
29366                 this.xhr.setRequestHeader(headerName, headerValue);
29367             }
29368         }
29369         
29370         var _this = this;
29371         
29372         this.xhr.onload = function()
29373         {
29374             _this.xhrOnLoad(_this.xhr);
29375         }
29376         
29377         this.xhr.onerror = function()
29378         {
29379             _this.xhrOnError(_this.xhr);
29380         }
29381         
29382         var formData = new FormData();
29383
29384         formData.append('returnHTML', 'NO');
29385         
29386         formData.append('crop', crop);
29387         
29388         if(typeof(file.filename) != 'undefined'){
29389             formData.append('filename', file.filename);
29390         }
29391         
29392         if(typeof(file.mimetype) != 'undefined'){
29393             formData.append('mimetype', file.mimetype);
29394         }
29395         
29396         Roo.log(formData);
29397         
29398         if(this.fireEvent('prepare', this, formData) != false){
29399             this.xhr.send(formData);
29400         };
29401     }
29402 });
29403
29404 /*
29405 * Licence: LGPL
29406 */
29407
29408 /**
29409  * @class Roo.bootstrap.DocumentViewer
29410  * @extends Roo.bootstrap.Component
29411  * Bootstrap DocumentViewer class
29412  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29413  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29414  * 
29415  * @constructor
29416  * Create a new DocumentViewer
29417  * @param {Object} config The config object
29418  */
29419
29420 Roo.bootstrap.DocumentViewer = function(config){
29421     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29422     
29423     this.addEvents({
29424         /**
29425          * @event initial
29426          * Fire after initEvent
29427          * @param {Roo.bootstrap.DocumentViewer} this
29428          */
29429         "initial" : true,
29430         /**
29431          * @event click
29432          * Fire after click
29433          * @param {Roo.bootstrap.DocumentViewer} this
29434          */
29435         "click" : true,
29436         /**
29437          * @event download
29438          * Fire after download button
29439          * @param {Roo.bootstrap.DocumentViewer} this
29440          */
29441         "download" : true,
29442         /**
29443          * @event trash
29444          * Fire after trash button
29445          * @param {Roo.bootstrap.DocumentViewer} this
29446          */
29447         "trash" : true
29448         
29449     });
29450 };
29451
29452 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29453     
29454     showDownload : true,
29455     
29456     showTrash : true,
29457     
29458     getAutoCreate : function()
29459     {
29460         var cfg = {
29461             tag : 'div',
29462             cls : 'roo-document-viewer',
29463             cn : [
29464                 {
29465                     tag : 'div',
29466                     cls : 'roo-document-viewer-body',
29467                     cn : [
29468                         {
29469                             tag : 'div',
29470                             cls : 'roo-document-viewer-thumb',
29471                             cn : [
29472                                 {
29473                                     tag : 'img',
29474                                     cls : 'roo-document-viewer-image'
29475                                 }
29476                             ]
29477                         }
29478                     ]
29479                 },
29480                 {
29481                     tag : 'div',
29482                     cls : 'roo-document-viewer-footer',
29483                     cn : {
29484                         tag : 'div',
29485                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29486                         cn : [
29487                             {
29488                                 tag : 'div',
29489                                 cls : 'btn-group roo-document-viewer-download',
29490                                 cn : [
29491                                     {
29492                                         tag : 'button',
29493                                         cls : 'btn btn-default',
29494                                         html : '<i class="fa fa-download"></i>'
29495                                     }
29496                                 ]
29497                             },
29498                             {
29499                                 tag : 'div',
29500                                 cls : 'btn-group roo-document-viewer-trash',
29501                                 cn : [
29502                                     {
29503                                         tag : 'button',
29504                                         cls : 'btn btn-default',
29505                                         html : '<i class="fa fa-trash"></i>'
29506                                     }
29507                                 ]
29508                             }
29509                         ]
29510                     }
29511                 }
29512             ]
29513         };
29514         
29515         return cfg;
29516     },
29517     
29518     initEvents : function()
29519     {
29520         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29521         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29522         
29523         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29524         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29525         
29526         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29527         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29528         
29529         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29530         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29531         
29532         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29533         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29534         
29535         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29536         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29537         
29538         this.bodyEl.on('click', this.onClick, this);
29539         this.downloadBtn.on('click', this.onDownload, this);
29540         this.trashBtn.on('click', this.onTrash, this);
29541         
29542         this.downloadBtn.hide();
29543         this.trashBtn.hide();
29544         
29545         if(this.showDownload){
29546             this.downloadBtn.show();
29547         }
29548         
29549         if(this.showTrash){
29550             this.trashBtn.show();
29551         }
29552         
29553         if(!this.showDownload && !this.showTrash) {
29554             this.footerEl.hide();
29555         }
29556         
29557     },
29558     
29559     initial : function()
29560     {
29561         this.fireEvent('initial', this);
29562         
29563     },
29564     
29565     onClick : function(e)
29566     {
29567         e.preventDefault();
29568         
29569         this.fireEvent('click', this);
29570     },
29571     
29572     onDownload : function(e)
29573     {
29574         e.preventDefault();
29575         
29576         this.fireEvent('download', this);
29577     },
29578     
29579     onTrash : function(e)
29580     {
29581         e.preventDefault();
29582         
29583         this.fireEvent('trash', this);
29584     }
29585     
29586 });
29587 /*
29588  * - LGPL
29589  *
29590  * nav progress bar
29591  * 
29592  */
29593
29594 /**
29595  * @class Roo.bootstrap.NavProgressBar
29596  * @extends Roo.bootstrap.Component
29597  * Bootstrap NavProgressBar class
29598  * 
29599  * @constructor
29600  * Create a new nav progress bar
29601  * @param {Object} config The config object
29602  */
29603
29604 Roo.bootstrap.NavProgressBar = function(config){
29605     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29606
29607     this.bullets = this.bullets || [];
29608    
29609 //    Roo.bootstrap.NavProgressBar.register(this);
29610      this.addEvents({
29611         /**
29612              * @event changed
29613              * Fires when the active item changes
29614              * @param {Roo.bootstrap.NavProgressBar} this
29615              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29616              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29617          */
29618         'changed': true
29619      });
29620     
29621 };
29622
29623 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29624     
29625     bullets : [],
29626     barItems : [],
29627     
29628     getAutoCreate : function()
29629     {
29630         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29631         
29632         cfg = {
29633             tag : 'div',
29634             cls : 'roo-navigation-bar-group',
29635             cn : [
29636                 {
29637                     tag : 'div',
29638                     cls : 'roo-navigation-top-bar'
29639                 },
29640                 {
29641                     tag : 'div',
29642                     cls : 'roo-navigation-bullets-bar',
29643                     cn : [
29644                         {
29645                             tag : 'ul',
29646                             cls : 'roo-navigation-bar'
29647                         }
29648                     ]
29649                 },
29650                 
29651                 {
29652                     tag : 'div',
29653                     cls : 'roo-navigation-bottom-bar'
29654                 }
29655             ]
29656             
29657         };
29658         
29659         return cfg;
29660         
29661     },
29662     
29663     initEvents: function() 
29664     {
29665         
29666     },
29667     
29668     onRender : function(ct, position) 
29669     {
29670         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29671         
29672         if(this.bullets.length){
29673             Roo.each(this.bullets, function(b){
29674                this.addItem(b);
29675             }, this);
29676         }
29677         
29678         this.format();
29679         
29680     },
29681     
29682     addItem : function(cfg)
29683     {
29684         var item = new Roo.bootstrap.NavProgressItem(cfg);
29685         
29686         item.parentId = this.id;
29687         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29688         
29689         if(cfg.html){
29690             var top = new Roo.bootstrap.Element({
29691                 tag : 'div',
29692                 cls : 'roo-navigation-bar-text'
29693             });
29694             
29695             var bottom = new Roo.bootstrap.Element({
29696                 tag : 'div',
29697                 cls : 'roo-navigation-bar-text'
29698             });
29699             
29700             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29701             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29702             
29703             var topText = new Roo.bootstrap.Element({
29704                 tag : 'span',
29705                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29706             });
29707             
29708             var bottomText = new Roo.bootstrap.Element({
29709                 tag : 'span',
29710                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29711             });
29712             
29713             topText.onRender(top.el, null);
29714             bottomText.onRender(bottom.el, null);
29715             
29716             item.topEl = top;
29717             item.bottomEl = bottom;
29718         }
29719         
29720         this.barItems.push(item);
29721         
29722         return item;
29723     },
29724     
29725     getActive : function()
29726     {
29727         var active = false;
29728         
29729         Roo.each(this.barItems, function(v){
29730             
29731             if (!v.isActive()) {
29732                 return;
29733             }
29734             
29735             active = v;
29736             return false;
29737             
29738         });
29739         
29740         return active;
29741     },
29742     
29743     setActiveItem : function(item)
29744     {
29745         var prev = false;
29746         
29747         Roo.each(this.barItems, function(v){
29748             if (v.rid == item.rid) {
29749                 return ;
29750             }
29751             
29752             if (v.isActive()) {
29753                 v.setActive(false);
29754                 prev = v;
29755             }
29756         });
29757
29758         item.setActive(true);
29759         
29760         this.fireEvent('changed', this, item, prev);
29761     },
29762     
29763     getBarItem: function(rid)
29764     {
29765         var ret = false;
29766         
29767         Roo.each(this.barItems, function(e) {
29768             if (e.rid != rid) {
29769                 return;
29770             }
29771             
29772             ret =  e;
29773             return false;
29774         });
29775         
29776         return ret;
29777     },
29778     
29779     indexOfItem : function(item)
29780     {
29781         var index = false;
29782         
29783         Roo.each(this.barItems, function(v, i){
29784             
29785             if (v.rid != item.rid) {
29786                 return;
29787             }
29788             
29789             index = i;
29790             return false
29791         });
29792         
29793         return index;
29794     },
29795     
29796     setActiveNext : function()
29797     {
29798         var i = this.indexOfItem(this.getActive());
29799         
29800         if (i > this.barItems.length) {
29801             return;
29802         }
29803         
29804         this.setActiveItem(this.barItems[i+1]);
29805     },
29806     
29807     setActivePrev : function()
29808     {
29809         var i = this.indexOfItem(this.getActive());
29810         
29811         if (i  < 1) {
29812             return;
29813         }
29814         
29815         this.setActiveItem(this.barItems[i-1]);
29816     },
29817     
29818     format : function()
29819     {
29820         if(!this.barItems.length){
29821             return;
29822         }
29823      
29824         var width = 100 / this.barItems.length;
29825         
29826         Roo.each(this.barItems, function(i){
29827             i.el.setStyle('width', width + '%');
29828             i.topEl.el.setStyle('width', width + '%');
29829             i.bottomEl.el.setStyle('width', width + '%');
29830         }, this);
29831         
29832     }
29833     
29834 });
29835 /*
29836  * - LGPL
29837  *
29838  * Nav Progress Item
29839  * 
29840  */
29841
29842 /**
29843  * @class Roo.bootstrap.NavProgressItem
29844  * @extends Roo.bootstrap.Component
29845  * Bootstrap NavProgressItem class
29846  * @cfg {String} rid the reference id
29847  * @cfg {Boolean} active (true|false) Is item active default false
29848  * @cfg {Boolean} disabled (true|false) Is item active default false
29849  * @cfg {String} html
29850  * @cfg {String} position (top|bottom) text position default bottom
29851  * @cfg {String} icon show icon instead of number
29852  * 
29853  * @constructor
29854  * Create a new NavProgressItem
29855  * @param {Object} config The config object
29856  */
29857 Roo.bootstrap.NavProgressItem = function(config){
29858     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29859     this.addEvents({
29860         // raw events
29861         /**
29862          * @event click
29863          * The raw click event for the entire grid.
29864          * @param {Roo.bootstrap.NavProgressItem} this
29865          * @param {Roo.EventObject} e
29866          */
29867         "click" : true
29868     });
29869    
29870 };
29871
29872 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29873     
29874     rid : '',
29875     active : false,
29876     disabled : false,
29877     html : '',
29878     position : 'bottom',
29879     icon : false,
29880     
29881     getAutoCreate : function()
29882     {
29883         var iconCls = 'roo-navigation-bar-item-icon';
29884         
29885         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29886         
29887         var cfg = {
29888             tag: 'li',
29889             cls: 'roo-navigation-bar-item',
29890             cn : [
29891                 {
29892                     tag : 'i',
29893                     cls : iconCls
29894                 }
29895             ]
29896         };
29897         
29898         if(this.active){
29899             cfg.cls += ' active';
29900         }
29901         if(this.disabled){
29902             cfg.cls += ' disabled';
29903         }
29904         
29905         return cfg;
29906     },
29907     
29908     disable : function()
29909     {
29910         this.setDisabled(true);
29911     },
29912     
29913     enable : function()
29914     {
29915         this.setDisabled(false);
29916     },
29917     
29918     initEvents: function() 
29919     {
29920         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29921         
29922         this.iconEl.on('click', this.onClick, this);
29923     },
29924     
29925     onClick : function(e)
29926     {
29927         e.preventDefault();
29928         
29929         if(this.disabled){
29930             return;
29931         }
29932         
29933         if(this.fireEvent('click', this, e) === false){
29934             return;
29935         };
29936         
29937         this.parent().setActiveItem(this);
29938     },
29939     
29940     isActive: function () 
29941     {
29942         return this.active;
29943     },
29944     
29945     setActive : function(state)
29946     {
29947         if(this.active == state){
29948             return;
29949         }
29950         
29951         this.active = state;
29952         
29953         if (state) {
29954             this.el.addClass('active');
29955             return;
29956         }
29957         
29958         this.el.removeClass('active');
29959         
29960         return;
29961     },
29962     
29963     setDisabled : function(state)
29964     {
29965         if(this.disabled == state){
29966             return;
29967         }
29968         
29969         this.disabled = state;
29970         
29971         if (state) {
29972             this.el.addClass('disabled');
29973             return;
29974         }
29975         
29976         this.el.removeClass('disabled');
29977     },
29978     
29979     tooltipEl : function()
29980     {
29981         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29982     }
29983 });
29984  
29985
29986  /*
29987  * - LGPL
29988  *
29989  * FieldLabel
29990  * 
29991  */
29992
29993 /**
29994  * @class Roo.bootstrap.FieldLabel
29995  * @extends Roo.bootstrap.Component
29996  * Bootstrap FieldLabel class
29997  * @cfg {String} html contents of the element
29998  * @cfg {String} tag tag of the element default label
29999  * @cfg {String} cls class of the element
30000  * @cfg {String} target label target 
30001  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30002  * @cfg {String} invalidClass default "text-warning"
30003  * @cfg {String} validClass default "text-success"
30004  * @cfg {String} iconTooltip default "This field is required"
30005  * @cfg {String} indicatorpos (left|right) default left
30006  * 
30007  * @constructor
30008  * Create a new FieldLabel
30009  * @param {Object} config The config object
30010  */
30011
30012 Roo.bootstrap.FieldLabel = function(config){
30013     Roo.bootstrap.Element.superclass.constructor.call(this, config);
30014     
30015     this.addEvents({
30016             /**
30017              * @event invalid
30018              * Fires after the field has been marked as invalid.
30019              * @param {Roo.form.FieldLabel} this
30020              * @param {String} msg The validation message
30021              */
30022             invalid : true,
30023             /**
30024              * @event valid
30025              * Fires after the field has been validated with no errors.
30026              * @param {Roo.form.FieldLabel} this
30027              */
30028             valid : true
30029         });
30030 };
30031
30032 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30033     
30034     tag: 'label',
30035     cls: '',
30036     html: '',
30037     target: '',
30038     allowBlank : true,
30039     invalidClass : 'has-warning',
30040     validClass : 'has-success',
30041     iconTooltip : 'This field is required',
30042     indicatorpos : 'left',
30043     
30044     getAutoCreate : function(){
30045         
30046         var cls = "";
30047         if (!this.allowBlank) {
30048             cls  = "visible";
30049         }
30050         
30051         var cfg = {
30052             tag : this.tag,
30053             cls : 'roo-bootstrap-field-label ' + this.cls,
30054             for : this.target,
30055             cn : [
30056                 {
30057                     tag : 'i',
30058                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30059                     tooltip : this.iconTooltip
30060                 },
30061                 {
30062                     tag : 'span',
30063                     html : this.html
30064                 }
30065             ] 
30066         };
30067         
30068         if(this.indicatorpos == 'right'){
30069             var cfg = {
30070                 tag : this.tag,
30071                 cls : 'roo-bootstrap-field-label ' + this.cls,
30072                 for : this.target,
30073                 cn : [
30074                     {
30075                         tag : 'span',
30076                         html : this.html
30077                     },
30078                     {
30079                         tag : 'i',
30080                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30081                         tooltip : this.iconTooltip
30082                     }
30083                 ] 
30084             };
30085         }
30086         
30087         return cfg;
30088     },
30089     
30090     initEvents: function() 
30091     {
30092         Roo.bootstrap.Element.superclass.initEvents.call(this);
30093         
30094         this.indicator = this.indicatorEl();
30095         
30096         if(this.indicator){
30097             this.indicator.removeClass('visible');
30098             this.indicator.addClass('invisible');
30099         }
30100         
30101         Roo.bootstrap.FieldLabel.register(this);
30102     },
30103     
30104     indicatorEl : function()
30105     {
30106         var indicator = this.el.select('i.roo-required-indicator',true).first();
30107         
30108         if(!indicator){
30109             return false;
30110         }
30111         
30112         return indicator;
30113         
30114     },
30115     
30116     /**
30117      * Mark this field as valid
30118      */
30119     markValid : function()
30120     {
30121         if(this.indicator){
30122             this.indicator.removeClass('visible');
30123             this.indicator.addClass('invisible');
30124         }
30125         
30126         this.el.removeClass(this.invalidClass);
30127         
30128         this.el.addClass(this.validClass);
30129         
30130         this.fireEvent('valid', this);
30131     },
30132     
30133     /**
30134      * Mark this field as invalid
30135      * @param {String} msg The validation message
30136      */
30137     markInvalid : function(msg)
30138     {
30139         if(this.indicator){
30140             this.indicator.removeClass('invisible');
30141             this.indicator.addClass('visible');
30142         }
30143         
30144         this.el.removeClass(this.validClass);
30145         
30146         this.el.addClass(this.invalidClass);
30147         
30148         this.fireEvent('invalid', this, msg);
30149     }
30150     
30151    
30152 });
30153
30154 Roo.apply(Roo.bootstrap.FieldLabel, {
30155     
30156     groups: {},
30157     
30158      /**
30159     * register a FieldLabel Group
30160     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30161     */
30162     register : function(label)
30163     {
30164         if(this.groups.hasOwnProperty(label.target)){
30165             return;
30166         }
30167      
30168         this.groups[label.target] = label;
30169         
30170     },
30171     /**
30172     * fetch a FieldLabel Group based on the target
30173     * @param {string} target
30174     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30175     */
30176     get: function(target) {
30177         if (typeof(this.groups[target]) == 'undefined') {
30178             return false;
30179         }
30180         
30181         return this.groups[target] ;
30182     }
30183 });
30184
30185  
30186
30187  /*
30188  * - LGPL
30189  *
30190  * page DateSplitField.
30191  * 
30192  */
30193
30194
30195 /**
30196  * @class Roo.bootstrap.DateSplitField
30197  * @extends Roo.bootstrap.Component
30198  * Bootstrap DateSplitField class
30199  * @cfg {string} fieldLabel - the label associated
30200  * @cfg {Number} labelWidth set the width of label (0-12)
30201  * @cfg {String} labelAlign (top|left)
30202  * @cfg {Boolean} dayAllowBlank (true|false) default false
30203  * @cfg {Boolean} monthAllowBlank (true|false) default false
30204  * @cfg {Boolean} yearAllowBlank (true|false) default false
30205  * @cfg {string} dayPlaceholder 
30206  * @cfg {string} monthPlaceholder
30207  * @cfg {string} yearPlaceholder
30208  * @cfg {string} dayFormat default 'd'
30209  * @cfg {string} monthFormat default 'm'
30210  * @cfg {string} yearFormat default 'Y'
30211  * @cfg {Number} labellg set the width of label (1-12)
30212  * @cfg {Number} labelmd set the width of label (1-12)
30213  * @cfg {Number} labelsm set the width of label (1-12)
30214  * @cfg {Number} labelxs set the width of label (1-12)
30215
30216  *     
30217  * @constructor
30218  * Create a new DateSplitField
30219  * @param {Object} config The config object
30220  */
30221
30222 Roo.bootstrap.DateSplitField = function(config){
30223     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30224     
30225     this.addEvents({
30226         // raw events
30227          /**
30228          * @event years
30229          * getting the data of years
30230          * @param {Roo.bootstrap.DateSplitField} this
30231          * @param {Object} years
30232          */
30233         "years" : true,
30234         /**
30235          * @event days
30236          * getting the data of days
30237          * @param {Roo.bootstrap.DateSplitField} this
30238          * @param {Object} days
30239          */
30240         "days" : true,
30241         /**
30242          * @event invalid
30243          * Fires after the field has been marked as invalid.
30244          * @param {Roo.form.Field} this
30245          * @param {String} msg The validation message
30246          */
30247         invalid : true,
30248        /**
30249          * @event valid
30250          * Fires after the field has been validated with no errors.
30251          * @param {Roo.form.Field} this
30252          */
30253         valid : true
30254     });
30255 };
30256
30257 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30258     
30259     fieldLabel : '',
30260     labelAlign : 'top',
30261     labelWidth : 3,
30262     dayAllowBlank : false,
30263     monthAllowBlank : false,
30264     yearAllowBlank : false,
30265     dayPlaceholder : '',
30266     monthPlaceholder : '',
30267     yearPlaceholder : '',
30268     dayFormat : 'd',
30269     monthFormat : 'm',
30270     yearFormat : 'Y',
30271     isFormField : true,
30272     labellg : 0,
30273     labelmd : 0,
30274     labelsm : 0,
30275     labelxs : 0,
30276     
30277     getAutoCreate : function()
30278     {
30279         var cfg = {
30280             tag : 'div',
30281             cls : 'row roo-date-split-field-group',
30282             cn : [
30283                 {
30284                     tag : 'input',
30285                     type : 'hidden',
30286                     cls : 'form-hidden-field roo-date-split-field-group-value',
30287                     name : this.name
30288                 }
30289             ]
30290         };
30291         
30292         var labelCls = 'col-md-12';
30293         var contentCls = 'col-md-4';
30294         
30295         if(this.fieldLabel){
30296             
30297             var label = {
30298                 tag : 'div',
30299                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30300                 cn : [
30301                     {
30302                         tag : 'label',
30303                         html : this.fieldLabel
30304                     }
30305                 ]
30306             };
30307             
30308             if(this.labelAlign == 'left'){
30309             
30310                 if(this.labelWidth > 12){
30311                     label.style = "width: " + this.labelWidth + 'px';
30312                 }
30313
30314                 if(this.labelWidth < 13 && this.labelmd == 0){
30315                     this.labelmd = this.labelWidth;
30316                 }
30317
30318                 if(this.labellg > 0){
30319                     labelCls = ' col-lg-' + this.labellg;
30320                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30321                 }
30322
30323                 if(this.labelmd > 0){
30324                     labelCls = ' col-md-' + this.labelmd;
30325                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30326                 }
30327
30328                 if(this.labelsm > 0){
30329                     labelCls = ' col-sm-' + this.labelsm;
30330                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30331                 }
30332
30333                 if(this.labelxs > 0){
30334                     labelCls = ' col-xs-' + this.labelxs;
30335                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30336                 }
30337             }
30338             
30339             label.cls += ' ' + labelCls;
30340             
30341             cfg.cn.push(label);
30342         }
30343         
30344         Roo.each(['day', 'month', 'year'], function(t){
30345             cfg.cn.push({
30346                 tag : 'div',
30347                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30348             });
30349         }, this);
30350         
30351         return cfg;
30352     },
30353     
30354     inputEl: function ()
30355     {
30356         return this.el.select('.roo-date-split-field-group-value', true).first();
30357     },
30358     
30359     onRender : function(ct, position) 
30360     {
30361         var _this = this;
30362         
30363         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30364         
30365         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30366         
30367         this.dayField = new Roo.bootstrap.ComboBox({
30368             allowBlank : this.dayAllowBlank,
30369             alwaysQuery : true,
30370             displayField : 'value',
30371             editable : false,
30372             fieldLabel : '',
30373             forceSelection : true,
30374             mode : 'local',
30375             placeholder : this.dayPlaceholder,
30376             selectOnFocus : true,
30377             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30378             triggerAction : 'all',
30379             typeAhead : true,
30380             valueField : 'value',
30381             store : new Roo.data.SimpleStore({
30382                 data : (function() {    
30383                     var days = [];
30384                     _this.fireEvent('days', _this, days);
30385                     return days;
30386                 })(),
30387                 fields : [ 'value' ]
30388             }),
30389             listeners : {
30390                 select : function (_self, record, index)
30391                 {
30392                     _this.setValue(_this.getValue());
30393                 }
30394             }
30395         });
30396
30397         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30398         
30399         this.monthField = new Roo.bootstrap.MonthField({
30400             after : '<i class=\"fa fa-calendar\"></i>',
30401             allowBlank : this.monthAllowBlank,
30402             placeholder : this.monthPlaceholder,
30403             readOnly : true,
30404             listeners : {
30405                 render : function (_self)
30406                 {
30407                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30408                         e.preventDefault();
30409                         _self.focus();
30410                     });
30411                 },
30412                 select : function (_self, oldvalue, newvalue)
30413                 {
30414                     _this.setValue(_this.getValue());
30415                 }
30416             }
30417         });
30418         
30419         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30420         
30421         this.yearField = new Roo.bootstrap.ComboBox({
30422             allowBlank : this.yearAllowBlank,
30423             alwaysQuery : true,
30424             displayField : 'value',
30425             editable : false,
30426             fieldLabel : '',
30427             forceSelection : true,
30428             mode : 'local',
30429             placeholder : this.yearPlaceholder,
30430             selectOnFocus : true,
30431             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30432             triggerAction : 'all',
30433             typeAhead : true,
30434             valueField : 'value',
30435             store : new Roo.data.SimpleStore({
30436                 data : (function() {
30437                     var years = [];
30438                     _this.fireEvent('years', _this, years);
30439                     return years;
30440                 })(),
30441                 fields : [ 'value' ]
30442             }),
30443             listeners : {
30444                 select : function (_self, record, index)
30445                 {
30446                     _this.setValue(_this.getValue());
30447                 }
30448             }
30449         });
30450
30451         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30452     },
30453     
30454     setValue : function(v, format)
30455     {
30456         this.inputEl.dom.value = v;
30457         
30458         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30459         
30460         var d = Date.parseDate(v, f);
30461         
30462         if(!d){
30463             this.validate();
30464             return;
30465         }
30466         
30467         this.setDay(d.format(this.dayFormat));
30468         this.setMonth(d.format(this.monthFormat));
30469         this.setYear(d.format(this.yearFormat));
30470         
30471         this.validate();
30472         
30473         return;
30474     },
30475     
30476     setDay : function(v)
30477     {
30478         this.dayField.setValue(v);
30479         this.inputEl.dom.value = this.getValue();
30480         this.validate();
30481         return;
30482     },
30483     
30484     setMonth : function(v)
30485     {
30486         this.monthField.setValue(v, true);
30487         this.inputEl.dom.value = this.getValue();
30488         this.validate();
30489         return;
30490     },
30491     
30492     setYear : function(v)
30493     {
30494         this.yearField.setValue(v);
30495         this.inputEl.dom.value = this.getValue();
30496         this.validate();
30497         return;
30498     },
30499     
30500     getDay : function()
30501     {
30502         return this.dayField.getValue();
30503     },
30504     
30505     getMonth : function()
30506     {
30507         return this.monthField.getValue();
30508     },
30509     
30510     getYear : function()
30511     {
30512         return this.yearField.getValue();
30513     },
30514     
30515     getValue : function()
30516     {
30517         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30518         
30519         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30520         
30521         return date;
30522     },
30523     
30524     reset : function()
30525     {
30526         this.setDay('');
30527         this.setMonth('');
30528         this.setYear('');
30529         this.inputEl.dom.value = '';
30530         this.validate();
30531         return;
30532     },
30533     
30534     validate : function()
30535     {
30536         var d = this.dayField.validate();
30537         var m = this.monthField.validate();
30538         var y = this.yearField.validate();
30539         
30540         var valid = true;
30541         
30542         if(
30543                 (!this.dayAllowBlank && !d) ||
30544                 (!this.monthAllowBlank && !m) ||
30545                 (!this.yearAllowBlank && !y)
30546         ){
30547             valid = false;
30548         }
30549         
30550         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30551             return valid;
30552         }
30553         
30554         if(valid){
30555             this.markValid();
30556             return valid;
30557         }
30558         
30559         this.markInvalid();
30560         
30561         return valid;
30562     },
30563     
30564     markValid : function()
30565     {
30566         
30567         var label = this.el.select('label', true).first();
30568         var icon = this.el.select('i.fa-star', true).first();
30569
30570         if(label && icon){
30571             icon.remove();
30572         }
30573         
30574         this.fireEvent('valid', this);
30575     },
30576     
30577      /**
30578      * Mark this field as invalid
30579      * @param {String} msg The validation message
30580      */
30581     markInvalid : function(msg)
30582     {
30583         
30584         var label = this.el.select('label', true).first();
30585         var icon = this.el.select('i.fa-star', true).first();
30586
30587         if(label && !icon){
30588             this.el.select('.roo-date-split-field-label', true).createChild({
30589                 tag : 'i',
30590                 cls : 'text-danger fa fa-lg fa-star',
30591                 tooltip : 'This field is required',
30592                 style : 'margin-right:5px;'
30593             }, label, true);
30594         }
30595         
30596         this.fireEvent('invalid', this, msg);
30597     },
30598     
30599     clearInvalid : function()
30600     {
30601         var label = this.el.select('label', true).first();
30602         var icon = this.el.select('i.fa-star', true).first();
30603
30604         if(label && icon){
30605             icon.remove();
30606         }
30607         
30608         this.fireEvent('valid', this);
30609     },
30610     
30611     getName: function()
30612     {
30613         return this.name;
30614     }
30615     
30616 });
30617
30618  /**
30619  *
30620  * This is based on 
30621  * http://masonry.desandro.com
30622  *
30623  * The idea is to render all the bricks based on vertical width...
30624  *
30625  * The original code extends 'outlayer' - we might need to use that....
30626  * 
30627  */
30628
30629
30630 /**
30631  * @class Roo.bootstrap.LayoutMasonry
30632  * @extends Roo.bootstrap.Component
30633  * Bootstrap Layout Masonry class
30634  * 
30635  * @constructor
30636  * Create a new Element
30637  * @param {Object} config The config object
30638  */
30639
30640 Roo.bootstrap.LayoutMasonry = function(config){
30641     
30642     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30643     
30644     this.bricks = [];
30645     
30646     Roo.bootstrap.LayoutMasonry.register(this);
30647     
30648     this.addEvents({
30649         // raw events
30650         /**
30651          * @event layout
30652          * Fire after layout the items
30653          * @param {Roo.bootstrap.LayoutMasonry} this
30654          * @param {Roo.EventObject} e
30655          */
30656         "layout" : true
30657     });
30658     
30659 };
30660
30661 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30662     
30663     /**
30664      * @cfg {Boolean} isLayoutInstant = no animation?
30665      */   
30666     isLayoutInstant : false, // needed?
30667    
30668     /**
30669      * @cfg {Number} boxWidth  width of the columns
30670      */   
30671     boxWidth : 450,
30672     
30673       /**
30674      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30675      */   
30676     boxHeight : 0,
30677     
30678     /**
30679      * @cfg {Number} padWidth padding below box..
30680      */   
30681     padWidth : 10, 
30682     
30683     /**
30684      * @cfg {Number} gutter gutter width..
30685      */   
30686     gutter : 10,
30687     
30688      /**
30689      * @cfg {Number} maxCols maximum number of columns
30690      */   
30691     
30692     maxCols: 0,
30693     
30694     /**
30695      * @cfg {Boolean} isAutoInitial defalut true
30696      */   
30697     isAutoInitial : true, 
30698     
30699     containerWidth: 0,
30700     
30701     /**
30702      * @cfg {Boolean} isHorizontal defalut false
30703      */   
30704     isHorizontal : false, 
30705
30706     currentSize : null,
30707     
30708     tag: 'div',
30709     
30710     cls: '',
30711     
30712     bricks: null, //CompositeElement
30713     
30714     cols : 1,
30715     
30716     _isLayoutInited : false,
30717     
30718 //    isAlternative : false, // only use for vertical layout...
30719     
30720     /**
30721      * @cfg {Number} alternativePadWidth padding below box..
30722      */   
30723     alternativePadWidth : 50,
30724     
30725     selectedBrick : [],
30726     
30727     getAutoCreate : function(){
30728         
30729         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30730         
30731         var cfg = {
30732             tag: this.tag,
30733             cls: 'blog-masonary-wrapper ' + this.cls,
30734             cn : {
30735                 cls : 'mas-boxes masonary'
30736             }
30737         };
30738         
30739         return cfg;
30740     },
30741     
30742     getChildContainer: function( )
30743     {
30744         if (this.boxesEl) {
30745             return this.boxesEl;
30746         }
30747         
30748         this.boxesEl = this.el.select('.mas-boxes').first();
30749         
30750         return this.boxesEl;
30751     },
30752     
30753     
30754     initEvents : function()
30755     {
30756         var _this = this;
30757         
30758         if(this.isAutoInitial){
30759             Roo.log('hook children rendered');
30760             this.on('childrenrendered', function() {
30761                 Roo.log('children rendered');
30762                 _this.initial();
30763             } ,this);
30764         }
30765     },
30766     
30767     initial : function()
30768     {
30769         this.selectedBrick = [];
30770         
30771         this.currentSize = this.el.getBox(true);
30772         
30773         Roo.EventManager.onWindowResize(this.resize, this); 
30774
30775         if(!this.isAutoInitial){
30776             this.layout();
30777             return;
30778         }
30779         
30780         this.layout();
30781         
30782         return;
30783         //this.layout.defer(500,this);
30784         
30785     },
30786     
30787     resize : function()
30788     {
30789         var cs = this.el.getBox(true);
30790         
30791         if (
30792                 this.currentSize.width == cs.width && 
30793                 this.currentSize.x == cs.x && 
30794                 this.currentSize.height == cs.height && 
30795                 this.currentSize.y == cs.y 
30796         ) {
30797             Roo.log("no change in with or X or Y");
30798             return;
30799         }
30800         
30801         this.currentSize = cs;
30802         
30803         this.layout();
30804         
30805     },
30806     
30807     layout : function()
30808     {   
30809         this._resetLayout();
30810         
30811         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30812         
30813         this.layoutItems( isInstant );
30814       
30815         this._isLayoutInited = true;
30816         
30817         this.fireEvent('layout', this);
30818         
30819     },
30820     
30821     _resetLayout : function()
30822     {
30823         if(this.isHorizontal){
30824             this.horizontalMeasureColumns();
30825             return;
30826         }
30827         
30828         this.verticalMeasureColumns();
30829         
30830     },
30831     
30832     verticalMeasureColumns : function()
30833     {
30834         this.getContainerWidth();
30835         
30836 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30837 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30838 //            return;
30839 //        }
30840         
30841         var boxWidth = this.boxWidth + this.padWidth;
30842         
30843         if(this.containerWidth < this.boxWidth){
30844             boxWidth = this.containerWidth
30845         }
30846         
30847         var containerWidth = this.containerWidth;
30848         
30849         var cols = Math.floor(containerWidth / boxWidth);
30850         
30851         this.cols = Math.max( cols, 1 );
30852         
30853         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30854         
30855         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30856         
30857         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30858         
30859         this.colWidth = boxWidth + avail - this.padWidth;
30860         
30861         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30862         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30863     },
30864     
30865     horizontalMeasureColumns : function()
30866     {
30867         this.getContainerWidth();
30868         
30869         var boxWidth = this.boxWidth;
30870         
30871         if(this.containerWidth < boxWidth){
30872             boxWidth = this.containerWidth;
30873         }
30874         
30875         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30876         
30877         this.el.setHeight(boxWidth);
30878         
30879     },
30880     
30881     getContainerWidth : function()
30882     {
30883         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30884     },
30885     
30886     layoutItems : function( isInstant )
30887     {
30888         Roo.log(this.bricks);
30889         
30890         var items = Roo.apply([], this.bricks);
30891         
30892         if(this.isHorizontal){
30893             this._horizontalLayoutItems( items , isInstant );
30894             return;
30895         }
30896         
30897 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30898 //            this._verticalAlternativeLayoutItems( items , isInstant );
30899 //            return;
30900 //        }
30901         
30902         this._verticalLayoutItems( items , isInstant );
30903         
30904     },
30905     
30906     _verticalLayoutItems : function ( items , isInstant)
30907     {
30908         if ( !items || !items.length ) {
30909             return;
30910         }
30911         
30912         var standard = [
30913             ['xs', 'xs', 'xs', 'tall'],
30914             ['xs', 'xs', 'tall'],
30915             ['xs', 'xs', 'sm'],
30916             ['xs', 'xs', 'xs'],
30917             ['xs', 'tall'],
30918             ['xs', 'sm'],
30919             ['xs', 'xs'],
30920             ['xs'],
30921             
30922             ['sm', 'xs', 'xs'],
30923             ['sm', 'xs'],
30924             ['sm'],
30925             
30926             ['tall', 'xs', 'xs', 'xs'],
30927             ['tall', 'xs', 'xs'],
30928             ['tall', 'xs'],
30929             ['tall']
30930             
30931         ];
30932         
30933         var queue = [];
30934         
30935         var boxes = [];
30936         
30937         var box = [];
30938         
30939         Roo.each(items, function(item, k){
30940             
30941             switch (item.size) {
30942                 // these layouts take up a full box,
30943                 case 'md' :
30944                 case 'md-left' :
30945                 case 'md-right' :
30946                 case 'wide' :
30947                     
30948                     if(box.length){
30949                         boxes.push(box);
30950                         box = [];
30951                     }
30952                     
30953                     boxes.push([item]);
30954                     
30955                     break;
30956                     
30957                 case 'xs' :
30958                 case 'sm' :
30959                 case 'tall' :
30960                     
30961                     box.push(item);
30962                     
30963                     break;
30964                 default :
30965                     break;
30966                     
30967             }
30968             
30969         }, this);
30970         
30971         if(box.length){
30972             boxes.push(box);
30973             box = [];
30974         }
30975         
30976         var filterPattern = function(box, length)
30977         {
30978             if(!box.length){
30979                 return;
30980             }
30981             
30982             var match = false;
30983             
30984             var pattern = box.slice(0, length);
30985             
30986             var format = [];
30987             
30988             Roo.each(pattern, function(i){
30989                 format.push(i.size);
30990             }, this);
30991             
30992             Roo.each(standard, function(s){
30993                 
30994                 if(String(s) != String(format)){
30995                     return;
30996                 }
30997                 
30998                 match = true;
30999                 return false;
31000                 
31001             }, this);
31002             
31003             if(!match && length == 1){
31004                 return;
31005             }
31006             
31007             if(!match){
31008                 filterPattern(box, length - 1);
31009                 return;
31010             }
31011                 
31012             queue.push(pattern);
31013
31014             box = box.slice(length, box.length);
31015
31016             filterPattern(box, 4);
31017
31018             return;
31019             
31020         }
31021         
31022         Roo.each(boxes, function(box, k){
31023             
31024             if(!box.length){
31025                 return;
31026             }
31027             
31028             if(box.length == 1){
31029                 queue.push(box);
31030                 return;
31031             }
31032             
31033             filterPattern(box, 4);
31034             
31035         }, this);
31036         
31037         this._processVerticalLayoutQueue( queue, isInstant );
31038         
31039     },
31040     
31041 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31042 //    {
31043 //        if ( !items || !items.length ) {
31044 //            return;
31045 //        }
31046 //
31047 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31048 //        
31049 //    },
31050     
31051     _horizontalLayoutItems : function ( items , isInstant)
31052     {
31053         if ( !items || !items.length || items.length < 3) {
31054             return;
31055         }
31056         
31057         items.reverse();
31058         
31059         var eItems = items.slice(0, 3);
31060         
31061         items = items.slice(3, items.length);
31062         
31063         var standard = [
31064             ['xs', 'xs', 'xs', 'wide'],
31065             ['xs', 'xs', 'wide'],
31066             ['xs', 'xs', 'sm'],
31067             ['xs', 'xs', 'xs'],
31068             ['xs', 'wide'],
31069             ['xs', 'sm'],
31070             ['xs', 'xs'],
31071             ['xs'],
31072             
31073             ['sm', 'xs', 'xs'],
31074             ['sm', 'xs'],
31075             ['sm'],
31076             
31077             ['wide', 'xs', 'xs', 'xs'],
31078             ['wide', 'xs', 'xs'],
31079             ['wide', 'xs'],
31080             ['wide'],
31081             
31082             ['wide-thin']
31083         ];
31084         
31085         var queue = [];
31086         
31087         var boxes = [];
31088         
31089         var box = [];
31090         
31091         Roo.each(items, function(item, k){
31092             
31093             switch (item.size) {
31094                 case 'md' :
31095                 case 'md-left' :
31096                 case 'md-right' :
31097                 case 'tall' :
31098                     
31099                     if(box.length){
31100                         boxes.push(box);
31101                         box = [];
31102                     }
31103                     
31104                     boxes.push([item]);
31105                     
31106                     break;
31107                     
31108                 case 'xs' :
31109                 case 'sm' :
31110                 case 'wide' :
31111                 case 'wide-thin' :
31112                     
31113                     box.push(item);
31114                     
31115                     break;
31116                 default :
31117                     break;
31118                     
31119             }
31120             
31121         }, this);
31122         
31123         if(box.length){
31124             boxes.push(box);
31125             box = [];
31126         }
31127         
31128         var filterPattern = function(box, length)
31129         {
31130             if(!box.length){
31131                 return;
31132             }
31133             
31134             var match = false;
31135             
31136             var pattern = box.slice(0, length);
31137             
31138             var format = [];
31139             
31140             Roo.each(pattern, function(i){
31141                 format.push(i.size);
31142             }, this);
31143             
31144             Roo.each(standard, function(s){
31145                 
31146                 if(String(s) != String(format)){
31147                     return;
31148                 }
31149                 
31150                 match = true;
31151                 return false;
31152                 
31153             }, this);
31154             
31155             if(!match && length == 1){
31156                 return;
31157             }
31158             
31159             if(!match){
31160                 filterPattern(box, length - 1);
31161                 return;
31162             }
31163                 
31164             queue.push(pattern);
31165
31166             box = box.slice(length, box.length);
31167
31168             filterPattern(box, 4);
31169
31170             return;
31171             
31172         }
31173         
31174         Roo.each(boxes, function(box, k){
31175             
31176             if(!box.length){
31177                 return;
31178             }
31179             
31180             if(box.length == 1){
31181                 queue.push(box);
31182                 return;
31183             }
31184             
31185             filterPattern(box, 4);
31186             
31187         }, this);
31188         
31189         
31190         var prune = [];
31191         
31192         var pos = this.el.getBox(true);
31193         
31194         var minX = pos.x;
31195         
31196         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31197         
31198         var hit_end = false;
31199         
31200         Roo.each(queue, function(box){
31201             
31202             if(hit_end){
31203                 
31204                 Roo.each(box, function(b){
31205                 
31206                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31207                     b.el.hide();
31208
31209                 }, this);
31210
31211                 return;
31212             }
31213             
31214             var mx = 0;
31215             
31216             Roo.each(box, function(b){
31217                 
31218                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31219                 b.el.show();
31220
31221                 mx = Math.max(mx, b.x);
31222                 
31223             }, this);
31224             
31225             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31226             
31227             if(maxX < minX){
31228                 
31229                 Roo.each(box, function(b){
31230                 
31231                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31232                     b.el.hide();
31233                     
31234                 }, this);
31235                 
31236                 hit_end = true;
31237                 
31238                 return;
31239             }
31240             
31241             prune.push(box);
31242             
31243         }, this);
31244         
31245         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31246     },
31247     
31248     /** Sets position of item in DOM
31249     * @param {Element} item
31250     * @param {Number} x - horizontal position
31251     * @param {Number} y - vertical position
31252     * @param {Boolean} isInstant - disables transitions
31253     */
31254     _processVerticalLayoutQueue : function( queue, isInstant )
31255     {
31256         var pos = this.el.getBox(true);
31257         var x = pos.x;
31258         var y = pos.y;
31259         var maxY = [];
31260         
31261         for (var i = 0; i < this.cols; i++){
31262             maxY[i] = pos.y;
31263         }
31264         
31265         Roo.each(queue, function(box, k){
31266             
31267             var col = k % this.cols;
31268             
31269             Roo.each(box, function(b,kk){
31270                 
31271                 b.el.position('absolute');
31272                 
31273                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31274                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31275                 
31276                 if(b.size == 'md-left' || b.size == 'md-right'){
31277                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31278                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31279                 }
31280                 
31281                 b.el.setWidth(width);
31282                 b.el.setHeight(height);
31283                 // iframe?
31284                 b.el.select('iframe',true).setSize(width,height);
31285                 
31286             }, this);
31287             
31288             for (var i = 0; i < this.cols; i++){
31289                 
31290                 if(maxY[i] < maxY[col]){
31291                     col = i;
31292                     continue;
31293                 }
31294                 
31295                 col = Math.min(col, i);
31296                 
31297             }
31298             
31299             x = pos.x + col * (this.colWidth + this.padWidth);
31300             
31301             y = maxY[col];
31302             
31303             var positions = [];
31304             
31305             switch (box.length){
31306                 case 1 :
31307                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31308                     break;
31309                 case 2 :
31310                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31311                     break;
31312                 case 3 :
31313                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31314                     break;
31315                 case 4 :
31316                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31317                     break;
31318                 default :
31319                     break;
31320             }
31321             
31322             Roo.each(box, function(b,kk){
31323                 
31324                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31325                 
31326                 var sz = b.el.getSize();
31327                 
31328                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31329                 
31330             }, this);
31331             
31332         }, this);
31333         
31334         var mY = 0;
31335         
31336         for (var i = 0; i < this.cols; i++){
31337             mY = Math.max(mY, maxY[i]);
31338         }
31339         
31340         this.el.setHeight(mY - pos.y);
31341         
31342     },
31343     
31344 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31345 //    {
31346 //        var pos = this.el.getBox(true);
31347 //        var x = pos.x;
31348 //        var y = pos.y;
31349 //        var maxX = pos.right;
31350 //        
31351 //        var maxHeight = 0;
31352 //        
31353 //        Roo.each(items, function(item, k){
31354 //            
31355 //            var c = k % 2;
31356 //            
31357 //            item.el.position('absolute');
31358 //                
31359 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31360 //
31361 //            item.el.setWidth(width);
31362 //
31363 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31364 //
31365 //            item.el.setHeight(height);
31366 //            
31367 //            if(c == 0){
31368 //                item.el.setXY([x, y], isInstant ? false : true);
31369 //            } else {
31370 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31371 //            }
31372 //            
31373 //            y = y + height + this.alternativePadWidth;
31374 //            
31375 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31376 //            
31377 //        }, this);
31378 //        
31379 //        this.el.setHeight(maxHeight);
31380 //        
31381 //    },
31382     
31383     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31384     {
31385         var pos = this.el.getBox(true);
31386         
31387         var minX = pos.x;
31388         var minY = pos.y;
31389         
31390         var maxX = pos.right;
31391         
31392         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31393         
31394         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31395         
31396         Roo.each(queue, function(box, k){
31397             
31398             Roo.each(box, function(b, kk){
31399                 
31400                 b.el.position('absolute');
31401                 
31402                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31403                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31404                 
31405                 if(b.size == 'md-left' || b.size == 'md-right'){
31406                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31407                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31408                 }
31409                 
31410                 b.el.setWidth(width);
31411                 b.el.setHeight(height);
31412                 
31413             }, this);
31414             
31415             if(!box.length){
31416                 return;
31417             }
31418             
31419             var positions = [];
31420             
31421             switch (box.length){
31422                 case 1 :
31423                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31424                     break;
31425                 case 2 :
31426                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31427                     break;
31428                 case 3 :
31429                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31430                     break;
31431                 case 4 :
31432                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31433                     break;
31434                 default :
31435                     break;
31436             }
31437             
31438             Roo.each(box, function(b,kk){
31439                 
31440                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31441                 
31442                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31443                 
31444             }, this);
31445             
31446         }, this);
31447         
31448     },
31449     
31450     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31451     {
31452         Roo.each(eItems, function(b,k){
31453             
31454             b.size = (k == 0) ? 'sm' : 'xs';
31455             b.x = (k == 0) ? 2 : 1;
31456             b.y = (k == 0) ? 2 : 1;
31457             
31458             b.el.position('absolute');
31459             
31460             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31461                 
31462             b.el.setWidth(width);
31463             
31464             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31465             
31466             b.el.setHeight(height);
31467             
31468         }, this);
31469
31470         var positions = [];
31471         
31472         positions.push({
31473             x : maxX - this.unitWidth * 2 - this.gutter,
31474             y : minY
31475         });
31476         
31477         positions.push({
31478             x : maxX - this.unitWidth,
31479             y : minY + (this.unitWidth + this.gutter) * 2
31480         });
31481         
31482         positions.push({
31483             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31484             y : minY
31485         });
31486         
31487         Roo.each(eItems, function(b,k){
31488             
31489             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31490
31491         }, this);
31492         
31493     },
31494     
31495     getVerticalOneBoxColPositions : function(x, y, box)
31496     {
31497         var pos = [];
31498         
31499         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31500         
31501         if(box[0].size == 'md-left'){
31502             rand = 0;
31503         }
31504         
31505         if(box[0].size == 'md-right'){
31506             rand = 1;
31507         }
31508         
31509         pos.push({
31510             x : x + (this.unitWidth + this.gutter) * rand,
31511             y : y
31512         });
31513         
31514         return pos;
31515     },
31516     
31517     getVerticalTwoBoxColPositions : function(x, y, box)
31518     {
31519         var pos = [];
31520         
31521         if(box[0].size == 'xs'){
31522             
31523             pos.push({
31524                 x : x,
31525                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31526             });
31527
31528             pos.push({
31529                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31530                 y : y
31531             });
31532             
31533             return pos;
31534             
31535         }
31536         
31537         pos.push({
31538             x : x,
31539             y : y
31540         });
31541
31542         pos.push({
31543             x : x + (this.unitWidth + this.gutter) * 2,
31544             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31545         });
31546         
31547         return pos;
31548         
31549     },
31550     
31551     getVerticalThreeBoxColPositions : function(x, y, box)
31552     {
31553         var pos = [];
31554         
31555         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31556             
31557             pos.push({
31558                 x : x,
31559                 y : y
31560             });
31561
31562             pos.push({
31563                 x : x + (this.unitWidth + this.gutter) * 1,
31564                 y : y
31565             });
31566             
31567             pos.push({
31568                 x : x + (this.unitWidth + this.gutter) * 2,
31569                 y : y
31570             });
31571             
31572             return pos;
31573             
31574         }
31575         
31576         if(box[0].size == 'xs' && box[1].size == 'xs'){
31577             
31578             pos.push({
31579                 x : x,
31580                 y : y
31581             });
31582
31583             pos.push({
31584                 x : x,
31585                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31586             });
31587             
31588             pos.push({
31589                 x : x + (this.unitWidth + this.gutter) * 1,
31590                 y : y
31591             });
31592             
31593             return pos;
31594             
31595         }
31596         
31597         pos.push({
31598             x : x,
31599             y : y
31600         });
31601
31602         pos.push({
31603             x : x + (this.unitWidth + this.gutter) * 2,
31604             y : y
31605         });
31606
31607         pos.push({
31608             x : x + (this.unitWidth + this.gutter) * 2,
31609             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31610         });
31611             
31612         return pos;
31613         
31614     },
31615     
31616     getVerticalFourBoxColPositions : function(x, y, box)
31617     {
31618         var pos = [];
31619         
31620         if(box[0].size == 'xs'){
31621             
31622             pos.push({
31623                 x : x,
31624                 y : y
31625             });
31626
31627             pos.push({
31628                 x : x,
31629                 y : y + (this.unitHeight + this.gutter) * 1
31630             });
31631             
31632             pos.push({
31633                 x : x,
31634                 y : y + (this.unitHeight + this.gutter) * 2
31635             });
31636             
31637             pos.push({
31638                 x : x + (this.unitWidth + this.gutter) * 1,
31639                 y : y
31640             });
31641             
31642             return pos;
31643             
31644         }
31645         
31646         pos.push({
31647             x : x,
31648             y : y
31649         });
31650
31651         pos.push({
31652             x : x + (this.unitWidth + this.gutter) * 2,
31653             y : y
31654         });
31655
31656         pos.push({
31657             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31658             y : y + (this.unitHeight + this.gutter) * 1
31659         });
31660
31661         pos.push({
31662             x : x + (this.unitWidth + this.gutter) * 2,
31663             y : y + (this.unitWidth + this.gutter) * 2
31664         });
31665
31666         return pos;
31667         
31668     },
31669     
31670     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31671     {
31672         var pos = [];
31673         
31674         if(box[0].size == 'md-left'){
31675             pos.push({
31676                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31677                 y : minY
31678             });
31679             
31680             return pos;
31681         }
31682         
31683         if(box[0].size == 'md-right'){
31684             pos.push({
31685                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31686                 y : minY + (this.unitWidth + this.gutter) * 1
31687             });
31688             
31689             return pos;
31690         }
31691         
31692         var rand = Math.floor(Math.random() * (4 - box[0].y));
31693         
31694         pos.push({
31695             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31696             y : minY + (this.unitWidth + this.gutter) * rand
31697         });
31698         
31699         return pos;
31700         
31701     },
31702     
31703     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31704     {
31705         var pos = [];
31706         
31707         if(box[0].size == 'xs'){
31708             
31709             pos.push({
31710                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31711                 y : minY
31712             });
31713
31714             pos.push({
31715                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31716                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31717             });
31718             
31719             return pos;
31720             
31721         }
31722         
31723         pos.push({
31724             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31725             y : minY
31726         });
31727
31728         pos.push({
31729             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31730             y : minY + (this.unitWidth + this.gutter) * 2
31731         });
31732         
31733         return pos;
31734         
31735     },
31736     
31737     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31738     {
31739         var pos = [];
31740         
31741         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31742             
31743             pos.push({
31744                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31745                 y : minY
31746             });
31747
31748             pos.push({
31749                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31750                 y : minY + (this.unitWidth + this.gutter) * 1
31751             });
31752             
31753             pos.push({
31754                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31755                 y : minY + (this.unitWidth + this.gutter) * 2
31756             });
31757             
31758             return pos;
31759             
31760         }
31761         
31762         if(box[0].size == 'xs' && box[1].size == 'xs'){
31763             
31764             pos.push({
31765                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31766                 y : minY
31767             });
31768
31769             pos.push({
31770                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31771                 y : minY
31772             });
31773             
31774             pos.push({
31775                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31776                 y : minY + (this.unitWidth + this.gutter) * 1
31777             });
31778             
31779             return pos;
31780             
31781         }
31782         
31783         pos.push({
31784             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31785             y : minY
31786         });
31787
31788         pos.push({
31789             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31790             y : minY + (this.unitWidth + this.gutter) * 2
31791         });
31792
31793         pos.push({
31794             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31795             y : minY + (this.unitWidth + this.gutter) * 2
31796         });
31797             
31798         return pos;
31799         
31800     },
31801     
31802     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31803     {
31804         var pos = [];
31805         
31806         if(box[0].size == 'xs'){
31807             
31808             pos.push({
31809                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31810                 y : minY
31811             });
31812
31813             pos.push({
31814                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31815                 y : minY
31816             });
31817             
31818             pos.push({
31819                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31820                 y : minY
31821             });
31822             
31823             pos.push({
31824                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31825                 y : minY + (this.unitWidth + this.gutter) * 1
31826             });
31827             
31828             return pos;
31829             
31830         }
31831         
31832         pos.push({
31833             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31834             y : minY
31835         });
31836         
31837         pos.push({
31838             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31839             y : minY + (this.unitWidth + this.gutter) * 2
31840         });
31841         
31842         pos.push({
31843             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31844             y : minY + (this.unitWidth + this.gutter) * 2
31845         });
31846         
31847         pos.push({
31848             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31849             y : minY + (this.unitWidth + this.gutter) * 2
31850         });
31851
31852         return pos;
31853         
31854     },
31855     
31856     /**
31857     * remove a Masonry Brick
31858     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31859     */
31860     removeBrick : function(brick_id)
31861     {
31862         if (!brick_id) {
31863             return;
31864         }
31865         
31866         for (var i = 0; i<this.bricks.length; i++) {
31867             if (this.bricks[i].id == brick_id) {
31868                 this.bricks.splice(i,1);
31869                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31870                 this.initial();
31871             }
31872         }
31873     },
31874     
31875     /**
31876     * adds a Masonry Brick
31877     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31878     */
31879     addBrick : function(cfg)
31880     {
31881         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31882         //this.register(cn);
31883         cn.parentId = this.id;
31884         cn.onRender(this.el, null);
31885         return cn;
31886     },
31887     
31888     /**
31889     * register a Masonry Brick
31890     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31891     */
31892     
31893     register : function(brick)
31894     {
31895         this.bricks.push(brick);
31896         brick.masonryId = this.id;
31897     },
31898     
31899     /**
31900     * clear all the Masonry Brick
31901     */
31902     clearAll : function()
31903     {
31904         this.bricks = [];
31905         //this.getChildContainer().dom.innerHTML = "";
31906         this.el.dom.innerHTML = '';
31907     },
31908     
31909     getSelected : function()
31910     {
31911         if (!this.selectedBrick) {
31912             return false;
31913         }
31914         
31915         return this.selectedBrick;
31916     }
31917 });
31918
31919 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31920     
31921     groups: {},
31922      /**
31923     * register a Masonry Layout
31924     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31925     */
31926     
31927     register : function(layout)
31928     {
31929         this.groups[layout.id] = layout;
31930     },
31931     /**
31932     * fetch a  Masonry Layout based on the masonry layout ID
31933     * @param {string} the masonry layout to add
31934     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31935     */
31936     
31937     get: function(layout_id) {
31938         if (typeof(this.groups[layout_id]) == 'undefined') {
31939             return false;
31940         }
31941         return this.groups[layout_id] ;
31942     }
31943     
31944     
31945     
31946 });
31947
31948  
31949
31950  /**
31951  *
31952  * This is based on 
31953  * http://masonry.desandro.com
31954  *
31955  * The idea is to render all the bricks based on vertical width...
31956  *
31957  * The original code extends 'outlayer' - we might need to use that....
31958  * 
31959  */
31960
31961
31962 /**
31963  * @class Roo.bootstrap.LayoutMasonryAuto
31964  * @extends Roo.bootstrap.Component
31965  * Bootstrap Layout Masonry class
31966  * 
31967  * @constructor
31968  * Create a new Element
31969  * @param {Object} config The config object
31970  */
31971
31972 Roo.bootstrap.LayoutMasonryAuto = function(config){
31973     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31974 };
31975
31976 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31977     
31978       /**
31979      * @cfg {Boolean} isFitWidth  - resize the width..
31980      */   
31981     isFitWidth : false,  // options..
31982     /**
31983      * @cfg {Boolean} isOriginLeft = left align?
31984      */   
31985     isOriginLeft : true,
31986     /**
31987      * @cfg {Boolean} isOriginTop = top align?
31988      */   
31989     isOriginTop : false,
31990     /**
31991      * @cfg {Boolean} isLayoutInstant = no animation?
31992      */   
31993     isLayoutInstant : false, // needed?
31994     /**
31995      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31996      */   
31997     isResizingContainer : true,
31998     /**
31999      * @cfg {Number} columnWidth  width of the columns 
32000      */   
32001     
32002     columnWidth : 0,
32003     
32004     /**
32005      * @cfg {Number} maxCols maximum number of columns
32006      */   
32007     
32008     maxCols: 0,
32009     /**
32010      * @cfg {Number} padHeight padding below box..
32011      */   
32012     
32013     padHeight : 10, 
32014     
32015     /**
32016      * @cfg {Boolean} isAutoInitial defalut true
32017      */   
32018     
32019     isAutoInitial : true, 
32020     
32021     // private?
32022     gutter : 0,
32023     
32024     containerWidth: 0,
32025     initialColumnWidth : 0,
32026     currentSize : null,
32027     
32028     colYs : null, // array.
32029     maxY : 0,
32030     padWidth: 10,
32031     
32032     
32033     tag: 'div',
32034     cls: '',
32035     bricks: null, //CompositeElement
32036     cols : 0, // array?
32037     // element : null, // wrapped now this.el
32038     _isLayoutInited : null, 
32039     
32040     
32041     getAutoCreate : function(){
32042         
32043         var cfg = {
32044             tag: this.tag,
32045             cls: 'blog-masonary-wrapper ' + this.cls,
32046             cn : {
32047                 cls : 'mas-boxes masonary'
32048             }
32049         };
32050         
32051         return cfg;
32052     },
32053     
32054     getChildContainer: function( )
32055     {
32056         if (this.boxesEl) {
32057             return this.boxesEl;
32058         }
32059         
32060         this.boxesEl = this.el.select('.mas-boxes').first();
32061         
32062         return this.boxesEl;
32063     },
32064     
32065     
32066     initEvents : function()
32067     {
32068         var _this = this;
32069         
32070         if(this.isAutoInitial){
32071             Roo.log('hook children rendered');
32072             this.on('childrenrendered', function() {
32073                 Roo.log('children rendered');
32074                 _this.initial();
32075             } ,this);
32076         }
32077         
32078     },
32079     
32080     initial : function()
32081     {
32082         this.reloadItems();
32083
32084         this.currentSize = this.el.getBox(true);
32085
32086         /// was window resize... - let's see if this works..
32087         Roo.EventManager.onWindowResize(this.resize, this); 
32088
32089         if(!this.isAutoInitial){
32090             this.layout();
32091             return;
32092         }
32093         
32094         this.layout.defer(500,this);
32095     },
32096     
32097     reloadItems: function()
32098     {
32099         this.bricks = this.el.select('.masonry-brick', true);
32100         
32101         this.bricks.each(function(b) {
32102             //Roo.log(b.getSize());
32103             if (!b.attr('originalwidth')) {
32104                 b.attr('originalwidth',  b.getSize().width);
32105             }
32106             
32107         });
32108         
32109         Roo.log(this.bricks.elements.length);
32110     },
32111     
32112     resize : function()
32113     {
32114         Roo.log('resize');
32115         var cs = this.el.getBox(true);
32116         
32117         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32118             Roo.log("no change in with or X");
32119             return;
32120         }
32121         this.currentSize = cs;
32122         this.layout();
32123     },
32124     
32125     layout : function()
32126     {
32127          Roo.log('layout');
32128         this._resetLayout();
32129         //this._manageStamps();
32130       
32131         // don't animate first layout
32132         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32133         this.layoutItems( isInstant );
32134       
32135         // flag for initalized
32136         this._isLayoutInited = true;
32137     },
32138     
32139     layoutItems : function( isInstant )
32140     {
32141         //var items = this._getItemsForLayout( this.items );
32142         // original code supports filtering layout items.. we just ignore it..
32143         
32144         this._layoutItems( this.bricks , isInstant );
32145       
32146         this._postLayout();
32147     },
32148     _layoutItems : function ( items , isInstant)
32149     {
32150        //this.fireEvent( 'layout', this, items );
32151     
32152
32153         if ( !items || !items.elements.length ) {
32154           // no items, emit event with empty array
32155             return;
32156         }
32157
32158         var queue = [];
32159         items.each(function(item) {
32160             Roo.log("layout item");
32161             Roo.log(item);
32162             // get x/y object from method
32163             var position = this._getItemLayoutPosition( item );
32164             // enqueue
32165             position.item = item;
32166             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32167             queue.push( position );
32168         }, this);
32169       
32170         this._processLayoutQueue( queue );
32171     },
32172     /** Sets position of item in DOM
32173     * @param {Element} item
32174     * @param {Number} x - horizontal position
32175     * @param {Number} y - vertical position
32176     * @param {Boolean} isInstant - disables transitions
32177     */
32178     _processLayoutQueue : function( queue )
32179     {
32180         for ( var i=0, len = queue.length; i < len; i++ ) {
32181             var obj = queue[i];
32182             obj.item.position('absolute');
32183             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32184         }
32185     },
32186       
32187     
32188     /**
32189     * Any logic you want to do after each layout,
32190     * i.e. size the container
32191     */
32192     _postLayout : function()
32193     {
32194         this.resizeContainer();
32195     },
32196     
32197     resizeContainer : function()
32198     {
32199         if ( !this.isResizingContainer ) {
32200             return;
32201         }
32202         var size = this._getContainerSize();
32203         if ( size ) {
32204             this.el.setSize(size.width,size.height);
32205             this.boxesEl.setSize(size.width,size.height);
32206         }
32207     },
32208     
32209     
32210     
32211     _resetLayout : function()
32212     {
32213         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32214         this.colWidth = this.el.getWidth();
32215         //this.gutter = this.el.getWidth(); 
32216         
32217         this.measureColumns();
32218
32219         // reset column Y
32220         var i = this.cols;
32221         this.colYs = [];
32222         while (i--) {
32223             this.colYs.push( 0 );
32224         }
32225     
32226         this.maxY = 0;
32227     },
32228
32229     measureColumns : function()
32230     {
32231         this.getContainerWidth();
32232       // if columnWidth is 0, default to outerWidth of first item
32233         if ( !this.columnWidth ) {
32234             var firstItem = this.bricks.first();
32235             Roo.log(firstItem);
32236             this.columnWidth  = this.containerWidth;
32237             if (firstItem && firstItem.attr('originalwidth') ) {
32238                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32239             }
32240             // columnWidth fall back to item of first element
32241             Roo.log("set column width?");
32242                         this.initialColumnWidth = this.columnWidth  ;
32243
32244             // if first elem has no width, default to size of container
32245             
32246         }
32247         
32248         
32249         if (this.initialColumnWidth) {
32250             this.columnWidth = this.initialColumnWidth;
32251         }
32252         
32253         
32254             
32255         // column width is fixed at the top - however if container width get's smaller we should
32256         // reduce it...
32257         
32258         // this bit calcs how man columns..
32259             
32260         var columnWidth = this.columnWidth += this.gutter;
32261       
32262         // calculate columns
32263         var containerWidth = this.containerWidth + this.gutter;
32264         
32265         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32266         // fix rounding errors, typically with gutters
32267         var excess = columnWidth - containerWidth % columnWidth;
32268         
32269         
32270         // if overshoot is less than a pixel, round up, otherwise floor it
32271         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32272         cols = Math[ mathMethod ]( cols );
32273         this.cols = Math.max( cols, 1 );
32274         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32275         
32276          // padding positioning..
32277         var totalColWidth = this.cols * this.columnWidth;
32278         var padavail = this.containerWidth - totalColWidth;
32279         // so for 2 columns - we need 3 'pads'
32280         
32281         var padNeeded = (1+this.cols) * this.padWidth;
32282         
32283         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32284         
32285         this.columnWidth += padExtra
32286         //this.padWidth = Math.floor(padavail /  ( this.cols));
32287         
32288         // adjust colum width so that padding is fixed??
32289         
32290         // we have 3 columns ... total = width * 3
32291         // we have X left over... that should be used by 
32292         
32293         //if (this.expandC) {
32294             
32295         //}
32296         
32297         
32298         
32299     },
32300     
32301     getContainerWidth : function()
32302     {
32303        /* // container is parent if fit width
32304         var container = this.isFitWidth ? this.element.parentNode : this.element;
32305         // check that this.size and size are there
32306         // IE8 triggers resize on body size change, so they might not be
32307         
32308         var size = getSize( container );  //FIXME
32309         this.containerWidth = size && size.innerWidth; //FIXME
32310         */
32311          
32312         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32313         
32314     },
32315     
32316     _getItemLayoutPosition : function( item )  // what is item?
32317     {
32318         // we resize the item to our columnWidth..
32319       
32320         item.setWidth(this.columnWidth);
32321         item.autoBoxAdjust  = false;
32322         
32323         var sz = item.getSize();
32324  
32325         // how many columns does this brick span
32326         var remainder = this.containerWidth % this.columnWidth;
32327         
32328         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32329         // round if off by 1 pixel, otherwise use ceil
32330         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32331         colSpan = Math.min( colSpan, this.cols );
32332         
32333         // normally this should be '1' as we dont' currently allow multi width columns..
32334         
32335         var colGroup = this._getColGroup( colSpan );
32336         // get the minimum Y value from the columns
32337         var minimumY = Math.min.apply( Math, colGroup );
32338         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32339         
32340         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32341          
32342         // position the brick
32343         var position = {
32344             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32345             y: this.currentSize.y + minimumY + this.padHeight
32346         };
32347         
32348         Roo.log(position);
32349         // apply setHeight to necessary columns
32350         var setHeight = minimumY + sz.height + this.padHeight;
32351         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32352         
32353         var setSpan = this.cols + 1 - colGroup.length;
32354         for ( var i = 0; i < setSpan; i++ ) {
32355           this.colYs[ shortColIndex + i ] = setHeight ;
32356         }
32357       
32358         return position;
32359     },
32360     
32361     /**
32362      * @param {Number} colSpan - number of columns the element spans
32363      * @returns {Array} colGroup
32364      */
32365     _getColGroup : function( colSpan )
32366     {
32367         if ( colSpan < 2 ) {
32368           // if brick spans only one column, use all the column Ys
32369           return this.colYs;
32370         }
32371       
32372         var colGroup = [];
32373         // how many different places could this brick fit horizontally
32374         var groupCount = this.cols + 1 - colSpan;
32375         // for each group potential horizontal position
32376         for ( var i = 0; i < groupCount; i++ ) {
32377           // make an array of colY values for that one group
32378           var groupColYs = this.colYs.slice( i, i + colSpan );
32379           // and get the max value of the array
32380           colGroup[i] = Math.max.apply( Math, groupColYs );
32381         }
32382         return colGroup;
32383     },
32384     /*
32385     _manageStamp : function( stamp )
32386     {
32387         var stampSize =  stamp.getSize();
32388         var offset = stamp.getBox();
32389         // get the columns that this stamp affects
32390         var firstX = this.isOriginLeft ? offset.x : offset.right;
32391         var lastX = firstX + stampSize.width;
32392         var firstCol = Math.floor( firstX / this.columnWidth );
32393         firstCol = Math.max( 0, firstCol );
32394         
32395         var lastCol = Math.floor( lastX / this.columnWidth );
32396         // lastCol should not go over if multiple of columnWidth #425
32397         lastCol -= lastX % this.columnWidth ? 0 : 1;
32398         lastCol = Math.min( this.cols - 1, lastCol );
32399         
32400         // set colYs to bottom of the stamp
32401         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32402             stampSize.height;
32403             
32404         for ( var i = firstCol; i <= lastCol; i++ ) {
32405           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32406         }
32407     },
32408     */
32409     
32410     _getContainerSize : function()
32411     {
32412         this.maxY = Math.max.apply( Math, this.colYs );
32413         var size = {
32414             height: this.maxY
32415         };
32416       
32417         if ( this.isFitWidth ) {
32418             size.width = this._getContainerFitWidth();
32419         }
32420       
32421         return size;
32422     },
32423     
32424     _getContainerFitWidth : function()
32425     {
32426         var unusedCols = 0;
32427         // count unused columns
32428         var i = this.cols;
32429         while ( --i ) {
32430           if ( this.colYs[i] !== 0 ) {
32431             break;
32432           }
32433           unusedCols++;
32434         }
32435         // fit container to columns that have been used
32436         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32437     },
32438     
32439     needsResizeLayout : function()
32440     {
32441         var previousWidth = this.containerWidth;
32442         this.getContainerWidth();
32443         return previousWidth !== this.containerWidth;
32444     }
32445  
32446 });
32447
32448  
32449
32450  /*
32451  * - LGPL
32452  *
32453  * element
32454  * 
32455  */
32456
32457 /**
32458  * @class Roo.bootstrap.MasonryBrick
32459  * @extends Roo.bootstrap.Component
32460  * Bootstrap MasonryBrick class
32461  * 
32462  * @constructor
32463  * Create a new MasonryBrick
32464  * @param {Object} config The config object
32465  */
32466
32467 Roo.bootstrap.MasonryBrick = function(config){
32468     
32469     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32470     
32471     Roo.bootstrap.MasonryBrick.register(this);
32472     
32473     this.addEvents({
32474         // raw events
32475         /**
32476          * @event click
32477          * When a MasonryBrick is clcik
32478          * @param {Roo.bootstrap.MasonryBrick} this
32479          * @param {Roo.EventObject} e
32480          */
32481         "click" : true
32482     });
32483 };
32484
32485 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32486     
32487     /**
32488      * @cfg {String} title
32489      */   
32490     title : '',
32491     /**
32492      * @cfg {String} html
32493      */   
32494     html : '',
32495     /**
32496      * @cfg {String} bgimage
32497      */   
32498     bgimage : '',
32499     /**
32500      * @cfg {String} videourl
32501      */   
32502     videourl : '',
32503     /**
32504      * @cfg {String} cls
32505      */   
32506     cls : '',
32507     /**
32508      * @cfg {String} href
32509      */   
32510     href : '',
32511     /**
32512      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32513      */   
32514     size : 'xs',
32515     
32516     /**
32517      * @cfg {String} placetitle (center|bottom)
32518      */   
32519     placetitle : '',
32520     
32521     /**
32522      * @cfg {Boolean} isFitContainer defalut true
32523      */   
32524     isFitContainer : true, 
32525     
32526     /**
32527      * @cfg {Boolean} preventDefault defalut false
32528      */   
32529     preventDefault : false, 
32530     
32531     /**
32532      * @cfg {Boolean} inverse defalut false
32533      */   
32534     maskInverse : false, 
32535     
32536     getAutoCreate : function()
32537     {
32538         if(!this.isFitContainer){
32539             return this.getSplitAutoCreate();
32540         }
32541         
32542         var cls = 'masonry-brick masonry-brick-full';
32543         
32544         if(this.href.length){
32545             cls += ' masonry-brick-link';
32546         }
32547         
32548         if(this.bgimage.length){
32549             cls += ' masonry-brick-image';
32550         }
32551         
32552         if(this.maskInverse){
32553             cls += ' mask-inverse';
32554         }
32555         
32556         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32557             cls += ' enable-mask';
32558         }
32559         
32560         if(this.size){
32561             cls += ' masonry-' + this.size + '-brick';
32562         }
32563         
32564         if(this.placetitle.length){
32565             
32566             switch (this.placetitle) {
32567                 case 'center' :
32568                     cls += ' masonry-center-title';
32569                     break;
32570                 case 'bottom' :
32571                     cls += ' masonry-bottom-title';
32572                     break;
32573                 default:
32574                     break;
32575             }
32576             
32577         } else {
32578             if(!this.html.length && !this.bgimage.length){
32579                 cls += ' masonry-center-title';
32580             }
32581
32582             if(!this.html.length && this.bgimage.length){
32583                 cls += ' masonry-bottom-title';
32584             }
32585         }
32586         
32587         if(this.cls){
32588             cls += ' ' + this.cls;
32589         }
32590         
32591         var cfg = {
32592             tag: (this.href.length) ? 'a' : 'div',
32593             cls: cls,
32594             cn: [
32595                 {
32596                     tag: 'div',
32597                     cls: 'masonry-brick-mask'
32598                 },
32599                 {
32600                     tag: 'div',
32601                     cls: 'masonry-brick-paragraph',
32602                     cn: []
32603                 }
32604             ]
32605         };
32606         
32607         if(this.href.length){
32608             cfg.href = this.href;
32609         }
32610         
32611         var cn = cfg.cn[1].cn;
32612         
32613         if(this.title.length){
32614             cn.push({
32615                 tag: 'h4',
32616                 cls: 'masonry-brick-title',
32617                 html: this.title
32618             });
32619         }
32620         
32621         if(this.html.length){
32622             cn.push({
32623                 tag: 'p',
32624                 cls: 'masonry-brick-text',
32625                 html: this.html
32626             });
32627         }
32628         
32629         if (!this.title.length && !this.html.length) {
32630             cfg.cn[1].cls += ' hide';
32631         }
32632         
32633         if(this.bgimage.length){
32634             cfg.cn.push({
32635                 tag: 'img',
32636                 cls: 'masonry-brick-image-view',
32637                 src: this.bgimage
32638             });
32639         }
32640         
32641         if(this.videourl.length){
32642             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32643             // youtube support only?
32644             cfg.cn.push({
32645                 tag: 'iframe',
32646                 cls: 'masonry-brick-image-view',
32647                 src: vurl,
32648                 frameborder : 0,
32649                 allowfullscreen : true
32650             });
32651         }
32652         
32653         return cfg;
32654         
32655     },
32656     
32657     getSplitAutoCreate : function()
32658     {
32659         var cls = 'masonry-brick masonry-brick-split';
32660         
32661         if(this.href.length){
32662             cls += ' masonry-brick-link';
32663         }
32664         
32665         if(this.bgimage.length){
32666             cls += ' masonry-brick-image';
32667         }
32668         
32669         if(this.size){
32670             cls += ' masonry-' + this.size + '-brick';
32671         }
32672         
32673         switch (this.placetitle) {
32674             case 'center' :
32675                 cls += ' masonry-center-title';
32676                 break;
32677             case 'bottom' :
32678                 cls += ' masonry-bottom-title';
32679                 break;
32680             default:
32681                 if(!this.bgimage.length){
32682                     cls += ' masonry-center-title';
32683                 }
32684
32685                 if(this.bgimage.length){
32686                     cls += ' masonry-bottom-title';
32687                 }
32688                 break;
32689         }
32690         
32691         if(this.cls){
32692             cls += ' ' + this.cls;
32693         }
32694         
32695         var cfg = {
32696             tag: (this.href.length) ? 'a' : 'div',
32697             cls: cls,
32698             cn: [
32699                 {
32700                     tag: 'div',
32701                     cls: 'masonry-brick-split-head',
32702                     cn: [
32703                         {
32704                             tag: 'div',
32705                             cls: 'masonry-brick-paragraph',
32706                             cn: []
32707                         }
32708                     ]
32709                 },
32710                 {
32711                     tag: 'div',
32712                     cls: 'masonry-brick-split-body',
32713                     cn: []
32714                 }
32715             ]
32716         };
32717         
32718         if(this.href.length){
32719             cfg.href = this.href;
32720         }
32721         
32722         if(this.title.length){
32723             cfg.cn[0].cn[0].cn.push({
32724                 tag: 'h4',
32725                 cls: 'masonry-brick-title',
32726                 html: this.title
32727             });
32728         }
32729         
32730         if(this.html.length){
32731             cfg.cn[1].cn.push({
32732                 tag: 'p',
32733                 cls: 'masonry-brick-text',
32734                 html: this.html
32735             });
32736         }
32737
32738         if(this.bgimage.length){
32739             cfg.cn[0].cn.push({
32740                 tag: 'img',
32741                 cls: 'masonry-brick-image-view',
32742                 src: this.bgimage
32743             });
32744         }
32745         
32746         if(this.videourl.length){
32747             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32748             // youtube support only?
32749             cfg.cn[0].cn.cn.push({
32750                 tag: 'iframe',
32751                 cls: 'masonry-brick-image-view',
32752                 src: vurl,
32753                 frameborder : 0,
32754                 allowfullscreen : true
32755             });
32756         }
32757         
32758         return cfg;
32759     },
32760     
32761     initEvents: function() 
32762     {
32763         switch (this.size) {
32764             case 'xs' :
32765                 this.x = 1;
32766                 this.y = 1;
32767                 break;
32768             case 'sm' :
32769                 this.x = 2;
32770                 this.y = 2;
32771                 break;
32772             case 'md' :
32773             case 'md-left' :
32774             case 'md-right' :
32775                 this.x = 3;
32776                 this.y = 3;
32777                 break;
32778             case 'tall' :
32779                 this.x = 2;
32780                 this.y = 3;
32781                 break;
32782             case 'wide' :
32783                 this.x = 3;
32784                 this.y = 2;
32785                 break;
32786             case 'wide-thin' :
32787                 this.x = 3;
32788                 this.y = 1;
32789                 break;
32790                         
32791             default :
32792                 break;
32793         }
32794         
32795         if(Roo.isTouch){
32796             this.el.on('touchstart', this.onTouchStart, this);
32797             this.el.on('touchmove', this.onTouchMove, this);
32798             this.el.on('touchend', this.onTouchEnd, this);
32799             this.el.on('contextmenu', this.onContextMenu, this);
32800         } else {
32801             this.el.on('mouseenter'  ,this.enter, this);
32802             this.el.on('mouseleave', this.leave, this);
32803             this.el.on('click', this.onClick, this);
32804         }
32805         
32806         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32807             this.parent().bricks.push(this);   
32808         }
32809         
32810     },
32811     
32812     onClick: function(e, el)
32813     {
32814         var time = this.endTimer - this.startTimer;
32815         // Roo.log(e.preventDefault());
32816         if(Roo.isTouch){
32817             if(time > 1000){
32818                 e.preventDefault();
32819                 return;
32820             }
32821         }
32822         
32823         if(!this.preventDefault){
32824             return;
32825         }
32826         
32827         e.preventDefault();
32828         
32829         if (this.activeClass != '') {
32830             this.selectBrick();
32831         }
32832         
32833         this.fireEvent('click', this, e);
32834     },
32835     
32836     enter: function(e, el)
32837     {
32838         e.preventDefault();
32839         
32840         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32841             return;
32842         }
32843         
32844         if(this.bgimage.length && this.html.length){
32845             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32846         }
32847     },
32848     
32849     leave: function(e, el)
32850     {
32851         e.preventDefault();
32852         
32853         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32854             return;
32855         }
32856         
32857         if(this.bgimage.length && this.html.length){
32858             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32859         }
32860     },
32861     
32862     onTouchStart: function(e, el)
32863     {
32864 //        e.preventDefault();
32865         
32866         this.touchmoved = false;
32867         
32868         if(!this.isFitContainer){
32869             return;
32870         }
32871         
32872         if(!this.bgimage.length || !this.html.length){
32873             return;
32874         }
32875         
32876         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32877         
32878         this.timer = new Date().getTime();
32879         
32880     },
32881     
32882     onTouchMove: function(e, el)
32883     {
32884         this.touchmoved = true;
32885     },
32886     
32887     onContextMenu : function(e,el)
32888     {
32889         e.preventDefault();
32890         e.stopPropagation();
32891         return false;
32892     },
32893     
32894     onTouchEnd: function(e, el)
32895     {
32896 //        e.preventDefault();
32897         
32898         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32899         
32900             this.leave(e,el);
32901             
32902             return;
32903         }
32904         
32905         if(!this.bgimage.length || !this.html.length){
32906             
32907             if(this.href.length){
32908                 window.location.href = this.href;
32909             }
32910             
32911             return;
32912         }
32913         
32914         if(!this.isFitContainer){
32915             return;
32916         }
32917         
32918         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32919         
32920         window.location.href = this.href;
32921     },
32922     
32923     //selection on single brick only
32924     selectBrick : function() {
32925         
32926         if (!this.parentId) {
32927             return;
32928         }
32929         
32930         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32931         var index = m.selectedBrick.indexOf(this.id);
32932         
32933         if ( index > -1) {
32934             m.selectedBrick.splice(index,1);
32935             this.el.removeClass(this.activeClass);
32936             return;
32937         }
32938         
32939         for(var i = 0; i < m.selectedBrick.length; i++) {
32940             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32941             b.el.removeClass(b.activeClass);
32942         }
32943         
32944         m.selectedBrick = [];
32945         
32946         m.selectedBrick.push(this.id);
32947         this.el.addClass(this.activeClass);
32948         return;
32949     },
32950     
32951     isSelected : function(){
32952         return this.el.hasClass(this.activeClass);
32953         
32954     }
32955 });
32956
32957 Roo.apply(Roo.bootstrap.MasonryBrick, {
32958     
32959     //groups: {},
32960     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32961      /**
32962     * register a Masonry Brick
32963     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32964     */
32965     
32966     register : function(brick)
32967     {
32968         //this.groups[brick.id] = brick;
32969         this.groups.add(brick.id, brick);
32970     },
32971     /**
32972     * fetch a  masonry brick based on the masonry brick ID
32973     * @param {string} the masonry brick to add
32974     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32975     */
32976     
32977     get: function(brick_id) 
32978     {
32979         // if (typeof(this.groups[brick_id]) == 'undefined') {
32980         //     return false;
32981         // }
32982         // return this.groups[brick_id] ;
32983         
32984         if(this.groups.key(brick_id)) {
32985             return this.groups.key(brick_id);
32986         }
32987         
32988         return false;
32989     }
32990     
32991     
32992     
32993 });
32994
32995  /*
32996  * - LGPL
32997  *
32998  * element
32999  * 
33000  */
33001
33002 /**
33003  * @class Roo.bootstrap.Brick
33004  * @extends Roo.bootstrap.Component
33005  * Bootstrap Brick class
33006  * 
33007  * @constructor
33008  * Create a new Brick
33009  * @param {Object} config The config object
33010  */
33011
33012 Roo.bootstrap.Brick = function(config){
33013     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33014     
33015     this.addEvents({
33016         // raw events
33017         /**
33018          * @event click
33019          * When a Brick is click
33020          * @param {Roo.bootstrap.Brick} this
33021          * @param {Roo.EventObject} e
33022          */
33023         "click" : true
33024     });
33025 };
33026
33027 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
33028     
33029     /**
33030      * @cfg {String} title
33031      */   
33032     title : '',
33033     /**
33034      * @cfg {String} html
33035      */   
33036     html : '',
33037     /**
33038      * @cfg {String} bgimage
33039      */   
33040     bgimage : '',
33041     /**
33042      * @cfg {String} cls
33043      */   
33044     cls : '',
33045     /**
33046      * @cfg {String} href
33047      */   
33048     href : '',
33049     /**
33050      * @cfg {String} video
33051      */   
33052     video : '',
33053     /**
33054      * @cfg {Boolean} square
33055      */   
33056     square : true,
33057     
33058     getAutoCreate : function()
33059     {
33060         var cls = 'roo-brick';
33061         
33062         if(this.href.length){
33063             cls += ' roo-brick-link';
33064         }
33065         
33066         if(this.bgimage.length){
33067             cls += ' roo-brick-image';
33068         }
33069         
33070         if(!this.html.length && !this.bgimage.length){
33071             cls += ' roo-brick-center-title';
33072         }
33073         
33074         if(!this.html.length && this.bgimage.length){
33075             cls += ' roo-brick-bottom-title';
33076         }
33077         
33078         if(this.cls){
33079             cls += ' ' + this.cls;
33080         }
33081         
33082         var cfg = {
33083             tag: (this.href.length) ? 'a' : 'div',
33084             cls: cls,
33085             cn: [
33086                 {
33087                     tag: 'div',
33088                     cls: 'roo-brick-paragraph',
33089                     cn: []
33090                 }
33091             ]
33092         };
33093         
33094         if(this.href.length){
33095             cfg.href = this.href;
33096         }
33097         
33098         var cn = cfg.cn[0].cn;
33099         
33100         if(this.title.length){
33101             cn.push({
33102                 tag: 'h4',
33103                 cls: 'roo-brick-title',
33104                 html: this.title
33105             });
33106         }
33107         
33108         if(this.html.length){
33109             cn.push({
33110                 tag: 'p',
33111                 cls: 'roo-brick-text',
33112                 html: this.html
33113             });
33114         } else {
33115             cn.cls += ' hide';
33116         }
33117         
33118         if(this.bgimage.length){
33119             cfg.cn.push({
33120                 tag: 'img',
33121                 cls: 'roo-brick-image-view',
33122                 src: this.bgimage
33123             });
33124         }
33125         
33126         return cfg;
33127     },
33128     
33129     initEvents: function() 
33130     {
33131         if(this.title.length || this.html.length){
33132             this.el.on('mouseenter'  ,this.enter, this);
33133             this.el.on('mouseleave', this.leave, this);
33134         }
33135         
33136         Roo.EventManager.onWindowResize(this.resize, this); 
33137         
33138         if(this.bgimage.length){
33139             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33140             this.imageEl.on('load', this.onImageLoad, this);
33141             return;
33142         }
33143         
33144         this.resize();
33145     },
33146     
33147     onImageLoad : function()
33148     {
33149         this.resize();
33150     },
33151     
33152     resize : function()
33153     {
33154         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33155         
33156         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33157         
33158         if(this.bgimage.length){
33159             var image = this.el.select('.roo-brick-image-view', true).first();
33160             
33161             image.setWidth(paragraph.getWidth());
33162             
33163             if(this.square){
33164                 image.setHeight(paragraph.getWidth());
33165             }
33166             
33167             this.el.setHeight(image.getHeight());
33168             paragraph.setHeight(image.getHeight());
33169             
33170         }
33171         
33172     },
33173     
33174     enter: function(e, el)
33175     {
33176         e.preventDefault();
33177         
33178         if(this.bgimage.length){
33179             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33180             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33181         }
33182     },
33183     
33184     leave: function(e, el)
33185     {
33186         e.preventDefault();
33187         
33188         if(this.bgimage.length){
33189             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33190             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33191         }
33192     }
33193     
33194 });
33195
33196  
33197
33198  /*
33199  * - LGPL
33200  *
33201  * Number field 
33202  */
33203
33204 /**
33205  * @class Roo.bootstrap.NumberField
33206  * @extends Roo.bootstrap.Input
33207  * Bootstrap NumberField class
33208  * 
33209  * 
33210  * 
33211  * 
33212  * @constructor
33213  * Create a new NumberField
33214  * @param {Object} config The config object
33215  */
33216
33217 Roo.bootstrap.NumberField = function(config){
33218     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33219 };
33220
33221 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33222     
33223     /**
33224      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33225      */
33226     allowDecimals : true,
33227     /**
33228      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33229      */
33230     decimalSeparator : ".",
33231     /**
33232      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33233      */
33234     decimalPrecision : 2,
33235     /**
33236      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33237      */
33238     allowNegative : true,
33239     
33240     /**
33241      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33242      */
33243     allowZero: true,
33244     /**
33245      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33246      */
33247     minValue : Number.NEGATIVE_INFINITY,
33248     /**
33249      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33250      */
33251     maxValue : Number.MAX_VALUE,
33252     /**
33253      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33254      */
33255     minText : "The minimum value for this field is {0}",
33256     /**
33257      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33258      */
33259     maxText : "The maximum value for this field is {0}",
33260     /**
33261      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33262      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33263      */
33264     nanText : "{0} is not a valid number",
33265     /**
33266      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33267      */
33268     thousandsDelimiter : false,
33269     /**
33270      * @cfg {String} valueAlign alignment of value
33271      */
33272     valueAlign : "left",
33273
33274     getAutoCreate : function()
33275     {
33276         var hiddenInput = {
33277             tag: 'input',
33278             type: 'hidden',
33279             id: Roo.id(),
33280             cls: 'hidden-number-input'
33281         };
33282         
33283         if (this.name) {
33284             hiddenInput.name = this.name;
33285         }
33286         
33287         this.name = '';
33288         
33289         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33290         
33291         this.name = hiddenInput.name;
33292         
33293         if(cfg.cn.length > 0) {
33294             cfg.cn.push(hiddenInput);
33295         }
33296         
33297         return cfg;
33298     },
33299
33300     // private
33301     initEvents : function()
33302     {   
33303         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33304         
33305         var allowed = "0123456789";
33306         
33307         if(this.allowDecimals){
33308             allowed += this.decimalSeparator;
33309         }
33310         
33311         if(this.allowNegative){
33312             allowed += "-";
33313         }
33314         
33315         if(this.thousandsDelimiter) {
33316             allowed += ",";
33317         }
33318         
33319         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33320         
33321         var keyPress = function(e){
33322             
33323             var k = e.getKey();
33324             
33325             var c = e.getCharCode();
33326             
33327             if(
33328                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33329                     allowed.indexOf(String.fromCharCode(c)) === -1
33330             ){
33331                 e.stopEvent();
33332                 return;
33333             }
33334             
33335             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33336                 return;
33337             }
33338             
33339             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33340                 e.stopEvent();
33341             }
33342         };
33343         
33344         this.el.on("keypress", keyPress, this);
33345     },
33346     
33347     validateValue : function(value)
33348     {
33349         
33350         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33351             return false;
33352         }
33353         
33354         var num = this.parseValue(value);
33355         
33356         if(isNaN(num)){
33357             this.markInvalid(String.format(this.nanText, value));
33358             return false;
33359         }
33360         
33361         if(num < this.minValue){
33362             this.markInvalid(String.format(this.minText, this.minValue));
33363             return false;
33364         }
33365         
33366         if(num > this.maxValue){
33367             this.markInvalid(String.format(this.maxText, this.maxValue));
33368             return false;
33369         }
33370         
33371         return true;
33372     },
33373
33374     getValue : function()
33375     {
33376         var v = this.hiddenEl().getValue();
33377         
33378         return this.fixPrecision(this.parseValue(v));
33379     },
33380
33381     parseValue : function(value)
33382     {
33383         if(this.thousandsDelimiter) {
33384             value += "";
33385             r = new RegExp(",", "g");
33386             value = value.replace(r, "");
33387         }
33388         
33389         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33390         return isNaN(value) ? '' : value;
33391     },
33392
33393     fixPrecision : function(value)
33394     {
33395         if(this.thousandsDelimiter) {
33396             value += "";
33397             r = new RegExp(",", "g");
33398             value = value.replace(r, "");
33399         }
33400         
33401         var nan = isNaN(value);
33402         
33403         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33404             return nan ? '' : value;
33405         }
33406         return parseFloat(value).toFixed(this.decimalPrecision);
33407     },
33408
33409     setValue : function(v)
33410     {
33411         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33412         
33413         this.value = v;
33414         
33415         if(this.rendered){
33416             
33417             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33418             
33419             this.inputEl().dom.value = (v == '') ? '' :
33420                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33421             
33422             if(!this.allowZero && v === '0') {
33423                 this.hiddenEl().dom.value = '';
33424                 this.inputEl().dom.value = '';
33425             }
33426             
33427             this.validate();
33428         }
33429     },
33430
33431     decimalPrecisionFcn : function(v)
33432     {
33433         return Math.floor(v);
33434     },
33435
33436     beforeBlur : function()
33437     {
33438         var v = this.parseValue(this.getRawValue());
33439         
33440         if(v || v === 0 || v === ''){
33441             this.setValue(v);
33442         }
33443     },
33444     
33445     hiddenEl : function()
33446     {
33447         return this.el.select('input.hidden-number-input',true).first();
33448     }
33449     
33450 });
33451
33452  
33453
33454 /*
33455 * Licence: LGPL
33456 */
33457
33458 /**
33459  * @class Roo.bootstrap.DocumentSlider
33460  * @extends Roo.bootstrap.Component
33461  * Bootstrap DocumentSlider class
33462  * 
33463  * @constructor
33464  * Create a new DocumentViewer
33465  * @param {Object} config The config object
33466  */
33467
33468 Roo.bootstrap.DocumentSlider = function(config){
33469     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33470     
33471     this.files = [];
33472     
33473     this.addEvents({
33474         /**
33475          * @event initial
33476          * Fire after initEvent
33477          * @param {Roo.bootstrap.DocumentSlider} this
33478          */
33479         "initial" : true,
33480         /**
33481          * @event update
33482          * Fire after update
33483          * @param {Roo.bootstrap.DocumentSlider} this
33484          */
33485         "update" : true,
33486         /**
33487          * @event click
33488          * Fire after click
33489          * @param {Roo.bootstrap.DocumentSlider} this
33490          */
33491         "click" : true
33492     });
33493 };
33494
33495 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33496     
33497     files : false,
33498     
33499     indicator : 0,
33500     
33501     getAutoCreate : function()
33502     {
33503         var cfg = {
33504             tag : 'div',
33505             cls : 'roo-document-slider',
33506             cn : [
33507                 {
33508                     tag : 'div',
33509                     cls : 'roo-document-slider-header',
33510                     cn : [
33511                         {
33512                             tag : 'div',
33513                             cls : 'roo-document-slider-header-title'
33514                         }
33515                     ]
33516                 },
33517                 {
33518                     tag : 'div',
33519                     cls : 'roo-document-slider-body',
33520                     cn : [
33521                         {
33522                             tag : 'div',
33523                             cls : 'roo-document-slider-prev',
33524                             cn : [
33525                                 {
33526                                     tag : 'i',
33527                                     cls : 'fa fa-chevron-left'
33528                                 }
33529                             ]
33530                         },
33531                         {
33532                             tag : 'div',
33533                             cls : 'roo-document-slider-thumb',
33534                             cn : [
33535                                 {
33536                                     tag : 'img',
33537                                     cls : 'roo-document-slider-image'
33538                                 }
33539                             ]
33540                         },
33541                         {
33542                             tag : 'div',
33543                             cls : 'roo-document-slider-next',
33544                             cn : [
33545                                 {
33546                                     tag : 'i',
33547                                     cls : 'fa fa-chevron-right'
33548                                 }
33549                             ]
33550                         }
33551                     ]
33552                 }
33553             ]
33554         };
33555         
33556         return cfg;
33557     },
33558     
33559     initEvents : function()
33560     {
33561         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33562         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33563         
33564         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33565         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33566         
33567         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33568         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33569         
33570         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33571         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33572         
33573         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33574         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33575         
33576         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33577         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33578         
33579         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33580         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33581         
33582         this.thumbEl.on('click', this.onClick, this);
33583         
33584         this.prevIndicator.on('click', this.prev, this);
33585         
33586         this.nextIndicator.on('click', this.next, this);
33587         
33588     },
33589     
33590     initial : function()
33591     {
33592         if(this.files.length){
33593             this.indicator = 1;
33594             this.update()
33595         }
33596         
33597         this.fireEvent('initial', this);
33598     },
33599     
33600     update : function()
33601     {
33602         this.imageEl.attr('src', this.files[this.indicator - 1]);
33603         
33604         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33605         
33606         this.prevIndicator.show();
33607         
33608         if(this.indicator == 1){
33609             this.prevIndicator.hide();
33610         }
33611         
33612         this.nextIndicator.show();
33613         
33614         if(this.indicator == this.files.length){
33615             this.nextIndicator.hide();
33616         }
33617         
33618         this.thumbEl.scrollTo('top');
33619         
33620         this.fireEvent('update', this);
33621     },
33622     
33623     onClick : function(e)
33624     {
33625         e.preventDefault();
33626         
33627         this.fireEvent('click', this);
33628     },
33629     
33630     prev : function(e)
33631     {
33632         e.preventDefault();
33633         
33634         this.indicator = Math.max(1, this.indicator - 1);
33635         
33636         this.update();
33637     },
33638     
33639     next : function(e)
33640     {
33641         e.preventDefault();
33642         
33643         this.indicator = Math.min(this.files.length, this.indicator + 1);
33644         
33645         this.update();
33646     }
33647 });
33648 /*
33649  * - LGPL
33650  *
33651  * RadioSet
33652  *
33653  *
33654  */
33655
33656 /**
33657  * @class Roo.bootstrap.RadioSet
33658  * @extends Roo.bootstrap.Input
33659  * Bootstrap RadioSet class
33660  * @cfg {String} indicatorpos (left|right) default left
33661  * @cfg {Boolean} inline (true|false) inline the element (default true)
33662  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33663  * @constructor
33664  * Create a new RadioSet
33665  * @param {Object} config The config object
33666  */
33667
33668 Roo.bootstrap.RadioSet = function(config){
33669     
33670     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33671     
33672     this.radioes = [];
33673     
33674     Roo.bootstrap.RadioSet.register(this);
33675     
33676     this.addEvents({
33677         /**
33678         * @event check
33679         * Fires when the element is checked or unchecked.
33680         * @param {Roo.bootstrap.RadioSet} this This radio
33681         * @param {Roo.bootstrap.Radio} item The checked item
33682         */
33683        check : true,
33684        /**
33685         * @event click
33686         * Fires when the element is click.
33687         * @param {Roo.bootstrap.RadioSet} this This radio set
33688         * @param {Roo.bootstrap.Radio} item The checked item
33689         * @param {Roo.EventObject} e The event object
33690         */
33691        click : true
33692     });
33693     
33694 };
33695
33696 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33697
33698     radioes : false,
33699     
33700     inline : true,
33701     
33702     weight : '',
33703     
33704     indicatorpos : 'left',
33705     
33706     getAutoCreate : function()
33707     {
33708         var label = {
33709             tag : 'label',
33710             cls : 'roo-radio-set-label',
33711             cn : [
33712                 {
33713                     tag : 'span',
33714                     html : this.fieldLabel
33715                 }
33716             ]
33717         };
33718         
33719         if(this.indicatorpos == 'left'){
33720             label.cn.unshift({
33721                 tag : 'i',
33722                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33723                 tooltip : 'This field is required'
33724             });
33725         } else {
33726             label.cn.push({
33727                 tag : 'i',
33728                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33729                 tooltip : 'This field is required'
33730             });
33731         }
33732         
33733         var items = {
33734             tag : 'div',
33735             cls : 'roo-radio-set-items'
33736         };
33737         
33738         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33739         
33740         if (align === 'left' && this.fieldLabel.length) {
33741             
33742             items = {
33743                 cls : "roo-radio-set-right", 
33744                 cn: [
33745                     items
33746                 ]
33747             };
33748             
33749             if(this.labelWidth > 12){
33750                 label.style = "width: " + this.labelWidth + 'px';
33751             }
33752             
33753             if(this.labelWidth < 13 && this.labelmd == 0){
33754                 this.labelmd = this.labelWidth;
33755             }
33756             
33757             if(this.labellg > 0){
33758                 label.cls += ' col-lg-' + this.labellg;
33759                 items.cls += ' col-lg-' + (12 - this.labellg);
33760             }
33761             
33762             if(this.labelmd > 0){
33763                 label.cls += ' col-md-' + this.labelmd;
33764                 items.cls += ' col-md-' + (12 - this.labelmd);
33765             }
33766             
33767             if(this.labelsm > 0){
33768                 label.cls += ' col-sm-' + this.labelsm;
33769                 items.cls += ' col-sm-' + (12 - this.labelsm);
33770             }
33771             
33772             if(this.labelxs > 0){
33773                 label.cls += ' col-xs-' + this.labelxs;
33774                 items.cls += ' col-xs-' + (12 - this.labelxs);
33775             }
33776         }
33777         
33778         var cfg = {
33779             tag : 'div',
33780             cls : 'roo-radio-set',
33781             cn : [
33782                 {
33783                     tag : 'input',
33784                     cls : 'roo-radio-set-input',
33785                     type : 'hidden',
33786                     name : this.name,
33787                     value : this.value ? this.value :  ''
33788                 },
33789                 label,
33790                 items
33791             ]
33792         };
33793         
33794         if(this.weight.length){
33795             cfg.cls += ' roo-radio-' + this.weight;
33796         }
33797         
33798         if(this.inline) {
33799             cfg.cls += ' roo-radio-set-inline';
33800         }
33801         
33802         var settings=this;
33803         ['xs','sm','md','lg'].map(function(size){
33804             if (settings[size]) {
33805                 cfg.cls += ' col-' + size + '-' + settings[size];
33806             }
33807         });
33808         
33809         return cfg;
33810         
33811     },
33812
33813     initEvents : function()
33814     {
33815         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33816         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33817         
33818         if(!this.fieldLabel.length){
33819             this.labelEl.hide();
33820         }
33821         
33822         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33823         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33824         
33825         this.indicator = this.indicatorEl();
33826         
33827         if(this.indicator){
33828             this.indicator.addClass('invisible');
33829         }
33830         
33831         this.originalValue = this.getValue();
33832         
33833     },
33834     
33835     inputEl: function ()
33836     {
33837         return this.el.select('.roo-radio-set-input', true).first();
33838     },
33839     
33840     getChildContainer : function()
33841     {
33842         return this.itemsEl;
33843     },
33844     
33845     register : function(item)
33846     {
33847         this.radioes.push(item);
33848         
33849     },
33850     
33851     validate : function()
33852     {   
33853         if(this.getVisibilityEl().hasClass('hidden')){
33854             return true;
33855         }
33856         
33857         var valid = false;
33858         
33859         Roo.each(this.radioes, function(i){
33860             if(!i.checked){
33861                 return;
33862             }
33863             
33864             valid = true;
33865             return false;
33866         });
33867         
33868         if(this.allowBlank) {
33869             return true;
33870         }
33871         
33872         if(this.disabled || valid){
33873             this.markValid();
33874             return true;
33875         }
33876         
33877         this.markInvalid();
33878         return false;
33879         
33880     },
33881     
33882     markValid : function()
33883     {
33884         if(this.labelEl.isVisible(true)){
33885             this.indicatorEl().removeClass('visible');
33886             this.indicatorEl().addClass('invisible');
33887         }
33888         
33889         this.el.removeClass([this.invalidClass, this.validClass]);
33890         this.el.addClass(this.validClass);
33891         
33892         this.fireEvent('valid', this);
33893     },
33894     
33895     markInvalid : function(msg)
33896     {
33897         if(this.allowBlank || this.disabled){
33898             return;
33899         }
33900         
33901         if(this.labelEl.isVisible(true)){
33902             this.indicatorEl().removeClass('invisible');
33903             this.indicatorEl().addClass('visible');
33904         }
33905         
33906         this.el.removeClass([this.invalidClass, this.validClass]);
33907         this.el.addClass(this.invalidClass);
33908         
33909         this.fireEvent('invalid', this, msg);
33910         
33911     },
33912     
33913     setValue : function(v, suppressEvent)
33914     {   
33915         if(this.value === v){
33916             return;
33917         }
33918         
33919         this.value = v;
33920         
33921         if(this.rendered){
33922             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33923         }
33924         
33925         Roo.each(this.radioes, function(i){
33926             i.checked = false;
33927             i.el.removeClass('checked');
33928         });
33929         
33930         Roo.each(this.radioes, function(i){
33931             
33932             if(i.value === v || i.value.toString() === v.toString()){
33933                 i.checked = true;
33934                 i.el.addClass('checked');
33935                 
33936                 if(suppressEvent !== true){
33937                     this.fireEvent('check', this, i);
33938                 }
33939                 
33940                 return false;
33941             }
33942             
33943         }, this);
33944         
33945         this.validate();
33946     },
33947     
33948     clearInvalid : function(){
33949         
33950         if(!this.el || this.preventMark){
33951             return;
33952         }
33953         
33954         this.el.removeClass([this.invalidClass]);
33955         
33956         this.fireEvent('valid', this);
33957     }
33958     
33959 });
33960
33961 Roo.apply(Roo.bootstrap.RadioSet, {
33962     
33963     groups: {},
33964     
33965     register : function(set)
33966     {
33967         this.groups[set.name] = set;
33968     },
33969     
33970     get: function(name) 
33971     {
33972         if (typeof(this.groups[name]) == 'undefined') {
33973             return false;
33974         }
33975         
33976         return this.groups[name] ;
33977     }
33978     
33979 });
33980 /*
33981  * Based on:
33982  * Ext JS Library 1.1.1
33983  * Copyright(c) 2006-2007, Ext JS, LLC.
33984  *
33985  * Originally Released Under LGPL - original licence link has changed is not relivant.
33986  *
33987  * Fork - LGPL
33988  * <script type="text/javascript">
33989  */
33990
33991
33992 /**
33993  * @class Roo.bootstrap.SplitBar
33994  * @extends Roo.util.Observable
33995  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33996  * <br><br>
33997  * Usage:
33998  * <pre><code>
33999 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34000                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34001 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34002 split.minSize = 100;
34003 split.maxSize = 600;
34004 split.animate = true;
34005 split.on('moved', splitterMoved);
34006 </code></pre>
34007  * @constructor
34008  * Create a new SplitBar
34009  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
34010  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
34011  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34012  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
34013                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34014                         position of the SplitBar).
34015  */
34016 Roo.bootstrap.SplitBar = function(cfg){
34017     
34018     /** @private */
34019     
34020     //{
34021     //  dragElement : elm
34022     //  resizingElement: el,
34023         // optional..
34024     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34025     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
34026         // existingProxy ???
34027     //}
34028     
34029     this.el = Roo.get(cfg.dragElement, true);
34030     this.el.dom.unselectable = "on";
34031     /** @private */
34032     this.resizingEl = Roo.get(cfg.resizingElement, true);
34033
34034     /**
34035      * @private
34036      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34037      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34038      * @type Number
34039      */
34040     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34041     
34042     /**
34043      * The minimum size of the resizing element. (Defaults to 0)
34044      * @type Number
34045      */
34046     this.minSize = 0;
34047     
34048     /**
34049      * The maximum size of the resizing element. (Defaults to 2000)
34050      * @type Number
34051      */
34052     this.maxSize = 2000;
34053     
34054     /**
34055      * Whether to animate the transition to the new size
34056      * @type Boolean
34057      */
34058     this.animate = false;
34059     
34060     /**
34061      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34062      * @type Boolean
34063      */
34064     this.useShim = false;
34065     
34066     /** @private */
34067     this.shim = null;
34068     
34069     if(!cfg.existingProxy){
34070         /** @private */
34071         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34072     }else{
34073         this.proxy = Roo.get(cfg.existingProxy).dom;
34074     }
34075     /** @private */
34076     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34077     
34078     /** @private */
34079     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34080     
34081     /** @private */
34082     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34083     
34084     /** @private */
34085     this.dragSpecs = {};
34086     
34087     /**
34088      * @private The adapter to use to positon and resize elements
34089      */
34090     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34091     this.adapter.init(this);
34092     
34093     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34094         /** @private */
34095         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34096         this.el.addClass("roo-splitbar-h");
34097     }else{
34098         /** @private */
34099         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34100         this.el.addClass("roo-splitbar-v");
34101     }
34102     
34103     this.addEvents({
34104         /**
34105          * @event resize
34106          * Fires when the splitter is moved (alias for {@link #event-moved})
34107          * @param {Roo.bootstrap.SplitBar} this
34108          * @param {Number} newSize the new width or height
34109          */
34110         "resize" : true,
34111         /**
34112          * @event moved
34113          * Fires when the splitter is moved
34114          * @param {Roo.bootstrap.SplitBar} this
34115          * @param {Number} newSize the new width or height
34116          */
34117         "moved" : true,
34118         /**
34119          * @event beforeresize
34120          * Fires before the splitter is dragged
34121          * @param {Roo.bootstrap.SplitBar} this
34122          */
34123         "beforeresize" : true,
34124
34125         "beforeapply" : true
34126     });
34127
34128     Roo.util.Observable.call(this);
34129 };
34130
34131 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34132     onStartProxyDrag : function(x, y){
34133         this.fireEvent("beforeresize", this);
34134         if(!this.overlay){
34135             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34136             o.unselectable();
34137             o.enableDisplayMode("block");
34138             // all splitbars share the same overlay
34139             Roo.bootstrap.SplitBar.prototype.overlay = o;
34140         }
34141         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34142         this.overlay.show();
34143         Roo.get(this.proxy).setDisplayed("block");
34144         var size = this.adapter.getElementSize(this);
34145         this.activeMinSize = this.getMinimumSize();;
34146         this.activeMaxSize = this.getMaximumSize();;
34147         var c1 = size - this.activeMinSize;
34148         var c2 = Math.max(this.activeMaxSize - size, 0);
34149         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34150             this.dd.resetConstraints();
34151             this.dd.setXConstraint(
34152                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34153                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34154             );
34155             this.dd.setYConstraint(0, 0);
34156         }else{
34157             this.dd.resetConstraints();
34158             this.dd.setXConstraint(0, 0);
34159             this.dd.setYConstraint(
34160                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34161                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34162             );
34163          }
34164         this.dragSpecs.startSize = size;
34165         this.dragSpecs.startPoint = [x, y];
34166         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34167     },
34168     
34169     /** 
34170      * @private Called after the drag operation by the DDProxy
34171      */
34172     onEndProxyDrag : function(e){
34173         Roo.get(this.proxy).setDisplayed(false);
34174         var endPoint = Roo.lib.Event.getXY(e);
34175         if(this.overlay){
34176             this.overlay.hide();
34177         }
34178         var newSize;
34179         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34180             newSize = this.dragSpecs.startSize + 
34181                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34182                     endPoint[0] - this.dragSpecs.startPoint[0] :
34183                     this.dragSpecs.startPoint[0] - endPoint[0]
34184                 );
34185         }else{
34186             newSize = this.dragSpecs.startSize + 
34187                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34188                     endPoint[1] - this.dragSpecs.startPoint[1] :
34189                     this.dragSpecs.startPoint[1] - endPoint[1]
34190                 );
34191         }
34192         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34193         if(newSize != this.dragSpecs.startSize){
34194             if(this.fireEvent('beforeapply', this, newSize) !== false){
34195                 this.adapter.setElementSize(this, newSize);
34196                 this.fireEvent("moved", this, newSize);
34197                 this.fireEvent("resize", this, newSize);
34198             }
34199         }
34200     },
34201     
34202     /**
34203      * Get the adapter this SplitBar uses
34204      * @return The adapter object
34205      */
34206     getAdapter : function(){
34207         return this.adapter;
34208     },
34209     
34210     /**
34211      * Set the adapter this SplitBar uses
34212      * @param {Object} adapter A SplitBar adapter object
34213      */
34214     setAdapter : function(adapter){
34215         this.adapter = adapter;
34216         this.adapter.init(this);
34217     },
34218     
34219     /**
34220      * Gets the minimum size for the resizing element
34221      * @return {Number} The minimum size
34222      */
34223     getMinimumSize : function(){
34224         return this.minSize;
34225     },
34226     
34227     /**
34228      * Sets the minimum size for the resizing element
34229      * @param {Number} minSize The minimum size
34230      */
34231     setMinimumSize : function(minSize){
34232         this.minSize = minSize;
34233     },
34234     
34235     /**
34236      * Gets the maximum size for the resizing element
34237      * @return {Number} The maximum size
34238      */
34239     getMaximumSize : function(){
34240         return this.maxSize;
34241     },
34242     
34243     /**
34244      * Sets the maximum size for the resizing element
34245      * @param {Number} maxSize The maximum size
34246      */
34247     setMaximumSize : function(maxSize){
34248         this.maxSize = maxSize;
34249     },
34250     
34251     /**
34252      * Sets the initialize size for the resizing element
34253      * @param {Number} size The initial size
34254      */
34255     setCurrentSize : function(size){
34256         var oldAnimate = this.animate;
34257         this.animate = false;
34258         this.adapter.setElementSize(this, size);
34259         this.animate = oldAnimate;
34260     },
34261     
34262     /**
34263      * Destroy this splitbar. 
34264      * @param {Boolean} removeEl True to remove the element
34265      */
34266     destroy : function(removeEl){
34267         if(this.shim){
34268             this.shim.remove();
34269         }
34270         this.dd.unreg();
34271         this.proxy.parentNode.removeChild(this.proxy);
34272         if(removeEl){
34273             this.el.remove();
34274         }
34275     }
34276 });
34277
34278 /**
34279  * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34280  */
34281 Roo.bootstrap.SplitBar.createProxy = function(dir){
34282     var proxy = new Roo.Element(document.createElement("div"));
34283     proxy.unselectable();
34284     var cls = 'roo-splitbar-proxy';
34285     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34286     document.body.appendChild(proxy.dom);
34287     return proxy.dom;
34288 };
34289
34290 /** 
34291  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34292  * Default Adapter. It assumes the splitter and resizing element are not positioned
34293  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34294  */
34295 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34296 };
34297
34298 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34299     // do nothing for now
34300     init : function(s){
34301     
34302     },
34303     /**
34304      * Called before drag operations to get the current size of the resizing element. 
34305      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34306      */
34307      getElementSize : function(s){
34308         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34309             return s.resizingEl.getWidth();
34310         }else{
34311             return s.resizingEl.getHeight();
34312         }
34313     },
34314     
34315     /**
34316      * Called after drag operations to set the size of the resizing element.
34317      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34318      * @param {Number} newSize The new size to set
34319      * @param {Function} onComplete A function to be invoked when resizing is complete
34320      */
34321     setElementSize : function(s, newSize, onComplete){
34322         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34323             if(!s.animate){
34324                 s.resizingEl.setWidth(newSize);
34325                 if(onComplete){
34326                     onComplete(s, newSize);
34327                 }
34328             }else{
34329                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34330             }
34331         }else{
34332             
34333             if(!s.animate){
34334                 s.resizingEl.setHeight(newSize);
34335                 if(onComplete){
34336                     onComplete(s, newSize);
34337                 }
34338             }else{
34339                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34340             }
34341         }
34342     }
34343 };
34344
34345 /** 
34346  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34347  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34348  * Adapter that  moves the splitter element to align with the resized sizing element. 
34349  * Used with an absolute positioned SplitBar.
34350  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34351  * document.body, make sure you assign an id to the body element.
34352  */
34353 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34354     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34355     this.container = Roo.get(container);
34356 };
34357
34358 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34359     init : function(s){
34360         this.basic.init(s);
34361     },
34362     
34363     getElementSize : function(s){
34364         return this.basic.getElementSize(s);
34365     },
34366     
34367     setElementSize : function(s, newSize, onComplete){
34368         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34369     },
34370     
34371     moveSplitter : function(s){
34372         var yes = Roo.bootstrap.SplitBar;
34373         switch(s.placement){
34374             case yes.LEFT:
34375                 s.el.setX(s.resizingEl.getRight());
34376                 break;
34377             case yes.RIGHT:
34378                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34379                 break;
34380             case yes.TOP:
34381                 s.el.setY(s.resizingEl.getBottom());
34382                 break;
34383             case yes.BOTTOM:
34384                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34385                 break;
34386         }
34387     }
34388 };
34389
34390 /**
34391  * Orientation constant - Create a vertical SplitBar
34392  * @static
34393  * @type Number
34394  */
34395 Roo.bootstrap.SplitBar.VERTICAL = 1;
34396
34397 /**
34398  * Orientation constant - Create a horizontal SplitBar
34399  * @static
34400  * @type Number
34401  */
34402 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34403
34404 /**
34405  * Placement constant - The resizing element is to the left of the splitter element
34406  * @static
34407  * @type Number
34408  */
34409 Roo.bootstrap.SplitBar.LEFT = 1;
34410
34411 /**
34412  * Placement constant - The resizing element is to the right of the splitter element
34413  * @static
34414  * @type Number
34415  */
34416 Roo.bootstrap.SplitBar.RIGHT = 2;
34417
34418 /**
34419  * Placement constant - The resizing element is positioned above the splitter element
34420  * @static
34421  * @type Number
34422  */
34423 Roo.bootstrap.SplitBar.TOP = 3;
34424
34425 /**
34426  * Placement constant - The resizing element is positioned under splitter element
34427  * @static
34428  * @type Number
34429  */
34430 Roo.bootstrap.SplitBar.BOTTOM = 4;
34431 Roo.namespace("Roo.bootstrap.layout");/*
34432  * Based on:
34433  * Ext JS Library 1.1.1
34434  * Copyright(c) 2006-2007, Ext JS, LLC.
34435  *
34436  * Originally Released Under LGPL - original licence link has changed is not relivant.
34437  *
34438  * Fork - LGPL
34439  * <script type="text/javascript">
34440  */
34441
34442 /**
34443  * @class Roo.bootstrap.layout.Manager
34444  * @extends Roo.bootstrap.Component
34445  * Base class for layout managers.
34446  */
34447 Roo.bootstrap.layout.Manager = function(config)
34448 {
34449     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34450
34451
34452
34453
34454
34455     /** false to disable window resize monitoring @type Boolean */
34456     this.monitorWindowResize = true;
34457     this.regions = {};
34458     this.addEvents({
34459         /**
34460          * @event layout
34461          * Fires when a layout is performed.
34462          * @param {Roo.LayoutManager} this
34463          */
34464         "layout" : true,
34465         /**
34466          * @event regionresized
34467          * Fires when the user resizes a region.
34468          * @param {Roo.LayoutRegion} region The resized region
34469          * @param {Number} newSize The new size (width for east/west, height for north/south)
34470          */
34471         "regionresized" : true,
34472         /**
34473          * @event regioncollapsed
34474          * Fires when a region is collapsed.
34475          * @param {Roo.LayoutRegion} region The collapsed region
34476          */
34477         "regioncollapsed" : true,
34478         /**
34479          * @event regionexpanded
34480          * Fires when a region is expanded.
34481          * @param {Roo.LayoutRegion} region The expanded region
34482          */
34483         "regionexpanded" : true
34484     });
34485     this.updating = false;
34486
34487     if (config.el) {
34488         this.el = Roo.get(config.el);
34489         this.initEvents();
34490     }
34491
34492 };
34493
34494 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34495
34496
34497     regions : null,
34498
34499     monitorWindowResize : true,
34500
34501
34502     updating : false,
34503
34504
34505     onRender : function(ct, position)
34506     {
34507         if(!this.el){
34508             this.el = Roo.get(ct);
34509             this.initEvents();
34510         }
34511         //this.fireEvent('render',this);
34512     },
34513
34514
34515     initEvents: function()
34516     {
34517
34518
34519         // ie scrollbar fix
34520         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34521             document.body.scroll = "no";
34522         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34523             this.el.position('relative');
34524         }
34525         this.id = this.el.id;
34526         this.el.addClass("roo-layout-container");
34527         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34528         if(this.el.dom != document.body ) {
34529             this.el.on('resize', this.layout,this);
34530             this.el.on('show', this.layout,this);
34531         }
34532
34533     },
34534
34535     /**
34536      * Returns true if this layout is currently being updated
34537      * @return {Boolean}
34538      */
34539     isUpdating : function(){
34540         return this.updating;
34541     },
34542
34543     /**
34544      * Suspend the LayoutManager from doing auto-layouts while
34545      * making multiple add or remove calls
34546      */
34547     beginUpdate : function(){
34548         this.updating = true;
34549     },
34550
34551     /**
34552      * Restore auto-layouts and optionally disable the manager from performing a layout
34553      * @param {Boolean} noLayout true to disable a layout update
34554      */
34555     endUpdate : function(noLayout){
34556         this.updating = false;
34557         if(!noLayout){
34558             this.layout();
34559         }
34560     },
34561
34562     layout: function(){
34563         // abstract...
34564     },
34565
34566     onRegionResized : function(region, newSize){
34567         this.fireEvent("regionresized", region, newSize);
34568         this.layout();
34569     },
34570
34571     onRegionCollapsed : function(region){
34572         this.fireEvent("regioncollapsed", region);
34573     },
34574
34575     onRegionExpanded : function(region){
34576         this.fireEvent("regionexpanded", region);
34577     },
34578
34579     /**
34580      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34581      * performs box-model adjustments.
34582      * @return {Object} The size as an object {width: (the width), height: (the height)}
34583      */
34584     getViewSize : function()
34585     {
34586         var size;
34587         if(this.el.dom != document.body){
34588             size = this.el.getSize();
34589         }else{
34590             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34591         }
34592         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34593         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34594         return size;
34595     },
34596
34597     /**
34598      * Returns the Element this layout is bound to.
34599      * @return {Roo.Element}
34600      */
34601     getEl : function(){
34602         return this.el;
34603     },
34604
34605     /**
34606      * Returns the specified region.
34607      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34608      * @return {Roo.LayoutRegion}
34609      */
34610     getRegion : function(target){
34611         return this.regions[target.toLowerCase()];
34612     },
34613
34614     onWindowResize : function(){
34615         if(this.monitorWindowResize){
34616             this.layout();
34617         }
34618     }
34619 });
34620 /*
34621  * Based on:
34622  * Ext JS Library 1.1.1
34623  * Copyright(c) 2006-2007, Ext JS, LLC.
34624  *
34625  * Originally Released Under LGPL - original licence link has changed is not relivant.
34626  *
34627  * Fork - LGPL
34628  * <script type="text/javascript">
34629  */
34630 /**
34631  * @class Roo.bootstrap.layout.Border
34632  * @extends Roo.bootstrap.layout.Manager
34633  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34634  * please see: examples/bootstrap/nested.html<br><br>
34635  
34636 <b>The container the layout is rendered into can be either the body element or any other element.
34637 If it is not the body element, the container needs to either be an absolute positioned element,
34638 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34639 the container size if it is not the body element.</b>
34640
34641 * @constructor
34642 * Create a new Border
34643 * @param {Object} config Configuration options
34644  */
34645 Roo.bootstrap.layout.Border = function(config){
34646     config = config || {};
34647     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34648     
34649     
34650     
34651     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34652         if(config[region]){
34653             config[region].region = region;
34654             this.addRegion(config[region]);
34655         }
34656     },this);
34657     
34658 };
34659
34660 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34661
34662 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34663     /**
34664      * Creates and adds a new region if it doesn't already exist.
34665      * @param {String} target The target region key (north, south, east, west or center).
34666      * @param {Object} config The regions config object
34667      * @return {BorderLayoutRegion} The new region
34668      */
34669     addRegion : function(config)
34670     {
34671         if(!this.regions[config.region]){
34672             var r = this.factory(config);
34673             this.bindRegion(r);
34674         }
34675         return this.regions[config.region];
34676     },
34677
34678     // private (kinda)
34679     bindRegion : function(r){
34680         this.regions[r.config.region] = r;
34681         
34682         r.on("visibilitychange",    this.layout, this);
34683         r.on("paneladded",          this.layout, this);
34684         r.on("panelremoved",        this.layout, this);
34685         r.on("invalidated",         this.layout, this);
34686         r.on("resized",             this.onRegionResized, this);
34687         r.on("collapsed",           this.onRegionCollapsed, this);
34688         r.on("expanded",            this.onRegionExpanded, this);
34689     },
34690
34691     /**
34692      * Performs a layout update.
34693      */
34694     layout : function()
34695     {
34696         if(this.updating) {
34697             return;
34698         }
34699         
34700         // render all the rebions if they have not been done alreayd?
34701         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34702             if(this.regions[region] && !this.regions[region].bodyEl){
34703                 this.regions[region].onRender(this.el)
34704             }
34705         },this);
34706         
34707         var size = this.getViewSize();
34708         var w = size.width;
34709         var h = size.height;
34710         var centerW = w;
34711         var centerH = h;
34712         var centerY = 0;
34713         var centerX = 0;
34714         //var x = 0, y = 0;
34715
34716         var rs = this.regions;
34717         var north = rs["north"];
34718         var south = rs["south"]; 
34719         var west = rs["west"];
34720         var east = rs["east"];
34721         var center = rs["center"];
34722         //if(this.hideOnLayout){ // not supported anymore
34723             //c.el.setStyle("display", "none");
34724         //}
34725         if(north && north.isVisible()){
34726             var b = north.getBox();
34727             var m = north.getMargins();
34728             b.width = w - (m.left+m.right);
34729             b.x = m.left;
34730             b.y = m.top;
34731             centerY = b.height + b.y + m.bottom;
34732             centerH -= centerY;
34733             north.updateBox(this.safeBox(b));
34734         }
34735         if(south && south.isVisible()){
34736             var b = south.getBox();
34737             var m = south.getMargins();
34738             b.width = w - (m.left+m.right);
34739             b.x = m.left;
34740             var totalHeight = (b.height + m.top + m.bottom);
34741             b.y = h - totalHeight + m.top;
34742             centerH -= totalHeight;
34743             south.updateBox(this.safeBox(b));
34744         }
34745         if(west && west.isVisible()){
34746             var b = west.getBox();
34747             var m = west.getMargins();
34748             b.height = centerH - (m.top+m.bottom);
34749             b.x = m.left;
34750             b.y = centerY + m.top;
34751             var totalWidth = (b.width + m.left + m.right);
34752             centerX += totalWidth;
34753             centerW -= totalWidth;
34754             west.updateBox(this.safeBox(b));
34755         }
34756         if(east && east.isVisible()){
34757             var b = east.getBox();
34758             var m = east.getMargins();
34759             b.height = centerH - (m.top+m.bottom);
34760             var totalWidth = (b.width + m.left + m.right);
34761             b.x = w - totalWidth + m.left;
34762             b.y = centerY + m.top;
34763             centerW -= totalWidth;
34764             east.updateBox(this.safeBox(b));
34765         }
34766         if(center){
34767             var m = center.getMargins();
34768             var centerBox = {
34769                 x: centerX + m.left,
34770                 y: centerY + m.top,
34771                 width: centerW - (m.left+m.right),
34772                 height: centerH - (m.top+m.bottom)
34773             };
34774             //if(this.hideOnLayout){
34775                 //center.el.setStyle("display", "block");
34776             //}
34777             center.updateBox(this.safeBox(centerBox));
34778         }
34779         this.el.repaint();
34780         this.fireEvent("layout", this);
34781     },
34782
34783     // private
34784     safeBox : function(box){
34785         box.width = Math.max(0, box.width);
34786         box.height = Math.max(0, box.height);
34787         return box;
34788     },
34789
34790     /**
34791      * Adds a ContentPanel (or subclass) to this layout.
34792      * @param {String} target The target region key (north, south, east, west or center).
34793      * @param {Roo.ContentPanel} panel The panel to add
34794      * @return {Roo.ContentPanel} The added panel
34795      */
34796     add : function(target, panel){
34797          
34798         target = target.toLowerCase();
34799         return this.regions[target].add(panel);
34800     },
34801
34802     /**
34803      * Remove a ContentPanel (or subclass) to this layout.
34804      * @param {String} target The target region key (north, south, east, west or center).
34805      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34806      * @return {Roo.ContentPanel} The removed panel
34807      */
34808     remove : function(target, panel){
34809         target = target.toLowerCase();
34810         return this.regions[target].remove(panel);
34811     },
34812
34813     /**
34814      * Searches all regions for a panel with the specified id
34815      * @param {String} panelId
34816      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34817      */
34818     findPanel : function(panelId){
34819         var rs = this.regions;
34820         for(var target in rs){
34821             if(typeof rs[target] != "function"){
34822                 var p = rs[target].getPanel(panelId);
34823                 if(p){
34824                     return p;
34825                 }
34826             }
34827         }
34828         return null;
34829     },
34830
34831     /**
34832      * Searches all regions for a panel with the specified id and activates (shows) it.
34833      * @param {String/ContentPanel} panelId The panels id or the panel itself
34834      * @return {Roo.ContentPanel} The shown panel or null
34835      */
34836     showPanel : function(panelId) {
34837       var rs = this.regions;
34838       for(var target in rs){
34839          var r = rs[target];
34840          if(typeof r != "function"){
34841             if(r.hasPanel(panelId)){
34842                return r.showPanel(panelId);
34843             }
34844          }
34845       }
34846       return null;
34847    },
34848
34849    /**
34850      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34851      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34852      */
34853    /*
34854     restoreState : function(provider){
34855         if(!provider){
34856             provider = Roo.state.Manager;
34857         }
34858         var sm = new Roo.LayoutStateManager();
34859         sm.init(this, provider);
34860     },
34861 */
34862  
34863  
34864     /**
34865      * Adds a xtype elements to the layout.
34866      * <pre><code>
34867
34868 layout.addxtype({
34869        xtype : 'ContentPanel',
34870        region: 'west',
34871        items: [ .... ]
34872    }
34873 );
34874
34875 layout.addxtype({
34876         xtype : 'NestedLayoutPanel',
34877         region: 'west',
34878         layout: {
34879            center: { },
34880            west: { }   
34881         },
34882         items : [ ... list of content panels or nested layout panels.. ]
34883    }
34884 );
34885 </code></pre>
34886      * @param {Object} cfg Xtype definition of item to add.
34887      */
34888     addxtype : function(cfg)
34889     {
34890         // basically accepts a pannel...
34891         // can accept a layout region..!?!?
34892         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34893         
34894         
34895         // theory?  children can only be panels??
34896         
34897         //if (!cfg.xtype.match(/Panel$/)) {
34898         //    return false;
34899         //}
34900         var ret = false;
34901         
34902         if (typeof(cfg.region) == 'undefined') {
34903             Roo.log("Failed to add Panel, region was not set");
34904             Roo.log(cfg);
34905             return false;
34906         }
34907         var region = cfg.region;
34908         delete cfg.region;
34909         
34910           
34911         var xitems = [];
34912         if (cfg.items) {
34913             xitems = cfg.items;
34914             delete cfg.items;
34915         }
34916         var nb = false;
34917         
34918         switch(cfg.xtype) 
34919         {
34920             case 'Content':  // ContentPanel (el, cfg)
34921             case 'Scroll':  // ContentPanel (el, cfg)
34922             case 'View': 
34923                 cfg.autoCreate = true;
34924                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34925                 //} else {
34926                 //    var el = this.el.createChild();
34927                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34928                 //}
34929                 
34930                 this.add(region, ret);
34931                 break;
34932             
34933             /*
34934             case 'TreePanel': // our new panel!
34935                 cfg.el = this.el.createChild();
34936                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34937                 this.add(region, ret);
34938                 break;
34939             */
34940             
34941             case 'Nest': 
34942                 // create a new Layout (which is  a Border Layout...
34943                 
34944                 var clayout = cfg.layout;
34945                 clayout.el  = this.el.createChild();
34946                 clayout.items   = clayout.items  || [];
34947                 
34948                 delete cfg.layout;
34949                 
34950                 // replace this exitems with the clayout ones..
34951                 xitems = clayout.items;
34952                  
34953                 // force background off if it's in center...
34954                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34955                     cfg.background = false;
34956                 }
34957                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34958                 
34959                 
34960                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34961                 //console.log('adding nested layout panel '  + cfg.toSource());
34962                 this.add(region, ret);
34963                 nb = {}; /// find first...
34964                 break;
34965             
34966             case 'Grid':
34967                 
34968                 // needs grid and region
34969                 
34970                 //var el = this.getRegion(region).el.createChild();
34971                 /*
34972                  *var el = this.el.createChild();
34973                 // create the grid first...
34974                 cfg.grid.container = el;
34975                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34976                 */
34977                 
34978                 if (region == 'center' && this.active ) {
34979                     cfg.background = false;
34980                 }
34981                 
34982                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34983                 
34984                 this.add(region, ret);
34985                 /*
34986                 if (cfg.background) {
34987                     // render grid on panel activation (if panel background)
34988                     ret.on('activate', function(gp) {
34989                         if (!gp.grid.rendered) {
34990                     //        gp.grid.render(el);
34991                         }
34992                     });
34993                 } else {
34994                   //  cfg.grid.render(el);
34995                 }
34996                 */
34997                 break;
34998            
34999            
35000             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35001                 // it was the old xcomponent building that caused this before.
35002                 // espeically if border is the top element in the tree.
35003                 ret = this;
35004                 break; 
35005                 
35006                     
35007                 
35008                 
35009                 
35010             default:
35011                 /*
35012                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35013                     
35014                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35015                     this.add(region, ret);
35016                 } else {
35017                 */
35018                     Roo.log(cfg);
35019                     throw "Can not add '" + cfg.xtype + "' to Border";
35020                     return null;
35021              
35022                                 
35023              
35024         }
35025         this.beginUpdate();
35026         // add children..
35027         var region = '';
35028         var abn = {};
35029         Roo.each(xitems, function(i)  {
35030             region = nb && i.region ? i.region : false;
35031             
35032             var add = ret.addxtype(i);
35033            
35034             if (region) {
35035                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35036                 if (!i.background) {
35037                     abn[region] = nb[region] ;
35038                 }
35039             }
35040             
35041         });
35042         this.endUpdate();
35043
35044         // make the last non-background panel active..
35045         //if (nb) { Roo.log(abn); }
35046         if (nb) {
35047             
35048             for(var r in abn) {
35049                 region = this.getRegion(r);
35050                 if (region) {
35051                     // tried using nb[r], but it does not work..
35052                      
35053                     region.showPanel(abn[r]);
35054                    
35055                 }
35056             }
35057         }
35058         return ret;
35059         
35060     },
35061     
35062     
35063 // private
35064     factory : function(cfg)
35065     {
35066         
35067         var validRegions = Roo.bootstrap.layout.Border.regions;
35068
35069         var target = cfg.region;
35070         cfg.mgr = this;
35071         
35072         var r = Roo.bootstrap.layout;
35073         Roo.log(target);
35074         switch(target){
35075             case "north":
35076                 return new r.North(cfg);
35077             case "south":
35078                 return new r.South(cfg);
35079             case "east":
35080                 return new r.East(cfg);
35081             case "west":
35082                 return new r.West(cfg);
35083             case "center":
35084                 return new r.Center(cfg);
35085         }
35086         throw 'Layout region "'+target+'" not supported.';
35087     }
35088     
35089     
35090 });
35091  /*
35092  * Based on:
35093  * Ext JS Library 1.1.1
35094  * Copyright(c) 2006-2007, Ext JS, LLC.
35095  *
35096  * Originally Released Under LGPL - original licence link has changed is not relivant.
35097  *
35098  * Fork - LGPL
35099  * <script type="text/javascript">
35100  */
35101  
35102 /**
35103  * @class Roo.bootstrap.layout.Basic
35104  * @extends Roo.util.Observable
35105  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35106  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35107  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35108  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35109  * @cfg {string}   region  the region that it inhabits..
35110  * @cfg {bool}   skipConfig skip config?
35111  * 
35112
35113  */
35114 Roo.bootstrap.layout.Basic = function(config){
35115     
35116     this.mgr = config.mgr;
35117     
35118     this.position = config.region;
35119     
35120     var skipConfig = config.skipConfig;
35121     
35122     this.events = {
35123         /**
35124          * @scope Roo.BasicLayoutRegion
35125          */
35126         
35127         /**
35128          * @event beforeremove
35129          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35130          * @param {Roo.LayoutRegion} this
35131          * @param {Roo.ContentPanel} panel The panel
35132          * @param {Object} e The cancel event object
35133          */
35134         "beforeremove" : true,
35135         /**
35136          * @event invalidated
35137          * Fires when the layout for this region is changed.
35138          * @param {Roo.LayoutRegion} this
35139          */
35140         "invalidated" : true,
35141         /**
35142          * @event visibilitychange
35143          * Fires when this region is shown or hidden 
35144          * @param {Roo.LayoutRegion} this
35145          * @param {Boolean} visibility true or false
35146          */
35147         "visibilitychange" : true,
35148         /**
35149          * @event paneladded
35150          * Fires when a panel is added. 
35151          * @param {Roo.LayoutRegion} this
35152          * @param {Roo.ContentPanel} panel The panel
35153          */
35154         "paneladded" : true,
35155         /**
35156          * @event panelremoved
35157          * Fires when a panel is removed. 
35158          * @param {Roo.LayoutRegion} this
35159          * @param {Roo.ContentPanel} panel The panel
35160          */
35161         "panelremoved" : true,
35162         /**
35163          * @event beforecollapse
35164          * Fires when this region before collapse.
35165          * @param {Roo.LayoutRegion} this
35166          */
35167         "beforecollapse" : true,
35168         /**
35169          * @event collapsed
35170          * Fires when this region is collapsed.
35171          * @param {Roo.LayoutRegion} this
35172          */
35173         "collapsed" : true,
35174         /**
35175          * @event expanded
35176          * Fires when this region is expanded.
35177          * @param {Roo.LayoutRegion} this
35178          */
35179         "expanded" : true,
35180         /**
35181          * @event slideshow
35182          * Fires when this region is slid into view.
35183          * @param {Roo.LayoutRegion} this
35184          */
35185         "slideshow" : true,
35186         /**
35187          * @event slidehide
35188          * Fires when this region slides out of view. 
35189          * @param {Roo.LayoutRegion} this
35190          */
35191         "slidehide" : true,
35192         /**
35193          * @event panelactivated
35194          * Fires when a panel is activated. 
35195          * @param {Roo.LayoutRegion} this
35196          * @param {Roo.ContentPanel} panel The activated panel
35197          */
35198         "panelactivated" : true,
35199         /**
35200          * @event resized
35201          * Fires when the user resizes this region. 
35202          * @param {Roo.LayoutRegion} this
35203          * @param {Number} newSize The new size (width for east/west, height for north/south)
35204          */
35205         "resized" : true
35206     };
35207     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35208     this.panels = new Roo.util.MixedCollection();
35209     this.panels.getKey = this.getPanelId.createDelegate(this);
35210     this.box = null;
35211     this.activePanel = null;
35212     // ensure listeners are added...
35213     
35214     if (config.listeners || config.events) {
35215         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35216             listeners : config.listeners || {},
35217             events : config.events || {}
35218         });
35219     }
35220     
35221     if(skipConfig !== true){
35222         this.applyConfig(config);
35223     }
35224 };
35225
35226 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35227 {
35228     getPanelId : function(p){
35229         return p.getId();
35230     },
35231     
35232     applyConfig : function(config){
35233         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35234         this.config = config;
35235         
35236     },
35237     
35238     /**
35239      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35240      * the width, for horizontal (north, south) the height.
35241      * @param {Number} newSize The new width or height
35242      */
35243     resizeTo : function(newSize){
35244         var el = this.el ? this.el :
35245                  (this.activePanel ? this.activePanel.getEl() : null);
35246         if(el){
35247             switch(this.position){
35248                 case "east":
35249                 case "west":
35250                     el.setWidth(newSize);
35251                     this.fireEvent("resized", this, newSize);
35252                 break;
35253                 case "north":
35254                 case "south":
35255                     el.setHeight(newSize);
35256                     this.fireEvent("resized", this, newSize);
35257                 break;                
35258             }
35259         }
35260     },
35261     
35262     getBox : function(){
35263         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35264     },
35265     
35266     getMargins : function(){
35267         return this.margins;
35268     },
35269     
35270     updateBox : function(box){
35271         this.box = box;
35272         var el = this.activePanel.getEl();
35273         el.dom.style.left = box.x + "px";
35274         el.dom.style.top = box.y + "px";
35275         this.activePanel.setSize(box.width, box.height);
35276     },
35277     
35278     /**
35279      * Returns the container element for this region.
35280      * @return {Roo.Element}
35281      */
35282     getEl : function(){
35283         return this.activePanel;
35284     },
35285     
35286     /**
35287      * Returns true if this region is currently visible.
35288      * @return {Boolean}
35289      */
35290     isVisible : function(){
35291         return this.activePanel ? true : false;
35292     },
35293     
35294     setActivePanel : function(panel){
35295         panel = this.getPanel(panel);
35296         if(this.activePanel && this.activePanel != panel){
35297             this.activePanel.setActiveState(false);
35298             this.activePanel.getEl().setLeftTop(-10000,-10000);
35299         }
35300         this.activePanel = panel;
35301         panel.setActiveState(true);
35302         if(this.box){
35303             panel.setSize(this.box.width, this.box.height);
35304         }
35305         this.fireEvent("panelactivated", this, panel);
35306         this.fireEvent("invalidated");
35307     },
35308     
35309     /**
35310      * Show the specified panel.
35311      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35312      * @return {Roo.ContentPanel} The shown panel or null
35313      */
35314     showPanel : function(panel){
35315         panel = this.getPanel(panel);
35316         if(panel){
35317             this.setActivePanel(panel);
35318         }
35319         return panel;
35320     },
35321     
35322     /**
35323      * Get the active panel for this region.
35324      * @return {Roo.ContentPanel} The active panel or null
35325      */
35326     getActivePanel : function(){
35327         return this.activePanel;
35328     },
35329     
35330     /**
35331      * Add the passed ContentPanel(s)
35332      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35333      * @return {Roo.ContentPanel} The panel added (if only one was added)
35334      */
35335     add : function(panel){
35336         if(arguments.length > 1){
35337             for(var i = 0, len = arguments.length; i < len; i++) {
35338                 this.add(arguments[i]);
35339             }
35340             return null;
35341         }
35342         if(this.hasPanel(panel)){
35343             this.showPanel(panel);
35344             return panel;
35345         }
35346         var el = panel.getEl();
35347         if(el.dom.parentNode != this.mgr.el.dom){
35348             this.mgr.el.dom.appendChild(el.dom);
35349         }
35350         if(panel.setRegion){
35351             panel.setRegion(this);
35352         }
35353         this.panels.add(panel);
35354         el.setStyle("position", "absolute");
35355         if(!panel.background){
35356             this.setActivePanel(panel);
35357             if(this.config.initialSize && this.panels.getCount()==1){
35358                 this.resizeTo(this.config.initialSize);
35359             }
35360         }
35361         this.fireEvent("paneladded", this, panel);
35362         return panel;
35363     },
35364     
35365     /**
35366      * Returns true if the panel is in this region.
35367      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35368      * @return {Boolean}
35369      */
35370     hasPanel : function(panel){
35371         if(typeof panel == "object"){ // must be panel obj
35372             panel = panel.getId();
35373         }
35374         return this.getPanel(panel) ? true : false;
35375     },
35376     
35377     /**
35378      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35379      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35380      * @param {Boolean} preservePanel Overrides the config preservePanel option
35381      * @return {Roo.ContentPanel} The panel that was removed
35382      */
35383     remove : function(panel, preservePanel){
35384         panel = this.getPanel(panel);
35385         if(!panel){
35386             return null;
35387         }
35388         var e = {};
35389         this.fireEvent("beforeremove", this, panel, e);
35390         if(e.cancel === true){
35391             return null;
35392         }
35393         var panelId = panel.getId();
35394         this.panels.removeKey(panelId);
35395         return panel;
35396     },
35397     
35398     /**
35399      * Returns the panel specified or null if it's not in this region.
35400      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35401      * @return {Roo.ContentPanel}
35402      */
35403     getPanel : function(id){
35404         if(typeof id == "object"){ // must be panel obj
35405             return id;
35406         }
35407         return this.panels.get(id);
35408     },
35409     
35410     /**
35411      * Returns this regions position (north/south/east/west/center).
35412      * @return {String} 
35413      */
35414     getPosition: function(){
35415         return this.position;    
35416     }
35417 });/*
35418  * Based on:
35419  * Ext JS Library 1.1.1
35420  * Copyright(c) 2006-2007, Ext JS, LLC.
35421  *
35422  * Originally Released Under LGPL - original licence link has changed is not relivant.
35423  *
35424  * Fork - LGPL
35425  * <script type="text/javascript">
35426  */
35427  
35428 /**
35429  * @class Roo.bootstrap.layout.Region
35430  * @extends Roo.bootstrap.layout.Basic
35431  * This class represents a region in a layout manager.
35432  
35433  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35434  * @cfg {Object}    cmargins        Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
35435  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35436  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35437  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35438  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35439  * @cfg {String}    title           The title for the region (overrides panel titles)
35440  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35441  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35442  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35443  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35444  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35445  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35446  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35447  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35448  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35449  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35450
35451  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35452  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35453  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35454  * @cfg {Number}    width           For East/West panels
35455  * @cfg {Number}    height          For North/South panels
35456  * @cfg {Boolean}   split           To show the splitter
35457  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35458  * 
35459  * @cfg {string}   cls             Extra CSS classes to add to region
35460  * 
35461  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35462  * @cfg {string}   region  the region that it inhabits..
35463  *
35464
35465  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35466  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35467
35468  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35469  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35470  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35471  */
35472 Roo.bootstrap.layout.Region = function(config)
35473 {
35474     this.applyConfig(config);
35475
35476     var mgr = config.mgr;
35477     var pos = config.region;
35478     config.skipConfig = true;
35479     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35480     
35481     if (mgr.el) {
35482         this.onRender(mgr.el);   
35483     }
35484      
35485     this.visible = true;
35486     this.collapsed = false;
35487     this.unrendered_panels = [];
35488 };
35489
35490 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35491
35492     position: '', // set by wrapper (eg. north/south etc..)
35493     unrendered_panels : null,  // unrendered panels.
35494     createBody : function(){
35495         /** This region's body element 
35496         * @type Roo.Element */
35497         this.bodyEl = this.el.createChild({
35498                 tag: "div",
35499                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35500         });
35501     },
35502
35503     onRender: function(ctr, pos)
35504     {
35505         var dh = Roo.DomHelper;
35506         /** This region's container element 
35507         * @type Roo.Element */
35508         this.el = dh.append(ctr.dom, {
35509                 tag: "div",
35510                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35511             }, true);
35512         /** This region's title element 
35513         * @type Roo.Element */
35514     
35515         this.titleEl = dh.append(this.el.dom,
35516             {
35517                     tag: "div",
35518                     unselectable: "on",
35519                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35520                     children:[
35521                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35522                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35523                     ]}, true);
35524         
35525         this.titleEl.enableDisplayMode();
35526         /** This region's title text element 
35527         * @type HTMLElement */
35528         this.titleTextEl = this.titleEl.dom.firstChild;
35529         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35530         /*
35531         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35532         this.closeBtn.enableDisplayMode();
35533         this.closeBtn.on("click", this.closeClicked, this);
35534         this.closeBtn.hide();
35535     */
35536         this.createBody(this.config);
35537         if(this.config.hideWhenEmpty){
35538             this.hide();
35539             this.on("paneladded", this.validateVisibility, this);
35540             this.on("panelremoved", this.validateVisibility, this);
35541         }
35542         if(this.autoScroll){
35543             this.bodyEl.setStyle("overflow", "auto");
35544         }else{
35545             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35546         }
35547         //if(c.titlebar !== false){
35548             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35549                 this.titleEl.hide();
35550             }else{
35551                 this.titleEl.show();
35552                 if(this.config.title){
35553                     this.titleTextEl.innerHTML = this.config.title;
35554                 }
35555             }
35556         //}
35557         if(this.config.collapsed){
35558             this.collapse(true);
35559         }
35560         if(this.config.hidden){
35561             this.hide();
35562         }
35563         
35564         if (this.unrendered_panels && this.unrendered_panels.length) {
35565             for (var i =0;i< this.unrendered_panels.length; i++) {
35566                 this.add(this.unrendered_panels[i]);
35567             }
35568             this.unrendered_panels = null;
35569             
35570         }
35571         
35572     },
35573     
35574     applyConfig : function(c)
35575     {
35576         /*
35577          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35578             var dh = Roo.DomHelper;
35579             if(c.titlebar !== false){
35580                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35581                 this.collapseBtn.on("click", this.collapse, this);
35582                 this.collapseBtn.enableDisplayMode();
35583                 /*
35584                 if(c.showPin === true || this.showPin){
35585                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35586                     this.stickBtn.enableDisplayMode();
35587                     this.stickBtn.on("click", this.expand, this);
35588                     this.stickBtn.hide();
35589                 }
35590                 
35591             }
35592             */
35593             /** This region's collapsed element
35594             * @type Roo.Element */
35595             /*
35596              *
35597             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35598                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35599             ]}, true);
35600             
35601             if(c.floatable !== false){
35602                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35603                this.collapsedEl.on("click", this.collapseClick, this);
35604             }
35605
35606             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35607                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35608                    id: "message", unselectable: "on", style:{"float":"left"}});
35609                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35610              }
35611             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35612             this.expandBtn.on("click", this.expand, this);
35613             
35614         }
35615         
35616         if(this.collapseBtn){
35617             this.collapseBtn.setVisible(c.collapsible == true);
35618         }
35619         
35620         this.cmargins = c.cmargins || this.cmargins ||
35621                          (this.position == "west" || this.position == "east" ?
35622                              {top: 0, left: 2, right:2, bottom: 0} :
35623                              {top: 2, left: 0, right:0, bottom: 2});
35624         */
35625         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35626         
35627         
35628         this.bottomTabs = c.tabPosition != "top";
35629         
35630         this.autoScroll = c.autoScroll || false;
35631         
35632         
35633        
35634         
35635         this.duration = c.duration || .30;
35636         this.slideDuration = c.slideDuration || .45;
35637         this.config = c;
35638        
35639     },
35640     /**
35641      * Returns true if this region is currently visible.
35642      * @return {Boolean}
35643      */
35644     isVisible : function(){
35645         return this.visible;
35646     },
35647
35648     /**
35649      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35650      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35651      */
35652     //setCollapsedTitle : function(title){
35653     //    title = title || "&#160;";
35654      //   if(this.collapsedTitleTextEl){
35655       //      this.collapsedTitleTextEl.innerHTML = title;
35656        // }
35657     //},
35658
35659     getBox : function(){
35660         var b;
35661       //  if(!this.collapsed){
35662             b = this.el.getBox(false, true);
35663        // }else{
35664           //  b = this.collapsedEl.getBox(false, true);
35665         //}
35666         return b;
35667     },
35668
35669     getMargins : function(){
35670         return this.margins;
35671         //return this.collapsed ? this.cmargins : this.margins;
35672     },
35673 /*
35674     highlight : function(){
35675         this.el.addClass("x-layout-panel-dragover");
35676     },
35677
35678     unhighlight : function(){
35679         this.el.removeClass("x-layout-panel-dragover");
35680     },
35681 */
35682     updateBox : function(box)
35683     {
35684         if (!this.bodyEl) {
35685             return; // not rendered yet..
35686         }
35687         
35688         this.box = box;
35689         if(!this.collapsed){
35690             this.el.dom.style.left = box.x + "px";
35691             this.el.dom.style.top = box.y + "px";
35692             this.updateBody(box.width, box.height);
35693         }else{
35694             this.collapsedEl.dom.style.left = box.x + "px";
35695             this.collapsedEl.dom.style.top = box.y + "px";
35696             this.collapsedEl.setSize(box.width, box.height);
35697         }
35698         if(this.tabs){
35699             this.tabs.autoSizeTabs();
35700         }
35701     },
35702
35703     updateBody : function(w, h)
35704     {
35705         if(w !== null){
35706             this.el.setWidth(w);
35707             w -= this.el.getBorderWidth("rl");
35708             if(this.config.adjustments){
35709                 w += this.config.adjustments[0];
35710             }
35711         }
35712         if(h !== null && h > 0){
35713             this.el.setHeight(h);
35714             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35715             h -= this.el.getBorderWidth("tb");
35716             if(this.config.adjustments){
35717                 h += this.config.adjustments[1];
35718             }
35719             this.bodyEl.setHeight(h);
35720             if(this.tabs){
35721                 h = this.tabs.syncHeight(h);
35722             }
35723         }
35724         if(this.panelSize){
35725             w = w !== null ? w : this.panelSize.width;
35726             h = h !== null ? h : this.panelSize.height;
35727         }
35728         if(this.activePanel){
35729             var el = this.activePanel.getEl();
35730             w = w !== null ? w : el.getWidth();
35731             h = h !== null ? h : el.getHeight();
35732             this.panelSize = {width: w, height: h};
35733             this.activePanel.setSize(w, h);
35734         }
35735         if(Roo.isIE && this.tabs){
35736             this.tabs.el.repaint();
35737         }
35738     },
35739
35740     /**
35741      * Returns the container element for this region.
35742      * @return {Roo.Element}
35743      */
35744     getEl : function(){
35745         return this.el;
35746     },
35747
35748     /**
35749      * Hides this region.
35750      */
35751     hide : function(){
35752         //if(!this.collapsed){
35753             this.el.dom.style.left = "-2000px";
35754             this.el.hide();
35755         //}else{
35756          //   this.collapsedEl.dom.style.left = "-2000px";
35757          //   this.collapsedEl.hide();
35758        // }
35759         this.visible = false;
35760         this.fireEvent("visibilitychange", this, false);
35761     },
35762
35763     /**
35764      * Shows this region if it was previously hidden.
35765      */
35766     show : function(){
35767         //if(!this.collapsed){
35768             this.el.show();
35769         //}else{
35770         //    this.collapsedEl.show();
35771        // }
35772         this.visible = true;
35773         this.fireEvent("visibilitychange", this, true);
35774     },
35775 /*
35776     closeClicked : function(){
35777         if(this.activePanel){
35778             this.remove(this.activePanel);
35779         }
35780     },
35781
35782     collapseClick : function(e){
35783         if(this.isSlid){
35784            e.stopPropagation();
35785            this.slideIn();
35786         }else{
35787            e.stopPropagation();
35788            this.slideOut();
35789         }
35790     },
35791 */
35792     /**
35793      * Collapses this region.
35794      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35795      */
35796     /*
35797     collapse : function(skipAnim, skipCheck = false){
35798         if(this.collapsed) {
35799             return;
35800         }
35801         
35802         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35803             
35804             this.collapsed = true;
35805             if(this.split){
35806                 this.split.el.hide();
35807             }
35808             if(this.config.animate && skipAnim !== true){
35809                 this.fireEvent("invalidated", this);
35810                 this.animateCollapse();
35811             }else{
35812                 this.el.setLocation(-20000,-20000);
35813                 this.el.hide();
35814                 this.collapsedEl.show();
35815                 this.fireEvent("collapsed", this);
35816                 this.fireEvent("invalidated", this);
35817             }
35818         }
35819         
35820     },
35821 */
35822     animateCollapse : function(){
35823         // overridden
35824     },
35825
35826     /**
35827      * Expands this region if it was previously collapsed.
35828      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35829      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35830      */
35831     /*
35832     expand : function(e, skipAnim){
35833         if(e) {
35834             e.stopPropagation();
35835         }
35836         if(!this.collapsed || this.el.hasActiveFx()) {
35837             return;
35838         }
35839         if(this.isSlid){
35840             this.afterSlideIn();
35841             skipAnim = true;
35842         }
35843         this.collapsed = false;
35844         if(this.config.animate && skipAnim !== true){
35845             this.animateExpand();
35846         }else{
35847             this.el.show();
35848             if(this.split){
35849                 this.split.el.show();
35850             }
35851             this.collapsedEl.setLocation(-2000,-2000);
35852             this.collapsedEl.hide();
35853             this.fireEvent("invalidated", this);
35854             this.fireEvent("expanded", this);
35855         }
35856     },
35857 */
35858     animateExpand : function(){
35859         // overridden
35860     },
35861
35862     initTabs : function()
35863     {
35864         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35865         
35866         var ts = new Roo.bootstrap.panel.Tabs({
35867                 el: this.bodyEl.dom,
35868                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35869                 disableTooltips: this.config.disableTabTips,
35870                 toolbar : this.config.toolbar
35871             });
35872         
35873         if(this.config.hideTabs){
35874             ts.stripWrap.setDisplayed(false);
35875         }
35876         this.tabs = ts;
35877         ts.resizeTabs = this.config.resizeTabs === true;
35878         ts.minTabWidth = this.config.minTabWidth || 40;
35879         ts.maxTabWidth = this.config.maxTabWidth || 250;
35880         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35881         ts.monitorResize = false;
35882         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35883         ts.bodyEl.addClass('roo-layout-tabs-body');
35884         this.panels.each(this.initPanelAsTab, this);
35885     },
35886
35887     initPanelAsTab : function(panel){
35888         var ti = this.tabs.addTab(
35889             panel.getEl().id,
35890             panel.getTitle(),
35891             null,
35892             this.config.closeOnTab && panel.isClosable(),
35893             panel.tpl
35894         );
35895         if(panel.tabTip !== undefined){
35896             ti.setTooltip(panel.tabTip);
35897         }
35898         ti.on("activate", function(){
35899               this.setActivePanel(panel);
35900         }, this);
35901         
35902         if(this.config.closeOnTab){
35903             ti.on("beforeclose", function(t, e){
35904                 e.cancel = true;
35905                 this.remove(panel);
35906             }, this);
35907         }
35908         
35909         panel.tabItem = ti;
35910         
35911         return ti;
35912     },
35913
35914     updatePanelTitle : function(panel, title)
35915     {
35916         if(this.activePanel == panel){
35917             this.updateTitle(title);
35918         }
35919         if(this.tabs){
35920             var ti = this.tabs.getTab(panel.getEl().id);
35921             ti.setText(title);
35922             if(panel.tabTip !== undefined){
35923                 ti.setTooltip(panel.tabTip);
35924             }
35925         }
35926     },
35927
35928     updateTitle : function(title){
35929         if(this.titleTextEl && !this.config.title){
35930             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35931         }
35932     },
35933
35934     setActivePanel : function(panel)
35935     {
35936         panel = this.getPanel(panel);
35937         if(this.activePanel && this.activePanel != panel){
35938             if(this.activePanel.setActiveState(false) === false){
35939                 return;
35940             }
35941         }
35942         this.activePanel = panel;
35943         panel.setActiveState(true);
35944         if(this.panelSize){
35945             panel.setSize(this.panelSize.width, this.panelSize.height);
35946         }
35947         if(this.closeBtn){
35948             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35949         }
35950         this.updateTitle(panel.getTitle());
35951         if(this.tabs){
35952             this.fireEvent("invalidated", this);
35953         }
35954         this.fireEvent("panelactivated", this, panel);
35955     },
35956
35957     /**
35958      * Shows the specified panel.
35959      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35960      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35961      */
35962     showPanel : function(panel)
35963     {
35964         panel = this.getPanel(panel);
35965         if(panel){
35966             if(this.tabs){
35967                 var tab = this.tabs.getTab(panel.getEl().id);
35968                 if(tab.isHidden()){
35969                     this.tabs.unhideTab(tab.id);
35970                 }
35971                 tab.activate();
35972             }else{
35973                 this.setActivePanel(panel);
35974             }
35975         }
35976         return panel;
35977     },
35978
35979     /**
35980      * Get the active panel for this region.
35981      * @return {Roo.ContentPanel} The active panel or null
35982      */
35983     getActivePanel : function(){
35984         return this.activePanel;
35985     },
35986
35987     validateVisibility : function(){
35988         if(this.panels.getCount() < 1){
35989             this.updateTitle("&#160;");
35990             this.closeBtn.hide();
35991             this.hide();
35992         }else{
35993             if(!this.isVisible()){
35994                 this.show();
35995             }
35996         }
35997     },
35998
35999     /**
36000      * Adds the passed ContentPanel(s) to this region.
36001      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36002      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36003      */
36004     add : function(panel)
36005     {
36006         if(arguments.length > 1){
36007             for(var i = 0, len = arguments.length; i < len; i++) {
36008                 this.add(arguments[i]);
36009             }
36010             return null;
36011         }
36012         
36013         // if we have not been rendered yet, then we can not really do much of this..
36014         if (!this.bodyEl) {
36015             this.unrendered_panels.push(panel);
36016             return panel;
36017         }
36018         
36019         
36020         
36021         
36022         if(this.hasPanel(panel)){
36023             this.showPanel(panel);
36024             return panel;
36025         }
36026         panel.setRegion(this);
36027         this.panels.add(panel);
36028        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36029             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36030             // and hide them... ???
36031             this.bodyEl.dom.appendChild(panel.getEl().dom);
36032             if(panel.background !== true){
36033                 this.setActivePanel(panel);
36034             }
36035             this.fireEvent("paneladded", this, panel);
36036             return panel;
36037         }
36038         */
36039         if(!this.tabs){
36040             this.initTabs();
36041         }else{
36042             this.initPanelAsTab(panel);
36043         }
36044         
36045         
36046         if(panel.background !== true){
36047             this.tabs.activate(panel.getEl().id);
36048         }
36049         this.fireEvent("paneladded", this, panel);
36050         return panel;
36051     },
36052
36053     /**
36054      * Hides the tab for the specified panel.
36055      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36056      */
36057     hidePanel : function(panel){
36058         if(this.tabs && (panel = this.getPanel(panel))){
36059             this.tabs.hideTab(panel.getEl().id);
36060         }
36061     },
36062
36063     /**
36064      * Unhides the tab for a previously hidden panel.
36065      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36066      */
36067     unhidePanel : function(panel){
36068         if(this.tabs && (panel = this.getPanel(panel))){
36069             this.tabs.unhideTab(panel.getEl().id);
36070         }
36071     },
36072
36073     clearPanels : function(){
36074         while(this.panels.getCount() > 0){
36075              this.remove(this.panels.first());
36076         }
36077     },
36078
36079     /**
36080      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36081      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36082      * @param {Boolean} preservePanel Overrides the config preservePanel option
36083      * @return {Roo.ContentPanel} The panel that was removed
36084      */
36085     remove : function(panel, preservePanel)
36086     {
36087         panel = this.getPanel(panel);
36088         if(!panel){
36089             return null;
36090         }
36091         var e = {};
36092         this.fireEvent("beforeremove", this, panel, e);
36093         if(e.cancel === true){
36094             return null;
36095         }
36096         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36097         var panelId = panel.getId();
36098         this.panels.removeKey(panelId);
36099         if(preservePanel){
36100             document.body.appendChild(panel.getEl().dom);
36101         }
36102         if(this.tabs){
36103             this.tabs.removeTab(panel.getEl().id);
36104         }else if (!preservePanel){
36105             this.bodyEl.dom.removeChild(panel.getEl().dom);
36106         }
36107         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36108             var p = this.panels.first();
36109             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36110             tempEl.appendChild(p.getEl().dom);
36111             this.bodyEl.update("");
36112             this.bodyEl.dom.appendChild(p.getEl().dom);
36113             tempEl = null;
36114             this.updateTitle(p.getTitle());
36115             this.tabs = null;
36116             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36117             this.setActivePanel(p);
36118         }
36119         panel.setRegion(null);
36120         if(this.activePanel == panel){
36121             this.activePanel = null;
36122         }
36123         if(this.config.autoDestroy !== false && preservePanel !== true){
36124             try{panel.destroy();}catch(e){}
36125         }
36126         this.fireEvent("panelremoved", this, panel);
36127         return panel;
36128     },
36129
36130     /**
36131      * Returns the TabPanel component used by this region
36132      * @return {Roo.TabPanel}
36133      */
36134     getTabs : function(){
36135         return this.tabs;
36136     },
36137
36138     createTool : function(parentEl, className){
36139         var btn = Roo.DomHelper.append(parentEl, {
36140             tag: "div",
36141             cls: "x-layout-tools-button",
36142             children: [ {
36143                 tag: "div",
36144                 cls: "roo-layout-tools-button-inner " + className,
36145                 html: "&#160;"
36146             }]
36147         }, true);
36148         btn.addClassOnOver("roo-layout-tools-button-over");
36149         return btn;
36150     }
36151 });/*
36152  * Based on:
36153  * Ext JS Library 1.1.1
36154  * Copyright(c) 2006-2007, Ext JS, LLC.
36155  *
36156  * Originally Released Under LGPL - original licence link has changed is not relivant.
36157  *
36158  * Fork - LGPL
36159  * <script type="text/javascript">
36160  */
36161  
36162
36163
36164 /**
36165  * @class Roo.SplitLayoutRegion
36166  * @extends Roo.LayoutRegion
36167  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36168  */
36169 Roo.bootstrap.layout.Split = function(config){
36170     this.cursor = config.cursor;
36171     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36172 };
36173
36174 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36175 {
36176     splitTip : "Drag to resize.",
36177     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36178     useSplitTips : false,
36179
36180     applyConfig : function(config){
36181         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36182     },
36183     
36184     onRender : function(ctr,pos) {
36185         
36186         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36187         if(!this.config.split){
36188             return;
36189         }
36190         if(!this.split){
36191             
36192             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36193                             tag: "div",
36194                             id: this.el.id + "-split",
36195                             cls: "roo-layout-split roo-layout-split-"+this.position,
36196                             html: "&#160;"
36197             });
36198             /** The SplitBar for this region 
36199             * @type Roo.SplitBar */
36200             // does not exist yet...
36201             Roo.log([this.position, this.orientation]);
36202             
36203             this.split = new Roo.bootstrap.SplitBar({
36204                 dragElement : splitEl,
36205                 resizingElement: this.el,
36206                 orientation : this.orientation
36207             });
36208             
36209             this.split.on("moved", this.onSplitMove, this);
36210             this.split.useShim = this.config.useShim === true;
36211             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36212             if(this.useSplitTips){
36213                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36214             }
36215             //if(config.collapsible){
36216             //    this.split.el.on("dblclick", this.collapse,  this);
36217             //}
36218         }
36219         if(typeof this.config.minSize != "undefined"){
36220             this.split.minSize = this.config.minSize;
36221         }
36222         if(typeof this.config.maxSize != "undefined"){
36223             this.split.maxSize = this.config.maxSize;
36224         }
36225         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36226             this.hideSplitter();
36227         }
36228         
36229     },
36230
36231     getHMaxSize : function(){
36232          var cmax = this.config.maxSize || 10000;
36233          var center = this.mgr.getRegion("center");
36234          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36235     },
36236
36237     getVMaxSize : function(){
36238          var cmax = this.config.maxSize || 10000;
36239          var center = this.mgr.getRegion("center");
36240          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36241     },
36242
36243     onSplitMove : function(split, newSize){
36244         this.fireEvent("resized", this, newSize);
36245     },
36246     
36247     /** 
36248      * Returns the {@link Roo.SplitBar} for this region.
36249      * @return {Roo.SplitBar}
36250      */
36251     getSplitBar : function(){
36252         return this.split;
36253     },
36254     
36255     hide : function(){
36256         this.hideSplitter();
36257         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36258     },
36259
36260     hideSplitter : function(){
36261         if(this.split){
36262             this.split.el.setLocation(-2000,-2000);
36263             this.split.el.hide();
36264         }
36265     },
36266
36267     show : function(){
36268         if(this.split){
36269             this.split.el.show();
36270         }
36271         Roo.bootstrap.layout.Split.superclass.show.call(this);
36272     },
36273     
36274     beforeSlide: function(){
36275         if(Roo.isGecko){// firefox overflow auto bug workaround
36276             this.bodyEl.clip();
36277             if(this.tabs) {
36278                 this.tabs.bodyEl.clip();
36279             }
36280             if(this.activePanel){
36281                 this.activePanel.getEl().clip();
36282                 
36283                 if(this.activePanel.beforeSlide){
36284                     this.activePanel.beforeSlide();
36285                 }
36286             }
36287         }
36288     },
36289     
36290     afterSlide : function(){
36291         if(Roo.isGecko){// firefox overflow auto bug workaround
36292             this.bodyEl.unclip();
36293             if(this.tabs) {
36294                 this.tabs.bodyEl.unclip();
36295             }
36296             if(this.activePanel){
36297                 this.activePanel.getEl().unclip();
36298                 if(this.activePanel.afterSlide){
36299                     this.activePanel.afterSlide();
36300                 }
36301             }
36302         }
36303     },
36304
36305     initAutoHide : function(){
36306         if(this.autoHide !== false){
36307             if(!this.autoHideHd){
36308                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36309                 this.autoHideHd = {
36310                     "mouseout": function(e){
36311                         if(!e.within(this.el, true)){
36312                             st.delay(500);
36313                         }
36314                     },
36315                     "mouseover" : function(e){
36316                         st.cancel();
36317                     },
36318                     scope : this
36319                 };
36320             }
36321             this.el.on(this.autoHideHd);
36322         }
36323     },
36324
36325     clearAutoHide : function(){
36326         if(this.autoHide !== false){
36327             this.el.un("mouseout", this.autoHideHd.mouseout);
36328             this.el.un("mouseover", this.autoHideHd.mouseover);
36329         }
36330     },
36331
36332     clearMonitor : function(){
36333         Roo.get(document).un("click", this.slideInIf, this);
36334     },
36335
36336     // these names are backwards but not changed for compat
36337     slideOut : function(){
36338         if(this.isSlid || this.el.hasActiveFx()){
36339             return;
36340         }
36341         this.isSlid = true;
36342         if(this.collapseBtn){
36343             this.collapseBtn.hide();
36344         }
36345         this.closeBtnState = this.closeBtn.getStyle('display');
36346         this.closeBtn.hide();
36347         if(this.stickBtn){
36348             this.stickBtn.show();
36349         }
36350         this.el.show();
36351         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36352         this.beforeSlide();
36353         this.el.setStyle("z-index", 10001);
36354         this.el.slideIn(this.getSlideAnchor(), {
36355             callback: function(){
36356                 this.afterSlide();
36357                 this.initAutoHide();
36358                 Roo.get(document).on("click", this.slideInIf, this);
36359                 this.fireEvent("slideshow", this);
36360             },
36361             scope: this,
36362             block: true
36363         });
36364     },
36365
36366     afterSlideIn : function(){
36367         this.clearAutoHide();
36368         this.isSlid = false;
36369         this.clearMonitor();
36370         this.el.setStyle("z-index", "");
36371         if(this.collapseBtn){
36372             this.collapseBtn.show();
36373         }
36374         this.closeBtn.setStyle('display', this.closeBtnState);
36375         if(this.stickBtn){
36376             this.stickBtn.hide();
36377         }
36378         this.fireEvent("slidehide", this);
36379     },
36380
36381     slideIn : function(cb){
36382         if(!this.isSlid || this.el.hasActiveFx()){
36383             Roo.callback(cb);
36384             return;
36385         }
36386         this.isSlid = false;
36387         this.beforeSlide();
36388         this.el.slideOut(this.getSlideAnchor(), {
36389             callback: function(){
36390                 this.el.setLeftTop(-10000, -10000);
36391                 this.afterSlide();
36392                 this.afterSlideIn();
36393                 Roo.callback(cb);
36394             },
36395             scope: this,
36396             block: true
36397         });
36398     },
36399     
36400     slideInIf : function(e){
36401         if(!e.within(this.el)){
36402             this.slideIn();
36403         }
36404     },
36405
36406     animateCollapse : function(){
36407         this.beforeSlide();
36408         this.el.setStyle("z-index", 20000);
36409         var anchor = this.getSlideAnchor();
36410         this.el.slideOut(anchor, {
36411             callback : function(){
36412                 this.el.setStyle("z-index", "");
36413                 this.collapsedEl.slideIn(anchor, {duration:.3});
36414                 this.afterSlide();
36415                 this.el.setLocation(-10000,-10000);
36416                 this.el.hide();
36417                 this.fireEvent("collapsed", this);
36418             },
36419             scope: this,
36420             block: true
36421         });
36422     },
36423
36424     animateExpand : function(){
36425         this.beforeSlide();
36426         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36427         this.el.setStyle("z-index", 20000);
36428         this.collapsedEl.hide({
36429             duration:.1
36430         });
36431         this.el.slideIn(this.getSlideAnchor(), {
36432             callback : function(){
36433                 this.el.setStyle("z-index", "");
36434                 this.afterSlide();
36435                 if(this.split){
36436                     this.split.el.show();
36437                 }
36438                 this.fireEvent("invalidated", this);
36439                 this.fireEvent("expanded", this);
36440             },
36441             scope: this,
36442             block: true
36443         });
36444     },
36445
36446     anchors : {
36447         "west" : "left",
36448         "east" : "right",
36449         "north" : "top",
36450         "south" : "bottom"
36451     },
36452
36453     sanchors : {
36454         "west" : "l",
36455         "east" : "r",
36456         "north" : "t",
36457         "south" : "b"
36458     },
36459
36460     canchors : {
36461         "west" : "tl-tr",
36462         "east" : "tr-tl",
36463         "north" : "tl-bl",
36464         "south" : "bl-tl"
36465     },
36466
36467     getAnchor : function(){
36468         return this.anchors[this.position];
36469     },
36470
36471     getCollapseAnchor : function(){
36472         return this.canchors[this.position];
36473     },
36474
36475     getSlideAnchor : function(){
36476         return this.sanchors[this.position];
36477     },
36478
36479     getAlignAdj : function(){
36480         var cm = this.cmargins;
36481         switch(this.position){
36482             case "west":
36483                 return [0, 0];
36484             break;
36485             case "east":
36486                 return [0, 0];
36487             break;
36488             case "north":
36489                 return [0, 0];
36490             break;
36491             case "south":
36492                 return [0, 0];
36493             break;
36494         }
36495     },
36496
36497     getExpandAdj : function(){
36498         var c = this.collapsedEl, cm = this.cmargins;
36499         switch(this.position){
36500             case "west":
36501                 return [-(cm.right+c.getWidth()+cm.left), 0];
36502             break;
36503             case "east":
36504                 return [cm.right+c.getWidth()+cm.left, 0];
36505             break;
36506             case "north":
36507                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36508             break;
36509             case "south":
36510                 return [0, cm.top+cm.bottom+c.getHeight()];
36511             break;
36512         }
36513     }
36514 });/*
36515  * Based on:
36516  * Ext JS Library 1.1.1
36517  * Copyright(c) 2006-2007, Ext JS, LLC.
36518  *
36519  * Originally Released Under LGPL - original licence link has changed is not relivant.
36520  *
36521  * Fork - LGPL
36522  * <script type="text/javascript">
36523  */
36524 /*
36525  * These classes are private internal classes
36526  */
36527 Roo.bootstrap.layout.Center = function(config){
36528     config.region = "center";
36529     Roo.bootstrap.layout.Region.call(this, config);
36530     this.visible = true;
36531     this.minWidth = config.minWidth || 20;
36532     this.minHeight = config.minHeight || 20;
36533 };
36534
36535 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36536     hide : function(){
36537         // center panel can't be hidden
36538     },
36539     
36540     show : function(){
36541         // center panel can't be hidden
36542     },
36543     
36544     getMinWidth: function(){
36545         return this.minWidth;
36546     },
36547     
36548     getMinHeight: function(){
36549         return this.minHeight;
36550     }
36551 });
36552
36553
36554
36555
36556  
36557
36558
36559
36560
36561
36562 Roo.bootstrap.layout.North = function(config)
36563 {
36564     config.region = 'north';
36565     config.cursor = 'n-resize';
36566     
36567     Roo.bootstrap.layout.Split.call(this, config);
36568     
36569     
36570     if(this.split){
36571         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36572         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36573         this.split.el.addClass("roo-layout-split-v");
36574     }
36575     var size = config.initialSize || config.height;
36576     if(typeof size != "undefined"){
36577         this.el.setHeight(size);
36578     }
36579 };
36580 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36581 {
36582     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36583     
36584     
36585     
36586     getBox : function(){
36587         if(this.collapsed){
36588             return this.collapsedEl.getBox();
36589         }
36590         var box = this.el.getBox();
36591         if(this.split){
36592             box.height += this.split.el.getHeight();
36593         }
36594         return box;
36595     },
36596     
36597     updateBox : function(box){
36598         if(this.split && !this.collapsed){
36599             box.height -= this.split.el.getHeight();
36600             this.split.el.setLeft(box.x);
36601             this.split.el.setTop(box.y+box.height);
36602             this.split.el.setWidth(box.width);
36603         }
36604         if(this.collapsed){
36605             this.updateBody(box.width, null);
36606         }
36607         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36608     }
36609 });
36610
36611
36612
36613
36614
36615 Roo.bootstrap.layout.South = function(config){
36616     config.region = 'south';
36617     config.cursor = 's-resize';
36618     Roo.bootstrap.layout.Split.call(this, config);
36619     if(this.split){
36620         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36621         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36622         this.split.el.addClass("roo-layout-split-v");
36623     }
36624     var size = config.initialSize || config.height;
36625     if(typeof size != "undefined"){
36626         this.el.setHeight(size);
36627     }
36628 };
36629
36630 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36631     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36632     getBox : function(){
36633         if(this.collapsed){
36634             return this.collapsedEl.getBox();
36635         }
36636         var box = this.el.getBox();
36637         if(this.split){
36638             var sh = this.split.el.getHeight();
36639             box.height += sh;
36640             box.y -= sh;
36641         }
36642         return box;
36643     },
36644     
36645     updateBox : function(box){
36646         if(this.split && !this.collapsed){
36647             var sh = this.split.el.getHeight();
36648             box.height -= sh;
36649             box.y += sh;
36650             this.split.el.setLeft(box.x);
36651             this.split.el.setTop(box.y-sh);
36652             this.split.el.setWidth(box.width);
36653         }
36654         if(this.collapsed){
36655             this.updateBody(box.width, null);
36656         }
36657         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36658     }
36659 });
36660
36661 Roo.bootstrap.layout.East = function(config){
36662     config.region = "east";
36663     config.cursor = "e-resize";
36664     Roo.bootstrap.layout.Split.call(this, config);
36665     if(this.split){
36666         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36667         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36668         this.split.el.addClass("roo-layout-split-h");
36669     }
36670     var size = config.initialSize || config.width;
36671     if(typeof size != "undefined"){
36672         this.el.setWidth(size);
36673     }
36674 };
36675 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36676     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36677     getBox : function(){
36678         if(this.collapsed){
36679             return this.collapsedEl.getBox();
36680         }
36681         var box = this.el.getBox();
36682         if(this.split){
36683             var sw = this.split.el.getWidth();
36684             box.width += sw;
36685             box.x -= sw;
36686         }
36687         return box;
36688     },
36689
36690     updateBox : function(box){
36691         if(this.split && !this.collapsed){
36692             var sw = this.split.el.getWidth();
36693             box.width -= sw;
36694             this.split.el.setLeft(box.x);
36695             this.split.el.setTop(box.y);
36696             this.split.el.setHeight(box.height);
36697             box.x += sw;
36698         }
36699         if(this.collapsed){
36700             this.updateBody(null, box.height);
36701         }
36702         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36703     }
36704 });
36705
36706 Roo.bootstrap.layout.West = function(config){
36707     config.region = "west";
36708     config.cursor = "w-resize";
36709     
36710     Roo.bootstrap.layout.Split.call(this, config);
36711     if(this.split){
36712         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36713         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36714         this.split.el.addClass("roo-layout-split-h");
36715     }
36716     
36717 };
36718 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36719     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36720     
36721     onRender: function(ctr, pos)
36722     {
36723         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36724         var size = this.config.initialSize || this.config.width;
36725         if(typeof size != "undefined"){
36726             this.el.setWidth(size);
36727         }
36728     },
36729     
36730     getBox : function(){
36731         if(this.collapsed){
36732             return this.collapsedEl.getBox();
36733         }
36734         var box = this.el.getBox();
36735         if(this.split){
36736             box.width += this.split.el.getWidth();
36737         }
36738         return box;
36739     },
36740     
36741     updateBox : function(box){
36742         if(this.split && !this.collapsed){
36743             var sw = this.split.el.getWidth();
36744             box.width -= sw;
36745             this.split.el.setLeft(box.x+box.width);
36746             this.split.el.setTop(box.y);
36747             this.split.el.setHeight(box.height);
36748         }
36749         if(this.collapsed){
36750             this.updateBody(null, box.height);
36751         }
36752         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36753     }
36754 });
36755 Roo.namespace("Roo.bootstrap.panel");/*
36756  * Based on:
36757  * Ext JS Library 1.1.1
36758  * Copyright(c) 2006-2007, Ext JS, LLC.
36759  *
36760  * Originally Released Under LGPL - original licence link has changed is not relivant.
36761  *
36762  * Fork - LGPL
36763  * <script type="text/javascript">
36764  */
36765 /**
36766  * @class Roo.ContentPanel
36767  * @extends Roo.util.Observable
36768  * A basic ContentPanel element.
36769  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36770  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36771  * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
36772  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36773  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36774  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36775  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36776  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36777  * @cfg {String} title          The title for this panel
36778  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36779  * @cfg {String} url            Calls {@link #setUrl} with this value
36780  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36781  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36782  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36783  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36784  * @cfg {Boolean} badges render the badges
36785
36786  * @constructor
36787  * Create a new ContentPanel.
36788  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36789  * @param {String/Object} config A string to set only the title or a config object
36790  * @param {String} content (optional) Set the HTML content for this panel
36791  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36792  */
36793 Roo.bootstrap.panel.Content = function( config){
36794     
36795     this.tpl = config.tpl || false;
36796     
36797     var el = config.el;
36798     var content = config.content;
36799
36800     if(config.autoCreate){ // xtype is available if this is called from factory
36801         el = Roo.id();
36802     }
36803     this.el = Roo.get(el);
36804     if(!this.el && config && config.autoCreate){
36805         if(typeof config.autoCreate == "object"){
36806             if(!config.autoCreate.id){
36807                 config.autoCreate.id = config.id||el;
36808             }
36809             this.el = Roo.DomHelper.append(document.body,
36810                         config.autoCreate, true);
36811         }else{
36812             var elcfg =  {   tag: "div",
36813                             cls: "roo-layout-inactive-content",
36814                             id: config.id||el
36815                             };
36816             if (config.html) {
36817                 elcfg.html = config.html;
36818                 
36819             }
36820                         
36821             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36822         }
36823     } 
36824     this.closable = false;
36825     this.loaded = false;
36826     this.active = false;
36827    
36828       
36829     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36830         
36831         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36832         
36833         this.wrapEl = this.el; //this.el.wrap();
36834         var ti = [];
36835         if (config.toolbar.items) {
36836             ti = config.toolbar.items ;
36837             delete config.toolbar.items ;
36838         }
36839         
36840         var nitems = [];
36841         this.toolbar.render(this.wrapEl, 'before');
36842         for(var i =0;i < ti.length;i++) {
36843           //  Roo.log(['add child', items[i]]);
36844             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36845         }
36846         this.toolbar.items = nitems;
36847         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36848         delete config.toolbar;
36849         
36850     }
36851     /*
36852     // xtype created footer. - not sure if will work as we normally have to render first..
36853     if (this.footer && !this.footer.el && this.footer.xtype) {
36854         if (!this.wrapEl) {
36855             this.wrapEl = this.el.wrap();
36856         }
36857     
36858         this.footer.container = this.wrapEl.createChild();
36859          
36860         this.footer = Roo.factory(this.footer, Roo);
36861         
36862     }
36863     */
36864     
36865      if(typeof config == "string"){
36866         this.title = config;
36867     }else{
36868         Roo.apply(this, config);
36869     }
36870     
36871     if(this.resizeEl){
36872         this.resizeEl = Roo.get(this.resizeEl, true);
36873     }else{
36874         this.resizeEl = this.el;
36875     }
36876     // handle view.xtype
36877     
36878  
36879     
36880     
36881     this.addEvents({
36882         /**
36883          * @event activate
36884          * Fires when this panel is activated. 
36885          * @param {Roo.ContentPanel} this
36886          */
36887         "activate" : true,
36888         /**
36889          * @event deactivate
36890          * Fires when this panel is activated. 
36891          * @param {Roo.ContentPanel} this
36892          */
36893         "deactivate" : true,
36894
36895         /**
36896          * @event resize
36897          * Fires when this panel is resized if fitToFrame is true.
36898          * @param {Roo.ContentPanel} this
36899          * @param {Number} width The width after any component adjustments
36900          * @param {Number} height The height after any component adjustments
36901          */
36902         "resize" : true,
36903         
36904          /**
36905          * @event render
36906          * Fires when this tab is created
36907          * @param {Roo.ContentPanel} this
36908          */
36909         "render" : true
36910         
36911         
36912         
36913     });
36914     
36915
36916     
36917     
36918     if(this.autoScroll){
36919         this.resizeEl.setStyle("overflow", "auto");
36920     } else {
36921         // fix randome scrolling
36922         //this.el.on('scroll', function() {
36923         //    Roo.log('fix random scolling');
36924         //    this.scrollTo('top',0); 
36925         //});
36926     }
36927     content = content || this.content;
36928     if(content){
36929         this.setContent(content);
36930     }
36931     if(config && config.url){
36932         this.setUrl(this.url, this.params, this.loadOnce);
36933     }
36934     
36935     
36936     
36937     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36938     
36939     if (this.view && typeof(this.view.xtype) != 'undefined') {
36940         this.view.el = this.el.appendChild(document.createElement("div"));
36941         this.view = Roo.factory(this.view); 
36942         this.view.render  &&  this.view.render(false, '');  
36943     }
36944     
36945     
36946     this.fireEvent('render', this);
36947 };
36948
36949 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36950     
36951     tabTip : '',
36952     
36953     setRegion : function(region){
36954         this.region = region;
36955         this.setActiveClass(region && !this.background);
36956     },
36957     
36958     
36959     setActiveClass: function(state)
36960     {
36961         if(state){
36962            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36963            this.el.setStyle('position','relative');
36964         }else{
36965            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36966            this.el.setStyle('position', 'absolute');
36967         } 
36968     },
36969     
36970     /**
36971      * Returns the toolbar for this Panel if one was configured. 
36972      * @return {Roo.Toolbar} 
36973      */
36974     getToolbar : function(){
36975         return this.toolbar;
36976     },
36977     
36978     setActiveState : function(active)
36979     {
36980         this.active = active;
36981         this.setActiveClass(active);
36982         if(!active){
36983             if(this.fireEvent("deactivate", this) === false){
36984                 return false;
36985             }
36986             return true;
36987         }
36988         this.fireEvent("activate", this);
36989         return true;
36990     },
36991     /**
36992      * Updates this panel's element
36993      * @param {String} content The new content
36994      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36995     */
36996     setContent : function(content, loadScripts){
36997         this.el.update(content, loadScripts);
36998     },
36999
37000     ignoreResize : function(w, h){
37001         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37002             return true;
37003         }else{
37004             this.lastSize = {width: w, height: h};
37005             return false;
37006         }
37007     },
37008     /**
37009      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37010      * @return {Roo.UpdateManager} The UpdateManager
37011      */
37012     getUpdateManager : function(){
37013         return this.el.getUpdateManager();
37014     },
37015      /**
37016      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37017      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
37018 <pre><code>
37019 panel.load({
37020     url: "your-url.php",
37021     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37022     callback: yourFunction,
37023     scope: yourObject, //(optional scope)
37024     discardUrl: false,
37025     nocache: false,
37026     text: "Loading...",
37027     timeout: 30,
37028     scripts: false
37029 });
37030 </code></pre>
37031      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37032      * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
37033      * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
37034      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37035      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
37036      * @return {Roo.ContentPanel} this
37037      */
37038     load : function(){
37039         var um = this.el.getUpdateManager();
37040         um.update.apply(um, arguments);
37041         return this;
37042     },
37043
37044
37045     /**
37046      * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
37047      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37048      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
37049      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
37050      * @return {Roo.UpdateManager} The UpdateManager
37051      */
37052     setUrl : function(url, params, loadOnce){
37053         if(this.refreshDelegate){
37054             this.removeListener("activate", this.refreshDelegate);
37055         }
37056         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37057         this.on("activate", this.refreshDelegate);
37058         return this.el.getUpdateManager();
37059     },
37060     
37061     _handleRefresh : function(url, params, loadOnce){
37062         if(!loadOnce || !this.loaded){
37063             var updater = this.el.getUpdateManager();
37064             updater.update(url, params, this._setLoaded.createDelegate(this));
37065         }
37066     },
37067     
37068     _setLoaded : function(){
37069         this.loaded = true;
37070     }, 
37071     
37072     /**
37073      * Returns this panel's id
37074      * @return {String} 
37075      */
37076     getId : function(){
37077         return this.el.id;
37078     },
37079     
37080     /** 
37081      * Returns this panel's element - used by regiosn to add.
37082      * @return {Roo.Element} 
37083      */
37084     getEl : function(){
37085         return this.wrapEl || this.el;
37086     },
37087     
37088    
37089     
37090     adjustForComponents : function(width, height)
37091     {
37092         //Roo.log('adjustForComponents ');
37093         if(this.resizeEl != this.el){
37094             width -= this.el.getFrameWidth('lr');
37095             height -= this.el.getFrameWidth('tb');
37096         }
37097         if(this.toolbar){
37098             var te = this.toolbar.getEl();
37099             te.setWidth(width);
37100             height -= te.getHeight();
37101         }
37102         if(this.footer){
37103             var te = this.footer.getEl();
37104             te.setWidth(width);
37105             height -= te.getHeight();
37106         }
37107         
37108         
37109         if(this.adjustments){
37110             width += this.adjustments[0];
37111             height += this.adjustments[1];
37112         }
37113         return {"width": width, "height": height};
37114     },
37115     
37116     setSize : function(width, height){
37117         if(this.fitToFrame && !this.ignoreResize(width, height)){
37118             if(this.fitContainer && this.resizeEl != this.el){
37119                 this.el.setSize(width, height);
37120             }
37121             var size = this.adjustForComponents(width, height);
37122             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37123             this.fireEvent('resize', this, size.width, size.height);
37124         }
37125     },
37126     
37127     /**
37128      * Returns this panel's title
37129      * @return {String} 
37130      */
37131     getTitle : function(){
37132         
37133         if (typeof(this.title) != 'object') {
37134             return this.title;
37135         }
37136         
37137         var t = '';
37138         for (var k in this.title) {
37139             if (!this.title.hasOwnProperty(k)) {
37140                 continue;
37141             }
37142             
37143             if (k.indexOf('-') >= 0) {
37144                 var s = k.split('-');
37145                 for (var i = 0; i<s.length; i++) {
37146                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37147                 }
37148             } else {
37149                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37150             }
37151         }
37152         return t;
37153     },
37154     
37155     /**
37156      * Set this panel's title
37157      * @param {String} title
37158      */
37159     setTitle : function(title){
37160         this.title = title;
37161         if(this.region){
37162             this.region.updatePanelTitle(this, title);
37163         }
37164     },
37165     
37166     /**
37167      * Returns true is this panel was configured to be closable
37168      * @return {Boolean} 
37169      */
37170     isClosable : function(){
37171         return this.closable;
37172     },
37173     
37174     beforeSlide : function(){
37175         this.el.clip();
37176         this.resizeEl.clip();
37177     },
37178     
37179     afterSlide : function(){
37180         this.el.unclip();
37181         this.resizeEl.unclip();
37182     },
37183     
37184     /**
37185      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37186      *   Will fail silently if the {@link #setUrl} method has not been called.
37187      *   This does not activate the panel, just updates its content.
37188      */
37189     refresh : function(){
37190         if(this.refreshDelegate){
37191            this.loaded = false;
37192            this.refreshDelegate();
37193         }
37194     },
37195     
37196     /**
37197      * Destroys this panel
37198      */
37199     destroy : function(){
37200         this.el.removeAllListeners();
37201         var tempEl = document.createElement("span");
37202         tempEl.appendChild(this.el.dom);
37203         tempEl.innerHTML = "";
37204         this.el.remove();
37205         this.el = null;
37206     },
37207     
37208     /**
37209      * form - if the content panel contains a form - this is a reference to it.
37210      * @type {Roo.form.Form}
37211      */
37212     form : false,
37213     /**
37214      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37215      *    This contains a reference to it.
37216      * @type {Roo.View}
37217      */
37218     view : false,
37219     
37220       /**
37221      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37222      * <pre><code>
37223
37224 layout.addxtype({
37225        xtype : 'Form',
37226        items: [ .... ]
37227    }
37228 );
37229
37230 </code></pre>
37231      * @param {Object} cfg Xtype definition of item to add.
37232      */
37233     
37234     
37235     getChildContainer: function () {
37236         return this.getEl();
37237     }
37238     
37239     
37240     /*
37241         var  ret = new Roo.factory(cfg);
37242         return ret;
37243         
37244         
37245         // add form..
37246         if (cfg.xtype.match(/^Form$/)) {
37247             
37248             var el;
37249             //if (this.footer) {
37250             //    el = this.footer.container.insertSibling(false, 'before');
37251             //} else {
37252                 el = this.el.createChild();
37253             //}
37254
37255             this.form = new  Roo.form.Form(cfg);
37256             
37257             
37258             if ( this.form.allItems.length) {
37259                 this.form.render(el.dom);
37260             }
37261             return this.form;
37262         }
37263         // should only have one of theses..
37264         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37265             // views.. should not be just added - used named prop 'view''
37266             
37267             cfg.el = this.el.appendChild(document.createElement("div"));
37268             // factory?
37269             
37270             var ret = new Roo.factory(cfg);
37271              
37272              ret.render && ret.render(false, ''); // render blank..
37273             this.view = ret;
37274             return ret;
37275         }
37276         return false;
37277     }
37278     \*/
37279 });
37280  
37281 /**
37282  * @class Roo.bootstrap.panel.Grid
37283  * @extends Roo.bootstrap.panel.Content
37284  * @constructor
37285  * Create a new GridPanel.
37286  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37287  * @param {Object} config A the config object
37288   
37289  */
37290
37291
37292
37293 Roo.bootstrap.panel.Grid = function(config)
37294 {
37295     
37296       
37297     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37298         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37299
37300     config.el = this.wrapper;
37301     //this.el = this.wrapper;
37302     
37303       if (config.container) {
37304         // ctor'ed from a Border/panel.grid
37305         
37306         
37307         this.wrapper.setStyle("overflow", "hidden");
37308         this.wrapper.addClass('roo-grid-container');
37309
37310     }
37311     
37312     
37313     if(config.toolbar){
37314         var tool_el = this.wrapper.createChild();    
37315         this.toolbar = Roo.factory(config.toolbar);
37316         var ti = [];
37317         if (config.toolbar.items) {
37318             ti = config.toolbar.items ;
37319             delete config.toolbar.items ;
37320         }
37321         
37322         var nitems = [];
37323         this.toolbar.render(tool_el);
37324         for(var i =0;i < ti.length;i++) {
37325           //  Roo.log(['add child', items[i]]);
37326             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37327         }
37328         this.toolbar.items = nitems;
37329         
37330         delete config.toolbar;
37331     }
37332     
37333     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37334     config.grid.scrollBody = true;;
37335     config.grid.monitorWindowResize = false; // turn off autosizing
37336     config.grid.autoHeight = false;
37337     config.grid.autoWidth = false;
37338     
37339     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37340     
37341     if (config.background) {
37342         // render grid on panel activation (if panel background)
37343         this.on('activate', function(gp) {
37344             if (!gp.grid.rendered) {
37345                 gp.grid.render(this.wrapper);
37346                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37347             }
37348         });
37349             
37350     } else {
37351         this.grid.render(this.wrapper);
37352         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37353
37354     }
37355     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37356     // ??? needed ??? config.el = this.wrapper;
37357     
37358     
37359     
37360   
37361     // xtype created footer. - not sure if will work as we normally have to render first..
37362     if (this.footer && !this.footer.el && this.footer.xtype) {
37363         
37364         var ctr = this.grid.getView().getFooterPanel(true);
37365         this.footer.dataSource = this.grid.dataSource;
37366         this.footer = Roo.factory(this.footer, Roo);
37367         this.footer.render(ctr);
37368         
37369     }
37370     
37371     
37372     
37373     
37374      
37375 };
37376
37377 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37378     getId : function(){
37379         return this.grid.id;
37380     },
37381     
37382     /**
37383      * Returns the grid for this panel
37384      * @return {Roo.bootstrap.Table} 
37385      */
37386     getGrid : function(){
37387         return this.grid;    
37388     },
37389     
37390     setSize : function(width, height){
37391         if(!this.ignoreResize(width, height)){
37392             var grid = this.grid;
37393             var size = this.adjustForComponents(width, height);
37394             var gridel = grid.getGridEl();
37395             gridel.setSize(size.width, size.height);
37396             /*
37397             var thd = grid.getGridEl().select('thead',true).first();
37398             var tbd = grid.getGridEl().select('tbody', true).first();
37399             if (tbd) {
37400                 tbd.setSize(width, height - thd.getHeight());
37401             }
37402             */
37403             grid.autoSize();
37404         }
37405     },
37406      
37407     
37408     
37409     beforeSlide : function(){
37410         this.grid.getView().scroller.clip();
37411     },
37412     
37413     afterSlide : function(){
37414         this.grid.getView().scroller.unclip();
37415     },
37416     
37417     destroy : function(){
37418         this.grid.destroy();
37419         delete this.grid;
37420         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37421     }
37422 });
37423
37424 /**
37425  * @class Roo.bootstrap.panel.Nest
37426  * @extends Roo.bootstrap.panel.Content
37427  * @constructor
37428  * Create a new Panel, that can contain a layout.Border.
37429  * 
37430  * 
37431  * @param {Roo.BorderLayout} layout The layout for this panel
37432  * @param {String/Object} config A string to set only the title or a config object
37433  */
37434 Roo.bootstrap.panel.Nest = function(config)
37435 {
37436     // construct with only one argument..
37437     /* FIXME - implement nicer consturctors
37438     if (layout.layout) {
37439         config = layout;
37440         layout = config.layout;
37441         delete config.layout;
37442     }
37443     if (layout.xtype && !layout.getEl) {
37444         // then layout needs constructing..
37445         layout = Roo.factory(layout, Roo);
37446     }
37447     */
37448     
37449     config.el =  config.layout.getEl();
37450     
37451     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37452     
37453     config.layout.monitorWindowResize = false; // turn off autosizing
37454     this.layout = config.layout;
37455     this.layout.getEl().addClass("roo-layout-nested-layout");
37456     
37457     
37458     
37459     
37460 };
37461
37462 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37463
37464     setSize : function(width, height){
37465         if(!this.ignoreResize(width, height)){
37466             var size = this.adjustForComponents(width, height);
37467             var el = this.layout.getEl();
37468             if (size.height < 1) {
37469                 el.setWidth(size.width);   
37470             } else {
37471                 el.setSize(size.width, size.height);
37472             }
37473             var touch = el.dom.offsetWidth;
37474             this.layout.layout();
37475             // ie requires a double layout on the first pass
37476             if(Roo.isIE && !this.initialized){
37477                 this.initialized = true;
37478                 this.layout.layout();
37479             }
37480         }
37481     },
37482     
37483     // activate all subpanels if not currently active..
37484     
37485     setActiveState : function(active){
37486         this.active = active;
37487         this.setActiveClass(active);
37488         
37489         if(!active){
37490             this.fireEvent("deactivate", this);
37491             return;
37492         }
37493         
37494         this.fireEvent("activate", this);
37495         // not sure if this should happen before or after..
37496         if (!this.layout) {
37497             return; // should not happen..
37498         }
37499         var reg = false;
37500         for (var r in this.layout.regions) {
37501             reg = this.layout.getRegion(r);
37502             if (reg.getActivePanel()) {
37503                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37504                 reg.setActivePanel(reg.getActivePanel());
37505                 continue;
37506             }
37507             if (!reg.panels.length) {
37508                 continue;
37509             }
37510             reg.showPanel(reg.getPanel(0));
37511         }
37512         
37513         
37514         
37515         
37516     },
37517     
37518     /**
37519      * Returns the nested BorderLayout for this panel
37520      * @return {Roo.BorderLayout} 
37521      */
37522     getLayout : function(){
37523         return this.layout;
37524     },
37525     
37526      /**
37527      * Adds a xtype elements to the layout of the nested panel
37528      * <pre><code>
37529
37530 panel.addxtype({
37531        xtype : 'ContentPanel',
37532        region: 'west',
37533        items: [ .... ]
37534    }
37535 );
37536
37537 panel.addxtype({
37538         xtype : 'NestedLayoutPanel',
37539         region: 'west',
37540         layout: {
37541            center: { },
37542            west: { }   
37543         },
37544         items : [ ... list of content panels or nested layout panels.. ]
37545    }
37546 );
37547 </code></pre>
37548      * @param {Object} cfg Xtype definition of item to add.
37549      */
37550     addxtype : function(cfg) {
37551         return this.layout.addxtype(cfg);
37552     
37553     }
37554 });        /*
37555  * Based on:
37556  * Ext JS Library 1.1.1
37557  * Copyright(c) 2006-2007, Ext JS, LLC.
37558  *
37559  * Originally Released Under LGPL - original licence link has changed is not relivant.
37560  *
37561  * Fork - LGPL
37562  * <script type="text/javascript">
37563  */
37564 /**
37565  * @class Roo.TabPanel
37566  * @extends Roo.util.Observable
37567  * A lightweight tab container.
37568  * <br><br>
37569  * Usage:
37570  * <pre><code>
37571 // basic tabs 1, built from existing content
37572 var tabs = new Roo.TabPanel("tabs1");
37573 tabs.addTab("script", "View Script");
37574 tabs.addTab("markup", "View Markup");
37575 tabs.activate("script");
37576
37577 // more advanced tabs, built from javascript
37578 var jtabs = new Roo.TabPanel("jtabs");
37579 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37580
37581 // set up the UpdateManager
37582 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37583 var updater = tab2.getUpdateManager();
37584 updater.setDefaultUrl("ajax1.htm");
37585 tab2.on('activate', updater.refresh, updater, true);
37586
37587 // Use setUrl for Ajax loading
37588 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37589 tab3.setUrl("ajax2.htm", null, true);
37590
37591 // Disabled tab
37592 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37593 tab4.disable();
37594
37595 jtabs.activate("jtabs-1");
37596  * </code></pre>
37597  * @constructor
37598  * Create a new TabPanel.
37599  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37600  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37601  */
37602 Roo.bootstrap.panel.Tabs = function(config){
37603     /**
37604     * The container element for this TabPanel.
37605     * @type Roo.Element
37606     */
37607     this.el = Roo.get(config.el);
37608     delete config.el;
37609     if(config){
37610         if(typeof config == "boolean"){
37611             this.tabPosition = config ? "bottom" : "top";
37612         }else{
37613             Roo.apply(this, config);
37614         }
37615     }
37616     
37617     if(this.tabPosition == "bottom"){
37618         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37619         this.el.addClass("roo-tabs-bottom");
37620     }
37621     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37622     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37623     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37624     if(Roo.isIE){
37625         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37626     }
37627     if(this.tabPosition != "bottom"){
37628         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37629          * @type Roo.Element
37630          */
37631         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37632         this.el.addClass("roo-tabs-top");
37633     }
37634     this.items = [];
37635
37636     this.bodyEl.setStyle("position", "relative");
37637
37638     this.active = null;
37639     this.activateDelegate = this.activate.createDelegate(this);
37640
37641     this.addEvents({
37642         /**
37643          * @event tabchange
37644          * Fires when the active tab changes
37645          * @param {Roo.TabPanel} this
37646          * @param {Roo.TabPanelItem} activePanel The new active tab
37647          */
37648         "tabchange": true,
37649         /**
37650          * @event beforetabchange
37651          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37652          * @param {Roo.TabPanel} this
37653          * @param {Object} e Set cancel to true on this object to cancel the tab change
37654          * @param {Roo.TabPanelItem} tab The tab being changed to
37655          */
37656         "beforetabchange" : true
37657     });
37658
37659     Roo.EventManager.onWindowResize(this.onResize, this);
37660     this.cpad = this.el.getPadding("lr");
37661     this.hiddenCount = 0;
37662
37663
37664     // toolbar on the tabbar support...
37665     if (this.toolbar) {
37666         alert("no toolbar support yet");
37667         this.toolbar  = false;
37668         /*
37669         var tcfg = this.toolbar;
37670         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37671         this.toolbar = new Roo.Toolbar(tcfg);
37672         if (Roo.isSafari) {
37673             var tbl = tcfg.container.child('table', true);
37674             tbl.setAttribute('width', '100%');
37675         }
37676         */
37677         
37678     }
37679    
37680
37681
37682     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37683 };
37684
37685 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37686     /*
37687      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37688      */
37689     tabPosition : "top",
37690     /*
37691      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37692      */
37693     currentTabWidth : 0,
37694     /*
37695      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37696      */
37697     minTabWidth : 40,
37698     /*
37699      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37700      */
37701     maxTabWidth : 250,
37702     /*
37703      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37704      */
37705     preferredTabWidth : 175,
37706     /*
37707      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37708      */
37709     resizeTabs : false,
37710     /*
37711      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37712      */
37713     monitorResize : true,
37714     /*
37715      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37716      */
37717     toolbar : false,
37718
37719     /**
37720      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37721      * @param {String} id The id of the div to use <b>or create</b>
37722      * @param {String} text The text for the tab
37723      * @param {String} content (optional) Content to put in the TabPanelItem body
37724      * @param {Boolean} closable (optional) True to create a close icon on the tab
37725      * @return {Roo.TabPanelItem} The created TabPanelItem
37726      */
37727     addTab : function(id, text, content, closable, tpl)
37728     {
37729         var item = new Roo.bootstrap.panel.TabItem({
37730             panel: this,
37731             id : id,
37732             text : text,
37733             closable : closable,
37734             tpl : tpl
37735         });
37736         this.addTabItem(item);
37737         if(content){
37738             item.setContent(content);
37739         }
37740         return item;
37741     },
37742
37743     /**
37744      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37745      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37746      * @return {Roo.TabPanelItem}
37747      */
37748     getTab : function(id){
37749         return this.items[id];
37750     },
37751
37752     /**
37753      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37754      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37755      */
37756     hideTab : function(id){
37757         var t = this.items[id];
37758         if(!t.isHidden()){
37759            t.setHidden(true);
37760            this.hiddenCount++;
37761            this.autoSizeTabs();
37762         }
37763     },
37764
37765     /**
37766      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37767      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37768      */
37769     unhideTab : function(id){
37770         var t = this.items[id];
37771         if(t.isHidden()){
37772            t.setHidden(false);
37773            this.hiddenCount--;
37774            this.autoSizeTabs();
37775         }
37776     },
37777
37778     /**
37779      * Adds an existing {@link Roo.TabPanelItem}.
37780      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37781      */
37782     addTabItem : function(item){
37783         this.items[item.id] = item;
37784         this.items.push(item);
37785       //  if(this.resizeTabs){
37786     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37787   //         this.autoSizeTabs();
37788 //        }else{
37789 //            item.autoSize();
37790        // }
37791     },
37792
37793     /**
37794      * Removes a {@link Roo.TabPanelItem}.
37795      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37796      */
37797     removeTab : function(id){
37798         var items = this.items;
37799         var tab = items[id];
37800         if(!tab) { return; }
37801         var index = items.indexOf(tab);
37802         if(this.active == tab && items.length > 1){
37803             var newTab = this.getNextAvailable(index);
37804             if(newTab) {
37805                 newTab.activate();
37806             }
37807         }
37808         this.stripEl.dom.removeChild(tab.pnode.dom);
37809         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37810             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37811         }
37812         items.splice(index, 1);
37813         delete this.items[tab.id];
37814         tab.fireEvent("close", tab);
37815         tab.purgeListeners();
37816         this.autoSizeTabs();
37817     },
37818
37819     getNextAvailable : function(start){
37820         var items = this.items;
37821         var index = start;
37822         // look for a next tab that will slide over to
37823         // replace the one being removed
37824         while(index < items.length){
37825             var item = items[++index];
37826             if(item && !item.isHidden()){
37827                 return item;
37828             }
37829         }
37830         // if one isn't found select the previous tab (on the left)
37831         index = start;
37832         while(index >= 0){
37833             var item = items[--index];
37834             if(item && !item.isHidden()){
37835                 return item;
37836             }
37837         }
37838         return null;
37839     },
37840
37841     /**
37842      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37843      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37844      */
37845     disableTab : function(id){
37846         var tab = this.items[id];
37847         if(tab && this.active != tab){
37848             tab.disable();
37849         }
37850     },
37851
37852     /**
37853      * Enables a {@link Roo.TabPanelItem} that is disabled.
37854      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37855      */
37856     enableTab : function(id){
37857         var tab = this.items[id];
37858         tab.enable();
37859     },
37860
37861     /**
37862      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37863      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37864      * @return {Roo.TabPanelItem} The TabPanelItem.
37865      */
37866     activate : function(id){
37867         var tab = this.items[id];
37868         if(!tab){
37869             return null;
37870         }
37871         if(tab == this.active || tab.disabled){
37872             return tab;
37873         }
37874         var e = {};
37875         this.fireEvent("beforetabchange", this, e, tab);
37876         if(e.cancel !== true && !tab.disabled){
37877             if(this.active){
37878                 this.active.hide();
37879             }
37880             this.active = this.items[id];
37881             this.active.show();
37882             this.fireEvent("tabchange", this, this.active);
37883         }
37884         return tab;
37885     },
37886
37887     /**
37888      * Gets the active {@link Roo.TabPanelItem}.
37889      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37890      */
37891     getActiveTab : function(){
37892         return this.active;
37893     },
37894
37895     /**
37896      * Updates the tab body element to fit the height of the container element
37897      * for overflow scrolling
37898      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37899      */
37900     syncHeight : function(targetHeight){
37901         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37902         var bm = this.bodyEl.getMargins();
37903         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37904         this.bodyEl.setHeight(newHeight);
37905         return newHeight;
37906     },
37907
37908     onResize : function(){
37909         if(this.monitorResize){
37910             this.autoSizeTabs();
37911         }
37912     },
37913
37914     /**
37915      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37916      */
37917     beginUpdate : function(){
37918         this.updating = true;
37919     },
37920
37921     /**
37922      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37923      */
37924     endUpdate : function(){
37925         this.updating = false;
37926         this.autoSizeTabs();
37927     },
37928
37929     /**
37930      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37931      */
37932     autoSizeTabs : function(){
37933         var count = this.items.length;
37934         var vcount = count - this.hiddenCount;
37935         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37936             return;
37937         }
37938         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37939         var availWidth = Math.floor(w / vcount);
37940         var b = this.stripBody;
37941         if(b.getWidth() > w){
37942             var tabs = this.items;
37943             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37944             if(availWidth < this.minTabWidth){
37945                 /*if(!this.sleft){    // incomplete scrolling code
37946                     this.createScrollButtons();
37947                 }
37948                 this.showScroll();
37949                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37950             }
37951         }else{
37952             if(this.currentTabWidth < this.preferredTabWidth){
37953                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37954             }
37955         }
37956     },
37957
37958     /**
37959      * Returns the number of tabs in this TabPanel.
37960      * @return {Number}
37961      */
37962      getCount : function(){
37963          return this.items.length;
37964      },
37965
37966     /**
37967      * Resizes all the tabs to the passed width
37968      * @param {Number} The new width
37969      */
37970     setTabWidth : function(width){
37971         this.currentTabWidth = width;
37972         for(var i = 0, len = this.items.length; i < len; i++) {
37973                 if(!this.items[i].isHidden()) {
37974                 this.items[i].setWidth(width);
37975             }
37976         }
37977     },
37978
37979     /**
37980      * Destroys this TabPanel
37981      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37982      */
37983     destroy : function(removeEl){
37984         Roo.EventManager.removeResizeListener(this.onResize, this);
37985         for(var i = 0, len = this.items.length; i < len; i++){
37986             this.items[i].purgeListeners();
37987         }
37988         if(removeEl === true){
37989             this.el.update("");
37990             this.el.remove();
37991         }
37992     },
37993     
37994     createStrip : function(container)
37995     {
37996         var strip = document.createElement("nav");
37997         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37998         container.appendChild(strip);
37999         return strip;
38000     },
38001     
38002     createStripList : function(strip)
38003     {
38004         // div wrapper for retard IE
38005         // returns the "tr" element.
38006         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38007         //'<div class="x-tabs-strip-wrap">'+
38008           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38009           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38010         return strip.firstChild; //.firstChild.firstChild.firstChild;
38011     },
38012     createBody : function(container)
38013     {
38014         var body = document.createElement("div");
38015         Roo.id(body, "tab-body");
38016         //Roo.fly(body).addClass("x-tabs-body");
38017         Roo.fly(body).addClass("tab-content");
38018         container.appendChild(body);
38019         return body;
38020     },
38021     createItemBody :function(bodyEl, id){
38022         var body = Roo.getDom(id);
38023         if(!body){
38024             body = document.createElement("div");
38025             body.id = id;
38026         }
38027         //Roo.fly(body).addClass("x-tabs-item-body");
38028         Roo.fly(body).addClass("tab-pane");
38029          bodyEl.insertBefore(body, bodyEl.firstChild);
38030         return body;
38031     },
38032     /** @private */
38033     createStripElements :  function(stripEl, text, closable, tpl)
38034     {
38035         var td = document.createElement("li"); // was td..
38036         
38037         
38038         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38039         
38040         
38041         stripEl.appendChild(td);
38042         /*if(closable){
38043             td.className = "x-tabs-closable";
38044             if(!this.closeTpl){
38045                 this.closeTpl = new Roo.Template(
38046                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38047                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38048                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38049                 );
38050             }
38051             var el = this.closeTpl.overwrite(td, {"text": text});
38052             var close = el.getElementsByTagName("div")[0];
38053             var inner = el.getElementsByTagName("em")[0];
38054             return {"el": el, "close": close, "inner": inner};
38055         } else {
38056         */
38057         // not sure what this is..
38058 //            if(!this.tabTpl){
38059                 //this.tabTpl = new Roo.Template(
38060                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38061                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38062                 //);
38063 //                this.tabTpl = new Roo.Template(
38064 //                   '<a href="#">' +
38065 //                   '<span unselectable="on"' +
38066 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38067 //                            ' >{text}</span></a>'
38068 //                );
38069 //                
38070 //            }
38071
38072
38073             var template = tpl || this.tabTpl || false;
38074             
38075             if(!template){
38076                 
38077                 template = new Roo.Template(
38078                    '<a href="#">' +
38079                    '<span unselectable="on"' +
38080                             (this.disableTooltips ? '' : ' title="{text}"') +
38081                             ' >{text}</span></a>'
38082                 );
38083             }
38084             
38085             switch (typeof(template)) {
38086                 case 'object' :
38087                     break;
38088                 case 'string' :
38089                     template = new Roo.Template(template);
38090                     break;
38091                 default :
38092                     break;
38093             }
38094             
38095             var el = template.overwrite(td, {"text": text});
38096             
38097             var inner = el.getElementsByTagName("span")[0];
38098             
38099             return {"el": el, "inner": inner};
38100             
38101     }
38102         
38103     
38104 });
38105
38106 /**
38107  * @class Roo.TabPanelItem
38108  * @extends Roo.util.Observable
38109  * Represents an individual item (tab plus body) in a TabPanel.
38110  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38111  * @param {String} id The id of this TabPanelItem
38112  * @param {String} text The text for the tab of this TabPanelItem
38113  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38114  */
38115 Roo.bootstrap.panel.TabItem = function(config){
38116     /**
38117      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38118      * @type Roo.TabPanel
38119      */
38120     this.tabPanel = config.panel;
38121     /**
38122      * The id for this TabPanelItem
38123      * @type String
38124      */
38125     this.id = config.id;
38126     /** @private */
38127     this.disabled = false;
38128     /** @private */
38129     this.text = config.text;
38130     /** @private */
38131     this.loaded = false;
38132     this.closable = config.closable;
38133
38134     /**
38135      * The body element for this TabPanelItem.
38136      * @type Roo.Element
38137      */
38138     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38139     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38140     this.bodyEl.setStyle("display", "block");
38141     this.bodyEl.setStyle("zoom", "1");
38142     //this.hideAction();
38143
38144     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38145     /** @private */
38146     this.el = Roo.get(els.el);
38147     this.inner = Roo.get(els.inner, true);
38148     this.textEl = Roo.get(this.el.dom.firstChild, true);
38149     this.pnode = Roo.get(els.el.parentNode, true);
38150 //    this.el.on("mousedown", this.onTabMouseDown, this);
38151     this.el.on("click", this.onTabClick, this);
38152     /** @private */
38153     if(config.closable){
38154         var c = Roo.get(els.close, true);
38155         c.dom.title = this.closeText;
38156         c.addClassOnOver("close-over");
38157         c.on("click", this.closeClick, this);
38158      }
38159
38160     this.addEvents({
38161          /**
38162          * @event activate
38163          * Fires when this tab becomes the active tab.
38164          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38165          * @param {Roo.TabPanelItem} this
38166          */
38167         "activate": true,
38168         /**
38169          * @event beforeclose
38170          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38171          * @param {Roo.TabPanelItem} this
38172          * @param {Object} e Set cancel to true on this object to cancel the close.
38173          */
38174         "beforeclose": true,
38175         /**
38176          * @event close
38177          * Fires when this tab is closed.
38178          * @param {Roo.TabPanelItem} this
38179          */
38180          "close": true,
38181         /**
38182          * @event deactivate
38183          * Fires when this tab is no longer the active tab.
38184          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38185          * @param {Roo.TabPanelItem} this
38186          */
38187          "deactivate" : true
38188     });
38189     this.hidden = false;
38190
38191     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38192 };
38193
38194 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38195            {
38196     purgeListeners : function(){
38197        Roo.util.Observable.prototype.purgeListeners.call(this);
38198        this.el.removeAllListeners();
38199     },
38200     /**
38201      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38202      */
38203     show : function(){
38204         this.pnode.addClass("active");
38205         this.showAction();
38206         if(Roo.isOpera){
38207             this.tabPanel.stripWrap.repaint();
38208         }
38209         this.fireEvent("activate", this.tabPanel, this);
38210     },
38211
38212     /**
38213      * Returns true if this tab is the active tab.
38214      * @return {Boolean}
38215      */
38216     isActive : function(){
38217         return this.tabPanel.getActiveTab() == this;
38218     },
38219
38220     /**
38221      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38222      */
38223     hide : function(){
38224         this.pnode.removeClass("active");
38225         this.hideAction();
38226         this.fireEvent("deactivate", this.tabPanel, this);
38227     },
38228
38229     hideAction : function(){
38230         this.bodyEl.hide();
38231         this.bodyEl.setStyle("position", "absolute");
38232         this.bodyEl.setLeft("-20000px");
38233         this.bodyEl.setTop("-20000px");
38234     },
38235
38236     showAction : function(){
38237         this.bodyEl.setStyle("position", "relative");
38238         this.bodyEl.setTop("");
38239         this.bodyEl.setLeft("");
38240         this.bodyEl.show();
38241     },
38242
38243     /**
38244      * Set the tooltip for the tab.
38245      * @param {String} tooltip The tab's tooltip
38246      */
38247     setTooltip : function(text){
38248         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38249             this.textEl.dom.qtip = text;
38250             this.textEl.dom.removeAttribute('title');
38251         }else{
38252             this.textEl.dom.title = text;
38253         }
38254     },
38255
38256     onTabClick : function(e){
38257         e.preventDefault();
38258         this.tabPanel.activate(this.id);
38259     },
38260
38261     onTabMouseDown : function(e){
38262         e.preventDefault();
38263         this.tabPanel.activate(this.id);
38264     },
38265 /*
38266     getWidth : function(){
38267         return this.inner.getWidth();
38268     },
38269
38270     setWidth : function(width){
38271         var iwidth = width - this.pnode.getPadding("lr");
38272         this.inner.setWidth(iwidth);
38273         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38274         this.pnode.setWidth(width);
38275     },
38276 */
38277     /**
38278      * Show or hide the tab
38279      * @param {Boolean} hidden True to hide or false to show.
38280      */
38281     setHidden : function(hidden){
38282         this.hidden = hidden;
38283         this.pnode.setStyle("display", hidden ? "none" : "");
38284     },
38285
38286     /**
38287      * Returns true if this tab is "hidden"
38288      * @return {Boolean}
38289      */
38290     isHidden : function(){
38291         return this.hidden;
38292     },
38293
38294     /**
38295      * Returns the text for this tab
38296      * @return {String}
38297      */
38298     getText : function(){
38299         return this.text;
38300     },
38301     /*
38302     autoSize : function(){
38303         //this.el.beginMeasure();
38304         this.textEl.setWidth(1);
38305         /*
38306          *  #2804 [new] Tabs in Roojs
38307          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38308          */
38309         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38310         //this.el.endMeasure();
38311     //},
38312
38313     /**
38314      * Sets the text for the tab (Note: this also sets the tooltip text)
38315      * @param {String} text The tab's text and tooltip
38316      */
38317     setText : function(text){
38318         this.text = text;
38319         this.textEl.update(text);
38320         this.setTooltip(text);
38321         //if(!this.tabPanel.resizeTabs){
38322         //    this.autoSize();
38323         //}
38324     },
38325     /**
38326      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38327      */
38328     activate : function(){
38329         this.tabPanel.activate(this.id);
38330     },
38331
38332     /**
38333      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38334      */
38335     disable : function(){
38336         if(this.tabPanel.active != this){
38337             this.disabled = true;
38338             this.pnode.addClass("disabled");
38339         }
38340     },
38341
38342     /**
38343      * Enables this TabPanelItem if it was previously disabled.
38344      */
38345     enable : function(){
38346         this.disabled = false;
38347         this.pnode.removeClass("disabled");
38348     },
38349
38350     /**
38351      * Sets the content for this TabPanelItem.
38352      * @param {String} content The content
38353      * @param {Boolean} loadScripts true to look for and load scripts
38354      */
38355     setContent : function(content, loadScripts){
38356         this.bodyEl.update(content, loadScripts);
38357     },
38358
38359     /**
38360      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38361      * @return {Roo.UpdateManager} The UpdateManager
38362      */
38363     getUpdateManager : function(){
38364         return this.bodyEl.getUpdateManager();
38365     },
38366
38367     /**
38368      * Set a URL to be used to load the content for this TabPanelItem.
38369      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38370      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
38371      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
38372      * @return {Roo.UpdateManager} The UpdateManager
38373      */
38374     setUrl : function(url, params, loadOnce){
38375         if(this.refreshDelegate){
38376             this.un('activate', this.refreshDelegate);
38377         }
38378         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38379         this.on("activate", this.refreshDelegate);
38380         return this.bodyEl.getUpdateManager();
38381     },
38382
38383     /** @private */
38384     _handleRefresh : function(url, params, loadOnce){
38385         if(!loadOnce || !this.loaded){
38386             var updater = this.bodyEl.getUpdateManager();
38387             updater.update(url, params, this._setLoaded.createDelegate(this));
38388         }
38389     },
38390
38391     /**
38392      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38393      *   Will fail silently if the setUrl method has not been called.
38394      *   This does not activate the panel, just updates its content.
38395      */
38396     refresh : function(){
38397         if(this.refreshDelegate){
38398            this.loaded = false;
38399            this.refreshDelegate();
38400         }
38401     },
38402
38403     /** @private */
38404     _setLoaded : function(){
38405         this.loaded = true;
38406     },
38407
38408     /** @private */
38409     closeClick : function(e){
38410         var o = {};
38411         e.stopEvent();
38412         this.fireEvent("beforeclose", this, o);
38413         if(o.cancel !== true){
38414             this.tabPanel.removeTab(this.id);
38415         }
38416     },
38417     /**
38418      * The text displayed in the tooltip for the close icon.
38419      * @type String
38420      */
38421     closeText : "Close this tab"
38422 });
38423 /**
38424 *    This script refer to:
38425 *    Title: International Telephone Input
38426 *    Author: Jack O'Connor
38427 *    Code version:  v12.1.12
38428 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38429 **/
38430
38431 Roo.bootstrap.PhoneInputData = function() {
38432     var d = [
38433       [
38434         "Afghanistan (‫افغانستان‬‎)",
38435         "af",
38436         "93"
38437       ],
38438       [
38439         "Albania (Shqipëri)",
38440         "al",
38441         "355"
38442       ],
38443       [
38444         "Algeria (‫الجزائر‬‎)",
38445         "dz",
38446         "213"
38447       ],
38448       [
38449         "American Samoa",
38450         "as",
38451         "1684"
38452       ],
38453       [
38454         "Andorra",
38455         "ad",
38456         "376"
38457       ],
38458       [
38459         "Angola",
38460         "ao",
38461         "244"
38462       ],
38463       [
38464         "Anguilla",
38465         "ai",
38466         "1264"
38467       ],
38468       [
38469         "Antigua and Barbuda",
38470         "ag",
38471         "1268"
38472       ],
38473       [
38474         "Argentina",
38475         "ar",
38476         "54"
38477       ],
38478       [
38479         "Armenia (Հայաստան)",
38480         "am",
38481         "374"
38482       ],
38483       [
38484         "Aruba",
38485         "aw",
38486         "297"
38487       ],
38488       [
38489         "Australia",
38490         "au",
38491         "61",
38492         0
38493       ],
38494       [
38495         "Austria (Österreich)",
38496         "at",
38497         "43"
38498       ],
38499       [
38500         "Azerbaijan (Azərbaycan)",
38501         "az",
38502         "994"
38503       ],
38504       [
38505         "Bahamas",
38506         "bs",
38507         "1242"
38508       ],
38509       [
38510         "Bahrain (‫البحرين‬‎)",
38511         "bh",
38512         "973"
38513       ],
38514       [
38515         "Bangladesh (বাংলাদেশ)",
38516         "bd",
38517         "880"
38518       ],
38519       [
38520         "Barbados",
38521         "bb",
38522         "1246"
38523       ],
38524       [
38525         "Belarus (Беларусь)",
38526         "by",
38527         "375"
38528       ],
38529       [
38530         "Belgium (België)",
38531         "be",
38532         "32"
38533       ],
38534       [
38535         "Belize",
38536         "bz",
38537         "501"
38538       ],
38539       [
38540         "Benin (Bénin)",
38541         "bj",
38542         "229"
38543       ],
38544       [
38545         "Bermuda",
38546         "bm",
38547         "1441"
38548       ],
38549       [
38550         "Bhutan (འབྲུག)",
38551         "bt",
38552         "975"
38553       ],
38554       [
38555         "Bolivia",
38556         "bo",
38557         "591"
38558       ],
38559       [
38560         "Bosnia and Herzegovina (Босна и Херцеговина)",
38561         "ba",
38562         "387"
38563       ],
38564       [
38565         "Botswana",
38566         "bw",
38567         "267"
38568       ],
38569       [
38570         "Brazil (Brasil)",
38571         "br",
38572         "55"
38573       ],
38574       [
38575         "British Indian Ocean Territory",
38576         "io",
38577         "246"
38578       ],
38579       [
38580         "British Virgin Islands",
38581         "vg",
38582         "1284"
38583       ],
38584       [
38585         "Brunei",
38586         "bn",
38587         "673"
38588       ],
38589       [
38590         "Bulgaria (България)",
38591         "bg",
38592         "359"
38593       ],
38594       [
38595         "Burkina Faso",
38596         "bf",
38597         "226"
38598       ],
38599       [
38600         "Burundi (Uburundi)",
38601         "bi",
38602         "257"
38603       ],
38604       [
38605         "Cambodia (កម្ពុជា)",
38606         "kh",
38607         "855"
38608       ],
38609       [
38610         "Cameroon (Cameroun)",
38611         "cm",
38612         "237"
38613       ],
38614       [
38615         "Canada",
38616         "ca",
38617         "1",
38618         1,
38619         ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38620       ],
38621       [
38622         "Cape Verde (Kabu Verdi)",
38623         "cv",
38624         "238"
38625       ],
38626       [
38627         "Caribbean Netherlands",
38628         "bq",
38629         "599",
38630         1
38631       ],
38632       [
38633         "Cayman Islands",
38634         "ky",
38635         "1345"
38636       ],
38637       [
38638         "Central African Republic (République centrafricaine)",
38639         "cf",
38640         "236"
38641       ],
38642       [
38643         "Chad (Tchad)",
38644         "td",
38645         "235"
38646       ],
38647       [
38648         "Chile",
38649         "cl",
38650         "56"
38651       ],
38652       [
38653         "China (中国)",
38654         "cn",
38655         "86"
38656       ],
38657       [
38658         "Christmas Island",
38659         "cx",
38660         "61",
38661         2
38662       ],
38663       [
38664         "Cocos (Keeling) Islands",
38665         "cc",
38666         "61",
38667         1
38668       ],
38669       [
38670         "Colombia",
38671         "co",
38672         "57"
38673       ],
38674       [
38675         "Comoros (‫جزر القمر‬‎)",
38676         "km",
38677         "269"
38678       ],
38679       [
38680         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38681         "cd",
38682         "243"
38683       ],
38684       [
38685         "Congo (Republic) (Congo-Brazzaville)",
38686         "cg",
38687         "242"
38688       ],
38689       [
38690         "Cook Islands",
38691         "ck",
38692         "682"
38693       ],
38694       [
38695         "Costa Rica",
38696         "cr",
38697         "506"
38698       ],
38699       [
38700         "Côte d’Ivoire",
38701         "ci",
38702         "225"
38703       ],
38704       [
38705         "Croatia (Hrvatska)",
38706         "hr",
38707         "385"
38708       ],
38709       [
38710         "Cuba",
38711         "cu",
38712         "53"
38713       ],
38714       [
38715         "Curaçao",
38716         "cw",
38717         "599",
38718         0
38719       ],
38720       [
38721         "Cyprus (Κύπρος)",
38722         "cy",
38723         "357"
38724       ],
38725       [
38726         "Czech Republic (Česká republika)",
38727         "cz",
38728         "420"
38729       ],
38730       [
38731         "Denmark (Danmark)",
38732         "dk",
38733         "45"
38734       ],
38735       [
38736         "Djibouti",
38737         "dj",
38738         "253"
38739       ],
38740       [
38741         "Dominica",
38742         "dm",
38743         "1767"
38744       ],
38745       [
38746         "Dominican Republic (República Dominicana)",
38747         "do",
38748         "1",
38749         2,
38750         ["809", "829", "849"]
38751       ],
38752       [
38753         "Ecuador",
38754         "ec",
38755         "593"
38756       ],
38757       [
38758         "Egypt (‫مصر‬‎)",
38759         "eg",
38760         "20"
38761       ],
38762       [
38763         "El Salvador",
38764         "sv",
38765         "503"
38766       ],
38767       [
38768         "Equatorial Guinea (Guinea Ecuatorial)",
38769         "gq",
38770         "240"
38771       ],
38772       [
38773         "Eritrea",
38774         "er",
38775         "291"
38776       ],
38777       [
38778         "Estonia (Eesti)",
38779         "ee",
38780         "372"
38781       ],
38782       [
38783         "Ethiopia",
38784         "et",
38785         "251"
38786       ],
38787       [
38788         "Falkland Islands (Islas Malvinas)",
38789         "fk",
38790         "500"
38791       ],
38792       [
38793         "Faroe Islands (Føroyar)",
38794         "fo",
38795         "298"
38796       ],
38797       [
38798         "Fiji",
38799         "fj",
38800         "679"
38801       ],
38802       [
38803         "Finland (Suomi)",
38804         "fi",
38805         "358",
38806         0
38807       ],
38808       [
38809         "France",
38810         "fr",
38811         "33"
38812       ],
38813       [
38814         "French Guiana (Guyane française)",
38815         "gf",
38816         "594"
38817       ],
38818       [
38819         "French Polynesia (Polynésie française)",
38820         "pf",
38821         "689"
38822       ],
38823       [
38824         "Gabon",
38825         "ga",
38826         "241"
38827       ],
38828       [
38829         "Gambia",
38830         "gm",
38831         "220"
38832       ],
38833       [
38834         "Georgia (საქართველო)",
38835         "ge",
38836         "995"
38837       ],
38838       [
38839         "Germany (Deutschland)",
38840         "de",
38841         "49"
38842       ],
38843       [
38844         "Ghana (Gaana)",
38845         "gh",
38846         "233"
38847       ],
38848       [
38849         "Gibraltar",
38850         "gi",
38851         "350"
38852       ],
38853       [
38854         "Greece (Ελλάδα)",
38855         "gr",
38856         "30"
38857       ],
38858       [
38859         "Greenland (Kalaallit Nunaat)",
38860         "gl",
38861         "299"
38862       ],
38863       [
38864         "Grenada",
38865         "gd",
38866         "1473"
38867       ],
38868       [
38869         "Guadeloupe",
38870         "gp",
38871         "590",
38872         0
38873       ],
38874       [
38875         "Guam",
38876         "gu",
38877         "1671"
38878       ],
38879       [
38880         "Guatemala",
38881         "gt",
38882         "502"
38883       ],
38884       [
38885         "Guernsey",
38886         "gg",
38887         "44",
38888         1
38889       ],
38890       [
38891         "Guinea (Guinée)",
38892         "gn",
38893         "224"
38894       ],
38895       [
38896         "Guinea-Bissau (Guiné Bissau)",
38897         "gw",
38898         "245"
38899       ],
38900       [
38901         "Guyana",
38902         "gy",
38903         "592"
38904       ],
38905       [
38906         "Haiti",
38907         "ht",
38908         "509"
38909       ],
38910       [
38911         "Honduras",
38912         "hn",
38913         "504"
38914       ],
38915       [
38916         "Hong Kong (香港)",
38917         "hk",
38918         "852"
38919       ],
38920       [
38921         "Hungary (Magyarország)",
38922         "hu",
38923         "36"
38924       ],
38925       [
38926         "Iceland (Ísland)",
38927         "is",
38928         "354"
38929       ],
38930       [
38931         "India (भारत)",
38932         "in",
38933         "91"
38934       ],
38935       [
38936         "Indonesia",
38937         "id",
38938         "62"
38939       ],
38940       [
38941         "Iran (‫ایران‬‎)",
38942         "ir",
38943         "98"
38944       ],
38945       [
38946         "Iraq (‫العراق‬‎)",
38947         "iq",
38948         "964"
38949       ],
38950       [
38951         "Ireland",
38952         "ie",
38953         "353"
38954       ],
38955       [
38956         "Isle of Man",
38957         "im",
38958         "44",
38959         2
38960       ],
38961       [
38962         "Israel (‫ישראל‬‎)",
38963         "il",
38964         "972"
38965       ],
38966       [
38967         "Italy (Italia)",
38968         "it",
38969         "39",
38970         0
38971       ],
38972       [
38973         "Jamaica",
38974         "jm",
38975         "1876"
38976       ],
38977       [
38978         "Japan (日本)",
38979         "jp",
38980         "81"
38981       ],
38982       [
38983         "Jersey",
38984         "je",
38985         "44",
38986         3
38987       ],
38988       [
38989         "Jordan (‫الأردن‬‎)",
38990         "jo",
38991         "962"
38992       ],
38993       [
38994         "Kazakhstan (Казахстан)",
38995         "kz",
38996         "7",
38997         1
38998       ],
38999       [
39000         "Kenya",
39001         "ke",
39002         "254"
39003       ],
39004       [
39005         "Kiribati",
39006         "ki",
39007         "686"
39008       ],
39009       [
39010         "Kosovo",
39011         "xk",
39012         "383"
39013       ],
39014       [
39015         "Kuwait (‫الكويت‬‎)",
39016         "kw",
39017         "965"
39018       ],
39019       [
39020         "Kyrgyzstan (Кыргызстан)",
39021         "kg",
39022         "996"
39023       ],
39024       [
39025         "Laos (ລາວ)",
39026         "la",
39027         "856"
39028       ],
39029       [
39030         "Latvia (Latvija)",
39031         "lv",
39032         "371"
39033       ],
39034       [
39035         "Lebanon (‫لبنان‬‎)",
39036         "lb",
39037         "961"
39038       ],
39039       [
39040         "Lesotho",
39041         "ls",
39042         "266"
39043       ],
39044       [
39045         "Liberia",
39046         "lr",
39047         "231"
39048       ],
39049       [
39050         "Libya (‫ليبيا‬‎)",
39051         "ly",
39052         "218"
39053       ],
39054       [
39055         "Liechtenstein",
39056         "li",
39057         "423"
39058       ],
39059       [
39060         "Lithuania (Lietuva)",
39061         "lt",
39062         "370"
39063       ],
39064       [
39065         "Luxembourg",
39066         "lu",
39067         "352"
39068       ],
39069       [
39070         "Macau (澳門)",
39071         "mo",
39072         "853"
39073       ],
39074       [
39075         "Macedonia (FYROM) (Македонија)",
39076         "mk",
39077         "389"
39078       ],
39079       [
39080         "Madagascar (Madagasikara)",
39081         "mg",
39082         "261"
39083       ],
39084       [
39085         "Malawi",
39086         "mw",
39087         "265"
39088       ],
39089       [
39090         "Malaysia",
39091         "my",
39092         "60"
39093       ],
39094       [
39095         "Maldives",
39096         "mv",
39097         "960"
39098       ],
39099       [
39100         "Mali",
39101         "ml",
39102         "223"
39103       ],
39104       [
39105         "Malta",
39106         "mt",
39107         "356"
39108       ],
39109       [
39110         "Marshall Islands",
39111         "mh",
39112         "692"
39113       ],
39114       [
39115         "Martinique",
39116         "mq",
39117         "596"
39118       ],
39119       [
39120         "Mauritania (‫موريتانيا‬‎)",
39121         "mr",
39122         "222"
39123       ],
39124       [
39125         "Mauritius (Moris)",
39126         "mu",
39127         "230"
39128       ],
39129       [
39130         "Mayotte",
39131         "yt",
39132         "262",
39133         1
39134       ],
39135       [
39136         "Mexico (México)",
39137         "mx",
39138         "52"
39139       ],
39140       [
39141         "Micronesia",
39142         "fm",
39143         "691"
39144       ],
39145       [
39146         "Moldova (Republica Moldova)",
39147         "md",
39148         "373"
39149       ],
39150       [
39151         "Monaco",
39152         "mc",
39153         "377"
39154       ],
39155       [
39156         "Mongolia (Монгол)",
39157         "mn",
39158         "976"
39159       ],
39160       [
39161         "Montenegro (Crna Gora)",
39162         "me",
39163         "382"
39164       ],
39165       [
39166         "Montserrat",
39167         "ms",
39168         "1664"
39169       ],
39170       [
39171         "Morocco (‫المغرب‬‎)",
39172         "ma",
39173         "212",
39174         0
39175       ],
39176       [
39177         "Mozambique (Moçambique)",
39178         "mz",
39179         "258"
39180       ],
39181       [
39182         "Myanmar (Burma) (မြန်မာ)",
39183         "mm",
39184         "95"
39185       ],
39186       [
39187         "Namibia (Namibië)",
39188         "na",
39189         "264"
39190       ],
39191       [
39192         "Nauru",
39193         "nr",
39194         "674"
39195       ],
39196       [
39197         "Nepal (नेपाल)",
39198         "np",
39199         "977"
39200       ],
39201       [
39202         "Netherlands (Nederland)",
39203         "nl",
39204         "31"
39205       ],
39206       [
39207         "New Caledonia (Nouvelle-Calédonie)",
39208         "nc",
39209         "687"
39210       ],
39211       [
39212         "New Zealand",
39213         "nz",
39214         "64"
39215       ],
39216       [
39217         "Nicaragua",
39218         "ni",
39219         "505"
39220       ],
39221       [
39222         "Niger (Nijar)",
39223         "ne",
39224         "227"
39225       ],
39226       [
39227         "Nigeria",
39228         "ng",
39229         "234"
39230       ],
39231       [
39232         "Niue",
39233         "nu",
39234         "683"
39235       ],
39236       [
39237         "Norfolk Island",
39238         "nf",
39239         "672"
39240       ],
39241       [
39242         "North Korea (조선 민주주의 인민 공화국)",
39243         "kp",
39244         "850"
39245       ],
39246       [
39247         "Northern Mariana Islands",
39248         "mp",
39249         "1670"
39250       ],
39251       [
39252         "Norway (Norge)",
39253         "no",
39254         "47",
39255         0
39256       ],
39257       [
39258         "Oman (‫عُمان‬‎)",
39259         "om",
39260         "968"
39261       ],
39262       [
39263         "Pakistan (‫پاکستان‬‎)",
39264         "pk",
39265         "92"
39266       ],
39267       [
39268         "Palau",
39269         "pw",
39270         "680"
39271       ],
39272       [
39273         "Palestine (‫فلسطين‬‎)",
39274         "ps",
39275         "970"
39276       ],
39277       [
39278         "Panama (Panamá)",
39279         "pa",
39280         "507"
39281       ],
39282       [
39283         "Papua New Guinea",
39284         "pg",
39285         "675"
39286       ],
39287       [
39288         "Paraguay",
39289         "py",
39290         "595"
39291       ],
39292       [
39293         "Peru (Perú)",
39294         "pe",
39295         "51"
39296       ],
39297       [
39298         "Philippines",
39299         "ph",
39300         "63"
39301       ],
39302       [
39303         "Poland (Polska)",
39304         "pl",
39305         "48"
39306       ],
39307       [
39308         "Portugal",
39309         "pt",
39310         "351"
39311       ],
39312       [
39313         "Puerto Rico",
39314         "pr",
39315         "1",
39316         3,
39317         ["787", "939"]
39318       ],
39319       [
39320         "Qatar (‫قطر‬‎)",
39321         "qa",
39322         "974"
39323       ],
39324       [
39325         "Réunion (La Réunion)",
39326         "re",
39327         "262",
39328         0
39329       ],
39330       [
39331         "Romania (România)",
39332         "ro",
39333         "40"
39334       ],
39335       [
39336         "Russia (Россия)",
39337         "ru",
39338         "7",
39339         0
39340       ],
39341       [
39342         "Rwanda",
39343         "rw",
39344         "250"
39345       ],
39346       [
39347         "Saint Barthélemy",
39348         "bl",
39349         "590",
39350         1
39351       ],
39352       [
39353         "Saint Helena",
39354         "sh",
39355         "290"
39356       ],
39357       [
39358         "Saint Kitts and Nevis",
39359         "kn",
39360         "1869"
39361       ],
39362       [
39363         "Saint Lucia",
39364         "lc",
39365         "1758"
39366       ],
39367       [
39368         "Saint Martin (Saint-Martin (partie française))",
39369         "mf",
39370         "590",
39371         2
39372       ],
39373       [
39374         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39375         "pm",
39376         "508"
39377       ],
39378       [
39379         "Saint Vincent and the Grenadines",
39380         "vc",
39381         "1784"
39382       ],
39383       [
39384         "Samoa",
39385         "ws",
39386         "685"
39387       ],
39388       [
39389         "San Marino",
39390         "sm",
39391         "378"
39392       ],
39393       [
39394         "São Tomé and Príncipe (São Tomé e Príncipe)",
39395         "st",
39396         "239"
39397       ],
39398       [
39399         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39400         "sa",
39401         "966"
39402       ],
39403       [
39404         "Senegal (Sénégal)",
39405         "sn",
39406         "221"
39407       ],
39408       [
39409         "Serbia (Србија)",
39410         "rs",
39411         "381"
39412       ],
39413       [
39414         "Seychelles",
39415         "sc",
39416         "248"
39417       ],
39418       [
39419         "Sierra Leone",
39420         "sl",
39421         "232"
39422       ],
39423       [
39424         "Singapore",
39425         "sg",
39426         "65"
39427       ],
39428       [
39429         "Sint Maarten",
39430         "sx",
39431         "1721"
39432       ],
39433       [
39434         "Slovakia (Slovensko)",
39435         "sk",
39436         "421"
39437       ],
39438       [
39439         "Slovenia (Slovenija)",
39440         "si",
39441         "386"
39442       ],
39443       [
39444         "Solomon Islands",
39445         "sb",
39446         "677"
39447       ],
39448       [
39449         "Somalia (Soomaaliya)",
39450         "so",
39451         "252"
39452       ],
39453       [
39454         "South Africa",
39455         "za",
39456         "27"
39457       ],
39458       [
39459         "South Korea (대한민국)",
39460         "kr",
39461         "82"
39462       ],
39463       [
39464         "South Sudan (‫جنوب السودان‬‎)",
39465         "ss",
39466         "211"
39467       ],
39468       [
39469         "Spain (España)",
39470         "es",
39471         "34"
39472       ],
39473       [
39474         "Sri Lanka (ශ්‍රී ලංකාව)",
39475         "lk",
39476         "94"
39477       ],
39478       [
39479         "Sudan (‫السودان‬‎)",
39480         "sd",
39481         "249"
39482       ],
39483       [
39484         "Suriname",
39485         "sr",
39486         "597"
39487       ],
39488       [
39489         "Svalbard and Jan Mayen",
39490         "sj",
39491         "47",
39492         1
39493       ],
39494       [
39495         "Swaziland",
39496         "sz",
39497         "268"
39498       ],
39499       [
39500         "Sweden (Sverige)",
39501         "se",
39502         "46"
39503       ],
39504       [
39505         "Switzerland (Schweiz)",
39506         "ch",
39507         "41"
39508       ],
39509       [
39510         "Syria (‫سوريا‬‎)",
39511         "sy",
39512         "963"
39513       ],
39514       [
39515         "Taiwan (台灣)",
39516         "tw",
39517         "886"
39518       ],
39519       [
39520         "Tajikistan",
39521         "tj",
39522         "992"
39523       ],
39524       [
39525         "Tanzania",
39526         "tz",
39527         "255"
39528       ],
39529       [
39530         "Thailand (ไทย)",
39531         "th",
39532         "66"
39533       ],
39534       [
39535         "Timor-Leste",
39536         "tl",
39537         "670"
39538       ],
39539       [
39540         "Togo",
39541         "tg",
39542         "228"
39543       ],
39544       [
39545         "Tokelau",
39546         "tk",
39547         "690"
39548       ],
39549       [
39550         "Tonga",
39551         "to",
39552         "676"
39553       ],
39554       [
39555         "Trinidad and Tobago",
39556         "tt",
39557         "1868"
39558       ],
39559       [
39560         "Tunisia (‫تونس‬‎)",
39561         "tn",
39562         "216"
39563       ],
39564       [
39565         "Turkey (Türkiye)",
39566         "tr",
39567         "90"
39568       ],
39569       [
39570         "Turkmenistan",
39571         "tm",
39572         "993"
39573       ],
39574       [
39575         "Turks and Caicos Islands",
39576         "tc",
39577         "1649"
39578       ],
39579       [
39580         "Tuvalu",
39581         "tv",
39582         "688"
39583       ],
39584       [
39585         "U.S. Virgin Islands",
39586         "vi",
39587         "1340"
39588       ],
39589       [
39590         "Uganda",
39591         "ug",
39592         "256"
39593       ],
39594       [
39595         "Ukraine (Україна)",
39596         "ua",
39597         "380"
39598       ],
39599       [
39600         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39601         "ae",
39602         "971"
39603       ],
39604       [
39605         "United Kingdom",
39606         "gb",
39607         "44",
39608         0
39609       ],
39610       [
39611         "United States",
39612         "us",
39613         "1",
39614         0
39615       ],
39616       [
39617         "Uruguay",
39618         "uy",
39619         "598"
39620       ],
39621       [
39622         "Uzbekistan (Oʻzbekiston)",
39623         "uz",
39624         "998"
39625       ],
39626       [
39627         "Vanuatu",
39628         "vu",
39629         "678"
39630       ],
39631       [
39632         "Vatican City (Città del Vaticano)",
39633         "va",
39634         "39",
39635         1
39636       ],
39637       [
39638         "Venezuela",
39639         "ve",
39640         "58"
39641       ],
39642       [
39643         "Vietnam (Việt Nam)",
39644         "vn",
39645         "84"
39646       ],
39647       [
39648         "Wallis and Futuna (Wallis-et-Futuna)",
39649         "wf",
39650         "681"
39651       ],
39652       [
39653         "Western Sahara (‫الصحراء الغربية‬‎)",
39654         "eh",
39655         "212",
39656         1
39657       ],
39658       [
39659         "Yemen (‫اليمن‬‎)",
39660         "ye",
39661         "967"
39662       ],
39663       [
39664         "Zambia",
39665         "zm",
39666         "260"
39667       ],
39668       [
39669         "Zimbabwe",
39670         "zw",
39671         "263"
39672       ],
39673       [
39674         "Åland Islands",
39675         "ax",
39676         "358",
39677         1
39678       ]
39679   ];
39680   
39681   return d;
39682 }/**
39683 *    This script refer to:
39684 *    Title: International Telephone Input
39685 *    Author: Jack O'Connor
39686 *    Code version:  v12.1.12
39687 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39688 **/
39689
39690 /**
39691  * @class Roo.bootstrap.PhoneInput
39692  * @extends Roo.bootstrap.TriggerField
39693  * An input with International dial-code selection
39694  
39695  * @cfg {String} defaultDialCode default '+852'
39696  * @cfg {Array} preferedCountries default []
39697   
39698  * @constructor
39699  * Create a new PhoneInput.
39700  * @param {Object} config Configuration options
39701  */
39702
39703 Roo.bootstrap.PhoneInput = function(config) {
39704     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39705 };
39706
39707 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39708         
39709         listWidth: undefined,
39710         
39711         selectedClass: 'active',
39712         
39713         invalidClass : "has-warning",
39714         
39715         validClass: 'has-success',
39716         
39717         allowed: '0123456789',
39718         
39719         /**
39720          * @cfg {String} defaultDialCode The default dial code when initializing the input
39721          */
39722         defaultDialCode: '+852',
39723         
39724         /**
39725          * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39726          */
39727         preferedCountries: false,
39728         
39729         getAutoCreate : function()
39730         {
39731             var data = Roo.bootstrap.PhoneInputData();
39732             var align = this.labelAlign || this.parentLabelAlign();
39733             var id = Roo.id();
39734             
39735             this.allCountries = [];
39736             this.dialCodeMapping = [];
39737             
39738             for (var i = 0; i < data.length; i++) {
39739               var c = data[i];
39740               this.allCountries[i] = {
39741                 name: c[0],
39742                 iso2: c[1],
39743                 dialCode: c[2],
39744                 priority: c[3] || 0,
39745                 areaCodes: c[4] || null
39746               };
39747               this.dialCodeMapping[c[2]] = {
39748                   name: c[0],
39749                   iso2: c[1],
39750                   priority: c[3] || 0,
39751                   areaCodes: c[4] || null
39752               };
39753             }
39754             
39755             var cfg = {
39756                 cls: 'form-group',
39757                 cn: []
39758             };
39759             
39760             var input =  {
39761                 tag: 'input',
39762                 id : id,
39763                 cls : 'form-control tel-input',
39764                 autocomplete: 'new-password'
39765             };
39766             
39767             var hiddenInput = {
39768                 tag: 'input',
39769                 type: 'hidden',
39770                 cls: 'hidden-tel-input'
39771             };
39772             
39773             if (this.name) {
39774                 hiddenInput.name = this.name;
39775             }
39776             
39777             if (this.disabled) {
39778                 input.disabled = true;
39779             }
39780             
39781             var flag_container = {
39782                 tag: 'div',
39783                 cls: 'flag-box',
39784                 cn: [
39785                     {
39786                         tag: 'div',
39787                         cls: 'flag'
39788                     },
39789                     {
39790                         tag: 'div',
39791                         cls: 'caret'
39792                     }
39793                 ]
39794             };
39795             
39796             var box = {
39797                 tag: 'div',
39798                 cls: this.hasFeedback ? 'has-feedback' : '',
39799                 cn: [
39800                     hiddenInput,
39801                     input,
39802                     {
39803                         tag: 'input',
39804                         cls: 'dial-code-holder',
39805                         disabled: true
39806                     }
39807                 ]
39808             };
39809             
39810             var container = {
39811                 cls: 'roo-select2-container input-group',
39812                 cn: [
39813                     flag_container,
39814                     box
39815                 ]
39816             };
39817             
39818             if (this.fieldLabel.length) {
39819                 var indicator = {
39820                     tag: 'i',
39821                     tooltip: 'This field is required'
39822                 };
39823                 
39824                 var label = {
39825                     tag: 'label',
39826                     'for':  id,
39827                     cls: 'control-label',
39828                     cn: []
39829                 };
39830                 
39831                 var label_text = {
39832                     tag: 'span',
39833                     html: this.fieldLabel
39834                 };
39835                 
39836                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39837                 label.cn = [
39838                     indicator,
39839                     label_text
39840                 ];
39841                 
39842                 if(this.indicatorpos == 'right') {
39843                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39844                     label.cn = [
39845                         label_text,
39846                         indicator
39847                     ];
39848                 }
39849                 
39850                 if(align == 'left') {
39851                     container = {
39852                         tag: 'div',
39853                         cn: [
39854                             container
39855                         ]
39856                     };
39857                     
39858                     if(this.labelWidth > 12){
39859                         label.style = "width: " + this.labelWidth + 'px';
39860                     }
39861                     if(this.labelWidth < 13 && this.labelmd == 0){
39862                         this.labelmd = this.labelWidth;
39863                     }
39864                     if(this.labellg > 0){
39865                         label.cls += ' col-lg-' + this.labellg;
39866                         input.cls += ' col-lg-' + (12 - this.labellg);
39867                     }
39868                     if(this.labelmd > 0){
39869                         label.cls += ' col-md-' + this.labelmd;
39870                         container.cls += ' col-md-' + (12 - this.labelmd);
39871                     }
39872                     if(this.labelsm > 0){
39873                         label.cls += ' col-sm-' + this.labelsm;
39874                         container.cls += ' col-sm-' + (12 - this.labelsm);
39875                     }
39876                     if(this.labelxs > 0){
39877                         label.cls += ' col-xs-' + this.labelxs;
39878                         container.cls += ' col-xs-' + (12 - this.labelxs);
39879                     }
39880                 }
39881             }
39882             
39883             cfg.cn = [
39884                 label,
39885                 container
39886             ];
39887             
39888             var settings = this;
39889             
39890             ['xs','sm','md','lg'].map(function(size){
39891                 if (settings[size]) {
39892                     cfg.cls += ' col-' + size + '-' + settings[size];
39893                 }
39894             });
39895             
39896             this.store = new Roo.data.Store({
39897                 proxy : new Roo.data.MemoryProxy({}),
39898                 reader : new Roo.data.JsonReader({
39899                     fields : [
39900                         {
39901                             'name' : 'name',
39902                             'type' : 'string'
39903                         },
39904                         {
39905                             'name' : 'iso2',
39906                             'type' : 'string'
39907                         },
39908                         {
39909                             'name' : 'dialCode',
39910                             'type' : 'string'
39911                         },
39912                         {
39913                             'name' : 'priority',
39914                             'type' : 'string'
39915                         },
39916                         {
39917                             'name' : 'areaCodes',
39918                             'type' : 'string'
39919                         }
39920                     ]
39921                 })
39922             });
39923             
39924             if(!this.preferedCountries) {
39925                 this.preferedCountries = [
39926                     'hk',
39927                     'gb',
39928                     'us'
39929                 ];
39930             }
39931             
39932             var p = this.preferedCountries.reverse();
39933             
39934             if(p) {
39935                 for (var i = 0; i < p.length; i++) {
39936                     for (var j = 0; j < this.allCountries.length; j++) {
39937                         if(this.allCountries[j].iso2 == p[i]) {
39938                             var t = this.allCountries[j];
39939                             this.allCountries.splice(j,1);
39940                             this.allCountries.unshift(t);
39941                         }
39942                     } 
39943                 }
39944             }
39945             
39946             this.store.proxy.data = {
39947                 success: true,
39948                 data: this.allCountries
39949             };
39950             
39951             return cfg;
39952         },
39953         
39954         initEvents : function()
39955         {
39956             this.createList();
39957             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39958             
39959             this.indicator = this.indicatorEl();
39960             this.flag = this.flagEl();
39961             this.dialCodeHolder = this.dialCodeHolderEl();
39962             
39963             this.trigger = this.el.select('div.flag-box',true).first();
39964             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39965             
39966             var _this = this;
39967             
39968             (function(){
39969                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39970                 _this.list.setWidth(lw);
39971             }).defer(100);
39972             
39973             this.list.on('mouseover', this.onViewOver, this);
39974             this.list.on('mousemove', this.onViewMove, this);
39975             this.inputEl().on("keyup", this.onKeyUp, this);
39976             
39977             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39978
39979             this.view = new Roo.View(this.list, this.tpl, {
39980                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39981             });
39982             
39983             this.view.on('click', this.onViewClick, this);
39984             this.setValue(this.defaultDialCode);
39985         },
39986         
39987         onTriggerClick : function(e)
39988         {
39989             Roo.log('trigger click');
39990             if(this.disabled){
39991                 return;
39992             }
39993             
39994             if(this.isExpanded()){
39995                 this.collapse();
39996                 this.hasFocus = false;
39997             }else {
39998                 this.store.load({});
39999                 this.hasFocus = true;
40000                 this.expand();
40001             }
40002         },
40003         
40004         isExpanded : function()
40005         {
40006             return this.list.isVisible();
40007         },
40008         
40009         collapse : function()
40010         {
40011             if(!this.isExpanded()){
40012                 return;
40013             }
40014             this.list.hide();
40015             Roo.get(document).un('mousedown', this.collapseIf, this);
40016             Roo.get(document).un('mousewheel', this.collapseIf, this);
40017             this.fireEvent('collapse', this);
40018             this.validate();
40019         },
40020         
40021         expand : function()
40022         {
40023             Roo.log('expand');
40024
40025             if(this.isExpanded() || !this.hasFocus){
40026                 return;
40027             }
40028             
40029             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40030             this.list.setWidth(lw);
40031             
40032             this.list.show();
40033             this.restrictHeight();
40034             
40035             Roo.get(document).on('mousedown', this.collapseIf, this);
40036             Roo.get(document).on('mousewheel', this.collapseIf, this);
40037             
40038             this.fireEvent('expand', this);
40039         },
40040         
40041         restrictHeight : function()
40042         {
40043             this.list.alignTo(this.inputEl(), this.listAlign);
40044             this.list.alignTo(this.inputEl(), this.listAlign);
40045         },
40046         
40047         onViewOver : function(e, t)
40048         {
40049             if(this.inKeyMode){
40050                 return;
40051             }
40052             var item = this.view.findItemFromChild(t);
40053             
40054             if(item){
40055                 var index = this.view.indexOf(item);
40056                 this.select(index, false);
40057             }
40058         },
40059
40060         // private
40061         onViewClick : function(view, doFocus, el, e)
40062         {
40063             var index = this.view.getSelectedIndexes()[0];
40064             
40065             var r = this.store.getAt(index);
40066             
40067             if(r){
40068                 this.onSelect(r, index);
40069             }
40070             if(doFocus !== false && !this.blockFocus){
40071                 this.inputEl().focus();
40072             }
40073         },
40074         
40075         onViewMove : function(e, t)
40076         {
40077             this.inKeyMode = false;
40078         },
40079         
40080         select : function(index, scrollIntoView)
40081         {
40082             this.selectedIndex = index;
40083             this.view.select(index);
40084             if(scrollIntoView !== false){
40085                 var el = this.view.getNode(index);
40086                 if(el){
40087                     this.list.scrollChildIntoView(el, false);
40088                 }
40089             }
40090         },
40091         
40092         createList : function()
40093         {
40094             this.list = Roo.get(document.body).createChild({
40095                 tag: 'ul',
40096                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40097                 style: 'display:none'
40098             });
40099             
40100             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40101         },
40102         
40103         collapseIf : function(e)
40104         {
40105             var in_combo  = e.within(this.el);
40106             var in_list =  e.within(this.list);
40107             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40108             
40109             if (in_combo || in_list || is_list) {
40110                 return;
40111             }
40112             this.collapse();
40113         },
40114         
40115         onSelect : function(record, index)
40116         {
40117             if(this.fireEvent('beforeselect', this, record, index) !== false){
40118                 
40119                 this.setFlagClass(record.data.iso2);
40120                 this.setDialCode(record.data.dialCode);
40121                 this.hasFocus = false;
40122                 this.collapse();
40123                 this.fireEvent('select', this, record, index);
40124             }
40125         },
40126         
40127         flagEl : function()
40128         {
40129             var flag = this.el.select('div.flag',true).first();
40130             if(!flag){
40131                 return false;
40132             }
40133             return flag;
40134         },
40135         
40136         dialCodeHolderEl : function()
40137         {
40138             var d = this.el.select('input.dial-code-holder',true).first();
40139             if(!d){
40140                 return false;
40141             }
40142             return d;
40143         },
40144         
40145         setDialCode : function(v)
40146         {
40147             this.dialCodeHolder.dom.value = '+'+v;
40148         },
40149         
40150         setFlagClass : function(n)
40151         {
40152             this.flag.dom.className = 'flag '+n;
40153         },
40154         
40155         getValue : function()
40156         {
40157             var v = this.inputEl().getValue();
40158             if(this.dialCodeHolder) {
40159                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40160             }
40161             return v;
40162         },
40163         
40164         setValue : function(v)
40165         {
40166             var d = this.getDialCode(v);
40167             
40168             //invalid dial code
40169             if(v.length == 0 || !d || d.length == 0) {
40170                 if(this.rendered){
40171                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40172                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40173                 }
40174                 return;
40175             }
40176             
40177             //valid dial code
40178             this.setFlagClass(this.dialCodeMapping[d].iso2);
40179             this.setDialCode(d);
40180             this.inputEl().dom.value = v.replace('+'+d,'');
40181             this.hiddenEl().dom.value = this.getValue();
40182             
40183             this.validate();
40184         },
40185         
40186         getDialCode : function(v)
40187         {
40188             v = v ||  '';
40189             
40190             if (v.length == 0) {
40191                 return this.dialCodeHolder.dom.value;
40192             }
40193             
40194             var dialCode = "";
40195             if (v.charAt(0) != "+") {
40196                 return false;
40197             }
40198             var numericChars = "";
40199             for (var i = 1; i < v.length; i++) {
40200               var c = v.charAt(i);
40201               if (!isNaN(c)) {
40202                 numericChars += c;
40203                 if (this.dialCodeMapping[numericChars]) {
40204                   dialCode = v.substr(1, i);
40205                 }
40206                 if (numericChars.length == 4) {
40207                   break;
40208                 }
40209               }
40210             }
40211             return dialCode;
40212         },
40213         
40214         reset : function()
40215         {
40216             this.setValue(this.defaultDialCode);
40217             this.validate();
40218         },
40219         
40220         hiddenEl : function()
40221         {
40222             return this.el.select('input.hidden-tel-input',true).first();
40223         },
40224         
40225         onKeyUp : function(e){
40226             
40227             var k = e.getKey();
40228             var c = e.getCharCode();
40229             
40230             if(
40231                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40232                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40233             ){
40234                 e.stopEvent();
40235             }
40236             
40237             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40238             //     return;
40239             // }
40240             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40241                 e.stopEvent();
40242             }
40243             
40244             this.setValue(this.getValue());
40245         }
40246         
40247 });
40248 /**
40249  * @class Roo.bootstrap.MoneyField
40250  * @extends Roo.bootstrap.ComboBox
40251  * Bootstrap MoneyField class
40252  * 
40253  * @constructor
40254  * Create a new MoneyField.
40255  * @param {Object} config Configuration options
40256  */
40257
40258 Roo.bootstrap.MoneyField = function(config) {
40259     
40260     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40261     
40262 };
40263
40264 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40265     
40266     /**
40267      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40268      */
40269     allowDecimals : true,
40270     /**
40271      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40272      */
40273     decimalSeparator : ".",
40274     /**
40275      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40276      */
40277     decimalPrecision : 0,
40278     /**
40279      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40280      */
40281     allowNegative : true,
40282     /**
40283      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40284      */
40285     allowZero: true,
40286     /**
40287      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40288      */
40289     minValue : Number.NEGATIVE_INFINITY,
40290     /**
40291      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40292      */
40293     maxValue : Number.MAX_VALUE,
40294     /**
40295      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40296      */
40297     minText : "The minimum value for this field is {0}",
40298     /**
40299      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40300      */
40301     maxText : "The maximum value for this field is {0}",
40302     /**
40303      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40304      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40305      */
40306     nanText : "{0} is not a valid number",
40307     /**
40308      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40309      */
40310     castInt : true,
40311     /**
40312      * @cfg {String} defaults currency of the MoneyField
40313      * value should be in lkey
40314      */
40315     defaultCurrency : false,
40316     /**
40317      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40318      */
40319     thousandsDelimiter : false,
40320     
40321     
40322     inputlg : 9,
40323     inputmd : 9,
40324     inputsm : 9,
40325     inputxs : 6,
40326     
40327     store : false,
40328     
40329     getAutoCreate : function()
40330     {
40331         var align = this.labelAlign || this.parentLabelAlign();
40332         
40333         var id = Roo.id();
40334
40335         var cfg = {
40336             cls: 'form-group',
40337             cn: []
40338         };
40339
40340         var input =  {
40341             tag: 'input',
40342             id : id,
40343             cls : 'form-control roo-money-amount-input',
40344             autocomplete: 'new-password'
40345         };
40346         
40347         var hiddenInput = {
40348             tag: 'input',
40349             type: 'hidden',
40350             id: Roo.id(),
40351             cls: 'hidden-number-input'
40352         };
40353         
40354         if (this.name) {
40355             hiddenInput.name = this.name;
40356         }
40357
40358         if (this.disabled) {
40359             input.disabled = true;
40360         }
40361
40362         var clg = 12 - this.inputlg;
40363         var cmd = 12 - this.inputmd;
40364         var csm = 12 - this.inputsm;
40365         var cxs = 12 - this.inputxs;
40366         
40367         var container = {
40368             tag : 'div',
40369             cls : 'row roo-money-field',
40370             cn : [
40371                 {
40372                     tag : 'div',
40373                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40374                     cn : [
40375                         {
40376                             tag : 'div',
40377                             cls: 'roo-select2-container input-group',
40378                             cn: [
40379                                 {
40380                                     tag : 'input',
40381                                     cls : 'form-control roo-money-currency-input',
40382                                     autocomplete: 'new-password',
40383                                     readOnly : 1,
40384                                     name : this.currencyName
40385                                 },
40386                                 {
40387                                     tag :'span',
40388                                     cls : 'input-group-addon',
40389                                     cn : [
40390                                         {
40391                                             tag: 'span',
40392                                             cls: 'caret'
40393                                         }
40394                                     ]
40395                                 }
40396                             ]
40397                         }
40398                     ]
40399                 },
40400                 {
40401                     tag : 'div',
40402                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40403                     cn : [
40404                         {
40405                             tag: 'div',
40406                             cls: this.hasFeedback ? 'has-feedback' : '',
40407                             cn: [
40408                                 input
40409                             ]
40410                         }
40411                     ]
40412                 }
40413             ]
40414             
40415         };
40416         
40417         if (this.fieldLabel.length) {
40418             var indicator = {
40419                 tag: 'i',
40420                 tooltip: 'This field is required'
40421             };
40422
40423             var label = {
40424                 tag: 'label',
40425                 'for':  id,
40426                 cls: 'control-label',
40427                 cn: []
40428             };
40429
40430             var label_text = {
40431                 tag: 'span',
40432                 html: this.fieldLabel
40433             };
40434
40435             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40436             label.cn = [
40437                 indicator,
40438                 label_text
40439             ];
40440
40441             if(this.indicatorpos == 'right') {
40442                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40443                 label.cn = [
40444                     label_text,
40445                     indicator
40446                 ];
40447             }
40448
40449             if(align == 'left') {
40450                 container = {
40451                     tag: 'div',
40452                     cn: [
40453                         container
40454                     ]
40455                 };
40456
40457                 if(this.labelWidth > 12){
40458                     label.style = "width: " + this.labelWidth + 'px';
40459                 }
40460                 if(this.labelWidth < 13 && this.labelmd == 0){
40461                     this.labelmd = this.labelWidth;
40462                 }
40463                 if(this.labellg > 0){
40464                     label.cls += ' col-lg-' + this.labellg;
40465                     input.cls += ' col-lg-' + (12 - this.labellg);
40466                 }
40467                 if(this.labelmd > 0){
40468                     label.cls += ' col-md-' + this.labelmd;
40469                     container.cls += ' col-md-' + (12 - this.labelmd);
40470                 }
40471                 if(this.labelsm > 0){
40472                     label.cls += ' col-sm-' + this.labelsm;
40473                     container.cls += ' col-sm-' + (12 - this.labelsm);
40474                 }
40475                 if(this.labelxs > 0){
40476                     label.cls += ' col-xs-' + this.labelxs;
40477                     container.cls += ' col-xs-' + (12 - this.labelxs);
40478                 }
40479             }
40480         }
40481
40482         cfg.cn = [
40483             label,
40484             container,
40485             hiddenInput
40486         ];
40487         
40488         var settings = this;
40489
40490         ['xs','sm','md','lg'].map(function(size){
40491             if (settings[size]) {
40492                 cfg.cls += ' col-' + size + '-' + settings[size];
40493             }
40494         });
40495         
40496         return cfg;
40497     },
40498     
40499     initEvents : function()
40500     {
40501         this.indicator = this.indicatorEl();
40502         
40503         this.initCurrencyEvent();
40504         
40505         this.initNumberEvent();
40506     },
40507     
40508     initCurrencyEvent : function()
40509     {
40510         if (!this.store) {
40511             throw "can not find store for combo";
40512         }
40513         
40514         this.store = Roo.factory(this.store, Roo.data);
40515         this.store.parent = this;
40516         
40517         this.createList();
40518         
40519         this.triggerEl = this.el.select('.input-group-addon', true).first();
40520         
40521         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40522         
40523         var _this = this;
40524         
40525         (function(){
40526             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40527             _this.list.setWidth(lw);
40528         }).defer(100);
40529         
40530         this.list.on('mouseover', this.onViewOver, this);
40531         this.list.on('mousemove', this.onViewMove, this);
40532         this.list.on('scroll', this.onViewScroll, this);
40533         
40534         if(!this.tpl){
40535             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40536         }
40537         
40538         this.view = new Roo.View(this.list, this.tpl, {
40539             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40540         });
40541         
40542         this.view.on('click', this.onViewClick, this);
40543         
40544         this.store.on('beforeload', this.onBeforeLoad, this);
40545         this.store.on('load', this.onLoad, this);
40546         this.store.on('loadexception', this.onLoadException, this);
40547         
40548         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40549             "up" : function(e){
40550                 this.inKeyMode = true;
40551                 this.selectPrev();
40552             },
40553
40554             "down" : function(e){
40555                 if(!this.isExpanded()){
40556                     this.onTriggerClick();
40557                 }else{
40558                     this.inKeyMode = true;
40559                     this.selectNext();
40560                 }
40561             },
40562
40563             "enter" : function(e){
40564                 this.collapse();
40565                 
40566                 if(this.fireEvent("specialkey", this, e)){
40567                     this.onViewClick(false);
40568                 }
40569                 
40570                 return true;
40571             },
40572
40573             "esc" : function(e){
40574                 this.collapse();
40575             },
40576
40577             "tab" : function(e){
40578                 this.collapse();
40579                 
40580                 if(this.fireEvent("specialkey", this, e)){
40581                     this.onViewClick(false);
40582                 }
40583                 
40584                 return true;
40585             },
40586
40587             scope : this,
40588
40589             doRelay : function(foo, bar, hname){
40590                 if(hname == 'down' || this.scope.isExpanded()){
40591                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40592                 }
40593                 return true;
40594             },
40595
40596             forceKeyDown: true
40597         });
40598         
40599         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40600         
40601     },
40602     
40603     initNumberEvent : function(e)
40604     {
40605         this.inputEl().on("keydown" , this.fireKey,  this);
40606         this.inputEl().on("focus", this.onFocus,  this);
40607         this.inputEl().on("blur", this.onBlur,  this);
40608         
40609         this.inputEl().relayEvent('keyup', this);
40610         
40611         if(this.indicator){
40612             this.indicator.addClass('invisible');
40613         }
40614  
40615         this.originalValue = this.getValue();
40616         
40617         if(this.validationEvent == 'keyup'){
40618             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40619             this.inputEl().on('keyup', this.filterValidation, this);
40620         }
40621         else if(this.validationEvent !== false){
40622             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40623         }
40624         
40625         if(this.selectOnFocus){
40626             this.on("focus", this.preFocus, this);
40627             
40628         }
40629         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40630             this.inputEl().on("keypress", this.filterKeys, this);
40631         } else {
40632             this.inputEl().relayEvent('keypress', this);
40633         }
40634         
40635         var allowed = "0123456789";
40636         
40637         if(this.allowDecimals){
40638             allowed += this.decimalSeparator;
40639         }
40640         
40641         if(this.allowNegative){
40642             allowed += "-";
40643         }
40644         
40645         if(this.thousandsDelimiter) {
40646             allowed += ",";
40647         }
40648         
40649         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40650         
40651         var keyPress = function(e){
40652             
40653             var k = e.getKey();
40654             
40655             var c = e.getCharCode();
40656             
40657             if(
40658                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40659                     allowed.indexOf(String.fromCharCode(c)) === -1
40660             ){
40661                 e.stopEvent();
40662                 return;
40663             }
40664             
40665             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40666                 return;
40667             }
40668             
40669             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40670                 e.stopEvent();
40671             }
40672         };
40673         
40674         this.inputEl().on("keypress", keyPress, this);
40675         
40676     },
40677     
40678     onTriggerClick : function(e)
40679     {   
40680         if(this.disabled){
40681             return;
40682         }
40683         
40684         this.page = 0;
40685         this.loadNext = false;
40686         
40687         if(this.isExpanded()){
40688             this.collapse();
40689             return;
40690         }
40691         
40692         this.hasFocus = true;
40693         
40694         if(this.triggerAction == 'all') {
40695             this.doQuery(this.allQuery, true);
40696             return;
40697         }
40698         
40699         this.doQuery(this.getRawValue());
40700     },
40701     
40702     getCurrency : function()
40703     {   
40704         var v = this.currencyEl().getValue();
40705         
40706         return v;
40707     },
40708     
40709     restrictHeight : function()
40710     {
40711         this.list.alignTo(this.currencyEl(), this.listAlign);
40712         this.list.alignTo(this.currencyEl(), this.listAlign);
40713     },
40714     
40715     onViewClick : function(view, doFocus, el, e)
40716     {
40717         var index = this.view.getSelectedIndexes()[0];
40718         
40719         var r = this.store.getAt(index);
40720         
40721         if(r){
40722             this.onSelect(r, index);
40723         }
40724     },
40725     
40726     onSelect : function(record, index){
40727         
40728         if(this.fireEvent('beforeselect', this, record, index) !== false){
40729         
40730             this.setFromCurrencyData(index > -1 ? record.data : false);
40731             
40732             this.collapse();
40733             
40734             this.fireEvent('select', this, record, index);
40735         }
40736     },
40737     
40738     setFromCurrencyData : function(o)
40739     {
40740         var currency = '';
40741         
40742         this.lastCurrency = o;
40743         
40744         if (this.currencyField) {
40745             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40746         } else {
40747             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40748         }
40749         
40750         this.lastSelectionText = currency;
40751         
40752         //setting default currency
40753         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40754             this.setCurrency(this.defaultCurrency);
40755             return;
40756         }
40757         
40758         this.setCurrency(currency);
40759     },
40760     
40761     setFromData : function(o)
40762     {
40763         var c = {};
40764         
40765         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40766         
40767         this.setFromCurrencyData(c);
40768         
40769         var value = '';
40770         
40771         if (this.name) {
40772             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40773         } else {
40774             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40775         }
40776         
40777         this.setValue(value);
40778         
40779     },
40780     
40781     setCurrency : function(v)
40782     {   
40783         this.currencyValue = v;
40784         
40785         if(this.rendered){
40786             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40787             this.validate();
40788         }
40789     },
40790     
40791     setValue : function(v)
40792     {
40793         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40794         
40795         this.value = v;
40796         
40797         if(this.rendered){
40798             
40799             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40800             
40801             this.inputEl().dom.value = (v == '') ? '' :
40802                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40803             
40804             if(!this.allowZero && v === '0') {
40805                 this.hiddenEl().dom.value = '';
40806                 this.inputEl().dom.value = '';
40807             }
40808             
40809             this.validate();
40810         }
40811     },
40812     
40813     getRawValue : function()
40814     {
40815         var v = this.inputEl().getValue();
40816         
40817         return v;
40818     },
40819     
40820     getValue : function()
40821     {
40822         return this.fixPrecision(this.parseValue(this.getRawValue()));
40823     },
40824     
40825     parseValue : function(value)
40826     {
40827         if(this.thousandsDelimiter) {
40828             value += "";
40829             r = new RegExp(",", "g");
40830             value = value.replace(r, "");
40831         }
40832         
40833         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40834         return isNaN(value) ? '' : value;
40835         
40836     },
40837     
40838     fixPrecision : function(value)
40839     {
40840         if(this.thousandsDelimiter) {
40841             value += "";
40842             r = new RegExp(",", "g");
40843             value = value.replace(r, "");
40844         }
40845         
40846         var nan = isNaN(value);
40847         
40848         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40849             return nan ? '' : value;
40850         }
40851         return parseFloat(value).toFixed(this.decimalPrecision);
40852     },
40853     
40854     decimalPrecisionFcn : function(v)
40855     {
40856         return Math.floor(v);
40857     },
40858     
40859     validateValue : function(value)
40860     {
40861         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40862             return false;
40863         }
40864         
40865         var num = this.parseValue(value);
40866         
40867         if(isNaN(num)){
40868             this.markInvalid(String.format(this.nanText, value));
40869             return false;
40870         }
40871         
40872         if(num < this.minValue){
40873             this.markInvalid(String.format(this.minText, this.minValue));
40874             return false;
40875         }
40876         
40877         if(num > this.maxValue){
40878             this.markInvalid(String.format(this.maxText, this.maxValue));
40879             return false;
40880         }
40881         
40882         return true;
40883     },
40884     
40885     validate : function()
40886     {
40887         if(this.disabled || this.allowBlank){
40888             this.markValid();
40889             return true;
40890         }
40891         
40892         var currency = this.getCurrency();
40893         
40894         if(this.validateValue(this.getRawValue()) && currency.length){
40895             this.markValid();
40896             return true;
40897         }
40898         
40899         this.markInvalid();
40900         return false;
40901     },
40902     
40903     getName: function()
40904     {
40905         return this.name;
40906     },
40907     
40908     beforeBlur : function()
40909     {
40910         if(!this.castInt){
40911             return;
40912         }
40913         
40914         var v = this.parseValue(this.getRawValue());
40915         
40916         if(v || v == 0){
40917             this.setValue(v);
40918         }
40919     },
40920     
40921     onBlur : function()
40922     {
40923         this.beforeBlur();
40924         
40925         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40926             //this.el.removeClass(this.focusClass);
40927         }
40928         
40929         this.hasFocus = false;
40930         
40931         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40932             this.validate();
40933         }
40934         
40935         var v = this.getValue();
40936         
40937         if(String(v) !== String(this.startValue)){
40938             this.fireEvent('change', this, v, this.startValue);
40939         }
40940         
40941         this.fireEvent("blur", this);
40942     },
40943     
40944     inputEl : function()
40945     {
40946         return this.el.select('.roo-money-amount-input', true).first();
40947     },
40948     
40949     currencyEl : function()
40950     {
40951         return this.el.select('.roo-money-currency-input', true).first();
40952     },
40953     
40954     hiddenEl : function()
40955     {
40956         return this.el.select('input.hidden-number-input',true).first();
40957     }
40958     
40959 });