buildSDK/dependancy_bootstrap.txt
[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  * 
20  * @constructor
21  * Do not use directly - it does not do anything..
22  * @param {Object} config The config object
23  */
24
25
26
27 Roo.bootstrap.Component = function(config){
28     Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 };
30
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
32     
33     
34     allowDomMove : false, // to stop relocations in parent onRender...
35     
36     cls : false,
37     
38     style : false,
39     
40     autoCreate : false,
41     
42     tooltip : null,
43     /**
44      * Initialize Events for the element
45      */
46     initEvents : function() { },
47     
48     xattr : false,
49     
50     parentId : false,
51     
52     can_build_overlaid : true,
53     
54     dataId : false,
55     
56     name : false,
57     
58     parent: function() {
59         // returns the parent component..
60         return Roo.ComponentMgr.get(this.parentId)
61         
62         
63     },
64     
65     // private
66     onRender : function(ct, position)
67     {
68        // Roo.log("Call onRender: " + this.xtype);
69         
70         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
71         
72         if(this.el){
73             if (this.el.attr('xtype')) {
74                 this.el.attr('xtypex', this.el.attr('xtype'));
75                 this.el.dom.removeAttribute('xtype');
76                 
77                 this.initEvents();
78             }
79             
80             return;
81         }
82         
83          
84         
85         var cfg = Roo.apply({},  this.getAutoCreate());
86         cfg.id = Roo.id();
87         
88         // fill in the extra attributes 
89         if (this.xattr && typeof(this.xattr) =='object') {
90             for (var i in this.xattr) {
91                 cfg[i] = this.xattr[i];
92             }
93         }
94         
95         if(this.dataId){
96             cfg.dataId = this.dataId;
97         }
98         
99         if (this.cls) {
100             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
101         }
102         
103         if (this.style) { // fixme needs to support more complex style data.
104             cfg.style = this.style;
105         }
106         
107         if(this.name){
108             cfg.name = this.name;
109         }
110         
111        
112         
113         this.el = ct.createChild(cfg, position);
114         
115         if (this.tooltip) {
116             this.tooltipEl().attr('tooltip', this.tooltip);
117         }
118         
119         if(this.tabIndex !== undefined){
120             this.el.dom.setAttribute('tabIndex', this.tabIndex);
121         }
122         this.initEvents();
123         
124         
125     },
126     /**
127      * Fetch the element to add children to
128      * @return {Roo.Element} defaults to this.el
129      */
130     getChildContainer : function()
131     {
132         return this.el;
133     },
134     /**
135      * Fetch the element to display the tooltip on.
136      * @return {Roo.Element} defaults to this.el
137      */
138     tooltipEl : function()
139     {
140         return this.el;
141     },
142         
143     addxtype  : function(tree,cntr)
144     {
145         var cn = this;
146         
147         cn = Roo.factory(tree);
148            
149         cn.parentType = this.xtype; //??
150         cn.parentId = this.id;
151         
152         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
153         
154         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
155         
156         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
157         
158         var build_from_html =  Roo.XComponent.build_from_html;
159           
160         var is_body  = (tree.xtype == 'Body') ;
161           
162         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
163           
164         var self_cntr_el = Roo.get(this[cntr](false));
165         
166         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
167             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
168                 return this.addxtypeChild(tree,cntr);
169             }
170             
171             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
172                 
173             if(echild){
174                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
175             }
176             
177             Roo.log('skipping render');
178             return cn;
179             
180         }
181         
182         var ret = false;
183         
184         while (true) {
185             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
186             
187             if (!echild) {
188                 break;
189             }
190             
191             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
192                 break;
193             }
194             
195             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
196         }
197         return ret;
198     },
199     
200     addxtypeChild : function (tree, cntr)
201     {
202         Roo.log('addxtypeChild:' + cntr);
203         var cn = this;
204         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
205         
206         
207         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
208                     (typeof(tree['flexy:foreach']) != 'undefined');
209           
210         
211         
212          skip_children = false;
213         // render the element if it's not BODY.
214         if (tree.xtype != 'Body') {
215            
216             cn = Roo.factory(tree);
217            
218             cn.parentType = this.xtype; //??
219             cn.parentId = this.id;
220             
221             var build_from_html =  Roo.XComponent.build_from_html;
222             
223             
224             // does the container contain child eleemnts with 'xtype' attributes.
225             // that match this xtype..
226             // note - when we render we create these as well..
227             // so we should check to see if body has xtype set.
228             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
229                
230                 var self_cntr_el = Roo.get(this[cntr](false));
231                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
232                 
233                 
234                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
235                 // and are not displayed -this causes this to use up the wrong element when matching.
236                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
237                 
238                 
239                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
240                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
241                   
242                   
243                   
244                     cn.el = echild;
245                   //  Roo.log("GOT");
246                     //echild.dom.removeAttribute('xtype');
247                 } else {
248                     Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
249                     Roo.log(self_cntr_el);
250                     Roo.log(echild);
251                     Roo.log(cn);
252                 }
253             }
254            
255             
256            
257             // if object has flexy:if - then it may or may not be rendered.
258             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
259                 // skip a flexy if element.
260                 Roo.log('skipping render');
261                 Roo.log(tree);
262                 if (!cn.el) {
263                     Roo.log('skipping all children');
264                     skip_children = true;
265                 }
266                 
267              } else {
268                  
269                 // actually if flexy:foreach is found, we really want to create 
270                 // multiple copies here...
271                 //Roo.log('render');
272                 //Roo.log(this[cntr]());
273                 cn.render(this[cntr](true));
274              }
275             // then add the element..
276         }
277         
278         
279         // handle the kids..
280         
281         var nitems = [];
282         /*
283         if (typeof (tree.menu) != 'undefined') {
284             tree.menu.parentType = cn.xtype;
285             tree.menu.triggerEl = cn.el;
286             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
287             
288         }
289         */
290         if (!tree.items || !tree.items.length) {
291             cn.items = nitems;
292             return cn;
293         }
294         var items = tree.items;
295         delete tree.items;
296         
297         //Roo.log(items.length);
298             // add the items..
299         if (!skip_children) {    
300             for(var i =0;i < items.length;i++) {
301                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
302             }
303         }
304         
305         cn.items = nitems;
306         
307         return cn;
308     }
309     
310     
311     
312     
313 });
314
315  /*
316  * - LGPL
317  *
318  * Body
319  * 
320  */
321
322 /**
323  * @class Roo.bootstrap.Body
324  * @extends Roo.bootstrap.Component
325  * Bootstrap Body class
326  * 
327  * @constructor
328  * Create a new body
329  * @param {Object} config The config object
330  */
331
332 Roo.bootstrap.Body = function(config){
333     Roo.bootstrap.Body.superclass.constructor.call(this, config);
334     this.el = Roo.get(document.body);
335     if (this.cls && this.cls.length) {
336         Roo.get(document.body).addClass(this.cls);
337     }
338 };
339
340 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
341       
342         autoCreate : {
343         cls: 'container'
344     },
345     onRender : function(ct, position)
346     {
347        /* Roo.log("Roo.bootstrap.Body - onRender");
348         if (this.cls && this.cls.length) {
349             Roo.get(document.body).addClass(this.cls);
350         }
351         // style??? xttr???
352         */
353     }
354     
355     
356  
357    
358 });
359
360  /*
361  * - LGPL
362  *
363  * button group
364  * 
365  */
366
367
368 /**
369  * @class Roo.bootstrap.ButtonGroup
370  * @extends Roo.bootstrap.Component
371  * Bootstrap ButtonGroup class
372  * @cfg {String} size lg | sm | xs (default empty normal)
373  * @cfg {String} align vertical | justified  (default none)
374  * @cfg {String} direction up | down (default down)
375  * @cfg {Boolean} toolbar false | true
376  * @cfg {Boolean} btn true | false
377  * 
378  * 
379  * @constructor
380  * Create a new Input
381  * @param {Object} config The config object
382  */
383
384 Roo.bootstrap.ButtonGroup = function(config){
385     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
386 };
387
388 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
389     
390     size: '',
391     align: '',
392     direction: '',
393     toolbar: false,
394     btn: true,
395
396     getAutoCreate : function(){
397         var cfg = {
398             cls: 'btn-group',
399             html : null
400         }
401         
402         cfg.html = this.html || cfg.html;
403         
404         if (this.toolbar) {
405             cfg = {
406                 cls: 'btn-toolbar',
407                 html: null
408             }
409             
410             return cfg;
411         }
412         
413         if (['vertical','justified'].indexOf(this.align)!==-1) {
414             cfg.cls = 'btn-group-' + this.align;
415             
416             if (this.align == 'justified') {
417                 console.log(this.items);
418             }
419         }
420         
421         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
422             cfg.cls += ' btn-group-' + this.size;
423         }
424         
425         if (this.direction == 'up') {
426             cfg.cls += ' dropup' ;
427         }
428         
429         return cfg;
430     }
431    
432 });
433
434  /*
435  * - LGPL
436  *
437  * button
438  * 
439  */
440
441 /**
442  * @class Roo.bootstrap.Button
443  * @extends Roo.bootstrap.Component
444  * Bootstrap Button class
445  * @cfg {String} html The button content
446  * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
447  * @cfg {String} size empty | lg | sm | xs
448  * @cfg {String} tag empty | a | input | submit
449  * @cfg {String} href empty or href
450  * @cfg {Boolean} disabled false | true
451  * @cfg {Boolean} isClose false | true
452  * @cfg {String} glyphicon empty | 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
453  * @cfg {String} badge text for badge
454  * @cfg {String} theme default (or empty) | glow
455  * @cfg {Boolean} inverse false | true
456  * @cfg {Boolean} toggle false | true
457  * @cfg {String} ontext text for on toggle state
458  * @cfg {String} offtext text for off toggle state
459  * @cfg {Boolean} defaulton true | false
460  * @cfg {Boolean} preventDefault (true | false) default true
461  * @cfg {Boolean} removeClass true | false remove the standard class..
462  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
463  * 
464  * @constructor
465  * Create a new button
466  * @param {Object} config The config object
467  */
468
469
470 Roo.bootstrap.Button = function(config){
471     Roo.bootstrap.Button.superclass.constructor.call(this, config);
472     this.addEvents({
473         // raw events
474         /**
475          * @event click
476          * When a butotn is pressed
477          * @param {Roo.EventObject} e
478          */
479         "click" : true,
480          /**
481          * @event toggle
482          * After the button has been toggles
483          * @param {Roo.EventObject} e
484          * @param {boolean} pressed (also available as button.pressed)
485          */
486         "toggle" : true
487     });
488 };
489
490 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
491     html: false,
492     active: false,
493     weight: '',
494     size: '',
495     tag: 'button',
496     href: '',
497     disabled: false,
498     isClose: false,
499     glyphicon: '',
500     badge: '',
501     theme: 'default',
502     inverse: false,
503     
504     toggle: false,
505     ontext: 'ON',
506     offtext: 'OFF',
507     defaulton: true,
508     preventDefault: true,
509     removeClass: false,
510     name: false,
511     target: false,
512     
513     
514     pressed : null,
515      
516     
517     getAutoCreate : function(){
518         
519         var cfg = {
520             tag : 'button',
521             cls : 'roo-button',
522             html: ''
523         };
524         
525         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
526             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
527             this.tag = 'button';
528         } else {
529             cfg.tag = this.tag;
530         }
531         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
532         
533         if (this.toggle == true) {
534             cfg={
535                 tag: 'div',
536                 cls: 'slider-frame roo-button',
537                 cn: [
538                     {
539                         tag: 'span',
540                         'data-on-text':'ON',
541                         'data-off-text':'OFF',
542                         cls: 'slider-button',
543                         html: this.offtext
544                     }
545                 ]
546             };
547             
548             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
549                 cfg.cls += ' '+this.weight;
550             }
551             
552             return cfg;
553         }
554         
555         if (this.isClose) {
556             cfg.cls += ' close';
557             
558             cfg["aria-hidden"] = true;
559             
560             cfg.html = "&times;";
561             
562             return cfg;
563         }
564         
565          
566         if (this.theme==='default') {
567             cfg.cls = 'btn roo-button';
568             
569             //if (this.parentType != 'Navbar') {
570             this.weight = this.weight.length ?  this.weight : 'default';
571             //}
572             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
573                 
574                 cfg.cls += ' btn-' + this.weight;
575             }
576         } else if (this.theme==='glow') {
577             
578             cfg.tag = 'a';
579             cfg.cls = 'btn-glow roo-button';
580             
581             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
582                 
583                 cfg.cls += ' ' + this.weight;
584             }
585         }
586    
587         
588         if (this.inverse) {
589             this.cls += ' inverse';
590         }
591         
592         
593         if (this.active) {
594             cfg.cls += ' active';
595         }
596         
597         if (this.disabled) {
598             cfg.disabled = 'disabled';
599         }
600         
601         if (this.items) {
602             Roo.log('changing to ul' );
603             cfg.tag = 'ul';
604             this.glyphicon = 'caret';
605         }
606         
607         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
608          
609         //gsRoo.log(this.parentType);
610         if (this.parentType === 'Navbar' && !this.parent().bar) {
611             Roo.log('changing to li?');
612             
613             cfg.tag = 'li';
614             
615             cfg.cls = '';
616             cfg.cn =  [{
617                 tag : 'a',
618                 cls : 'roo-button',
619                 html : this.html,
620                 href : this.href || '#'
621             }];
622             if (this.menu) {
623                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
624                 cfg.cls += ' dropdown';
625             }   
626             
627             delete cfg.html;
628             
629         }
630         
631        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
632         
633         if (this.glyphicon) {
634             cfg.html = ' ' + cfg.html;
635             
636             cfg.cn = [
637                 {
638                     tag: 'span',
639                     cls: 'glyphicon glyphicon-' + this.glyphicon
640                 }
641             ];
642         }
643         
644         if (this.badge) {
645             cfg.html += ' ';
646             
647             cfg.tag = 'a';
648             
649 //            cfg.cls='btn roo-button';
650             
651             cfg.href=this.href;
652             
653             var value = cfg.html;
654             
655             if(this.glyphicon){
656                 value = {
657                             tag: 'span',
658                             cls: 'glyphicon glyphicon-' + this.glyphicon,
659                             html: this.html
660                         };
661                 
662             }
663             
664             cfg.cn = [
665                 value,
666                 {
667                     tag: 'span',
668                     cls: 'badge',
669                     html: this.badge
670                 }
671             ];
672             
673             cfg.html='';
674         }
675         
676         if (this.menu) {
677             cfg.cls += ' dropdown';
678             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
679         }
680         
681         if (cfg.tag !== 'a' && this.href !== '') {
682             throw "Tag must be a to set href.";
683         } else if (this.href.length > 0) {
684             cfg.href = this.href;
685         }
686         
687         if(this.removeClass){
688             cfg.cls = '';
689         }
690         
691         if(this.target){
692             cfg.target = this.target;
693         }
694         
695         return cfg;
696     },
697     initEvents: function() {
698        // Roo.log('init events?');
699 //        Roo.log(this.el.dom);
700         // add the menu...
701         
702         if (typeof (this.menu) != 'undefined') {
703             this.menu.parentType = this.xtype;
704             this.menu.triggerEl = this.el;
705             this.addxtype(Roo.apply({}, this.menu));
706         }
707
708
709        if (this.el.hasClass('roo-button')) {
710             this.el.on('click', this.onClick, this);
711        } else {
712             this.el.select('.roo-button').on('click', this.onClick, this);
713        }
714        
715        if(this.removeClass){
716            this.el.on('click', this.onClick, this);
717        }
718        
719        this.el.enableDisplayMode();
720         
721     },
722     onClick : function(e)
723     {
724         if (this.disabled) {
725             return;
726         }
727         
728         Roo.log('button on click ');
729         if(this.preventDefault){
730             e.preventDefault();
731         }
732         if (this.pressed === true || this.pressed === false) {
733             this.pressed = !this.pressed;
734             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
735             this.fireEvent('toggle', this, e, this.pressed);
736         }
737         
738         
739         this.fireEvent('click', this, e);
740     },
741     
742     /**
743      * Enables this button
744      */
745     enable : function()
746     {
747         this.disabled = false;
748         this.el.removeClass('disabled');
749     },
750     
751     /**
752      * Disable this button
753      */
754     disable : function()
755     {
756         this.disabled = true;
757         this.el.addClass('disabled');
758     },
759      /**
760      * sets the active state on/off, 
761      * @param {Boolean} state (optional) Force a particular state
762      */
763     setActive : function(v) {
764         
765         this.el[v ? 'addClass' : 'removeClass']('active');
766     },
767      /**
768      * toggles the current active state 
769      */
770     toggleActive : function()
771     {
772        var active = this.el.hasClass('active');
773        this.setActive(!active);
774        
775         
776     },
777     setText : function(str)
778     {
779         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
780     },
781     getText : function()
782     {
783         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
784     },
785     hide: function() {
786        
787      
788         this.el.hide();   
789     },
790     show: function() {
791        
792         this.el.show();   
793     }
794     
795     
796 });
797
798  /*
799  * - LGPL
800  *
801  * column
802  * 
803  */
804
805 /**
806  * @class Roo.bootstrap.Column
807  * @extends Roo.bootstrap.Component
808  * Bootstrap Column class
809  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
810  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
811  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
812  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
813  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
814  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
815  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
816  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
817  *
818  * 
819  * @cfg {Boolean} hidden (true|false) hide the element
820  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
821  * @cfg {String} fa (ban|check|...) font awesome icon
822  * @cfg {Number} fasize (1|2|....) font awsome size
823
824  * @cfg {String} icon (info-sign|check|...) glyphicon name
825
826  * @cfg {String} html content of column.
827  * 
828  * @constructor
829  * Create a new Column
830  * @param {Object} config The config object
831  */
832
833 Roo.bootstrap.Column = function(config){
834     Roo.bootstrap.Column.superclass.constructor.call(this, config);
835 };
836
837 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
838     
839     xs: false,
840     sm: false,
841     md: false,
842     lg: false,
843     xsoff: false,
844     smoff: false,
845     mdoff: false,
846     lgoff: false,
847     html: '',
848     offset: 0,
849     alert: false,
850     fa: false,
851     icon : false,
852     hidden : false,
853     fasize : 1,
854     
855     getAutoCreate : function(){
856         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
857         
858         cfg = {
859             tag: 'div',
860             cls: 'column'
861         };
862         
863         var settings=this;
864         ['xs','sm','md','lg'].map(function(size){
865             //Roo.log( size + ':' + settings[size]);
866             
867             if (settings[size+'off'] !== false) {
868                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
869             }
870             
871             if (settings[size] === false) {
872                 return;
873             }
874             Roo.log(settings[size]);
875             if (!settings[size]) { // 0 = hidden
876                 cfg.cls += ' hidden-' + size;
877                 return;
878             }
879             cfg.cls += ' col-' + size + '-' + settings[size];
880             
881         });
882         
883         if (this.hidden) {
884             cfg.cls += ' hidden';
885         }
886         
887         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
888             cfg.cls +=' alert alert-' + this.alert;
889         }
890         
891         
892         if (this.html.length) {
893             cfg.html = this.html;
894         }
895         if (this.fa) {
896             var fasize = '';
897             if (this.fasize > 1) {
898                 fasize = ' fa-' + this.fasize + 'x';
899             }
900             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
901             
902             
903         }
904         if (this.icon) {
905             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + + (cfg.html || '')
906         }
907         
908         return cfg;
909     }
910    
911 });
912
913  
914
915  /*
916  * - LGPL
917  *
918  * page container.
919  * 
920  */
921
922
923 /**
924  * @class Roo.bootstrap.Container
925  * @extends Roo.bootstrap.Component
926  * Bootstrap Container class
927  * @cfg {Boolean} jumbotron is it a jumbotron element
928  * @cfg {String} html content of element
929  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
930  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
931  * @cfg {String} header content of header (for panel)
932  * @cfg {String} footer content of footer (for panel)
933  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
934  * @cfg {String} tag (header|aside|section) type of HTML tag.
935  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
936  * @cfg {String} fa (ban|check|...) font awesome icon
937  * @cfg {String} icon (info-sign|check|...) glyphicon name
938  * @cfg {Boolean} hidden (true|false) hide the element
939
940  *     
941  * @constructor
942  * Create a new Container
943  * @param {Object} config The config object
944  */
945
946 Roo.bootstrap.Container = function(config){
947     Roo.bootstrap.Container.superclass.constructor.call(this, config);
948 };
949
950 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
951     
952     jumbotron : false,
953     well: '',
954     panel : '',
955     header: '',
956     footer : '',
957     sticky: '',
958     tag : false,
959     alert : false,
960     fa: false,
961     icon : false,
962   
963      
964     getChildContainer : function() {
965         
966         if(!this.el){
967             return false;
968         }
969         
970         if (this.panel.length) {
971             return this.el.select('.panel-body',true).first();
972         }
973         
974         return this.el;
975     },
976     
977     
978     getAutoCreate : function(){
979         
980         var cfg = {
981             tag : this.tag || 'div',
982             html : '',
983             cls : ''
984         };
985         if (this.jumbotron) {
986             cfg.cls = 'jumbotron';
987         }
988         
989         
990         
991         // - this is applied by the parent..
992         //if (this.cls) {
993         //    cfg.cls = this.cls + '';
994         //}
995         
996         if (this.sticky.length) {
997             
998             var bd = Roo.get(document.body);
999             if (!bd.hasClass('bootstrap-sticky')) {
1000                 bd.addClass('bootstrap-sticky');
1001                 Roo.select('html',true).setStyle('height', '100%');
1002             }
1003              
1004             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1005         }
1006         
1007         
1008         if (this.well.length) {
1009             switch (this.well) {
1010                 case 'lg':
1011                 case 'sm':
1012                     cfg.cls +=' well well-' +this.well;
1013                     break;
1014                 default:
1015                     cfg.cls +=' well';
1016                     break;
1017             }
1018         }
1019         
1020         if (this.hidden) {
1021             cfg.cls += ' hidden';
1022         }
1023         
1024         
1025         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1026             cfg.cls +=' alert alert-' + this.alert;
1027         }
1028         
1029         var body = cfg;
1030         
1031         if (this.panel.length) {
1032             cfg.cls += ' panel panel-' + this.panel;
1033             cfg.cn = [];
1034             if (this.header.length) {
1035                 cfg.cn.push({
1036                     
1037                     cls : 'panel-heading',
1038                     cn : [{
1039                         tag: 'h3',
1040                         cls : 'panel-title',
1041                         html : this.header
1042                     }]
1043                     
1044                 });
1045             }
1046             body = false;
1047             cfg.cn.push({
1048                 cls : 'panel-body',
1049                 html : this.html
1050             });
1051             
1052             
1053             if (this.footer.length) {
1054                 cfg.cn.push({
1055                     cls : 'panel-footer',
1056                     html : this.footer
1057                     
1058                 });
1059             }
1060             
1061         }
1062         
1063         if (body) {
1064             body.html = this.html || cfg.html;
1065             // prefix with the icons..
1066             if (this.fa) {
1067                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1068             }
1069             if (this.icon) {
1070                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1071             }
1072             
1073             
1074         }
1075         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1076             cfg.cls =  'container';
1077         }
1078         
1079         return cfg;
1080     },
1081     
1082     titleEl : function()
1083     {
1084         if(!this.el || !this.panel.length || !this.header.length){
1085             return;
1086         }
1087         
1088         return this.el.select('.panel-title',true).first();
1089     },
1090     
1091     setTitle : function(v)
1092     {
1093         var titleEl = this.titleEl();
1094         
1095         if(!titleEl){
1096             return;
1097         }
1098         
1099         titleEl.dom.innerHTML = v;
1100     },
1101     
1102     getTitle : function()
1103     {
1104         
1105         var titleEl = this.titleEl();
1106         
1107         if(!titleEl){
1108             return '';
1109         }
1110         
1111         return titleEl.dom.innerHTML;
1112     }
1113    
1114 });
1115
1116  /*
1117  * - LGPL
1118  *
1119  * image
1120  * 
1121  */
1122
1123
1124 /**
1125  * @class Roo.bootstrap.Img
1126  * @extends Roo.bootstrap.Component
1127  * Bootstrap Img class
1128  * @cfg {Boolean} imgResponsive false | true
1129  * @cfg {String} border rounded | circle | thumbnail
1130  * @cfg {String} src image source
1131  * @cfg {String} alt image alternative text
1132  * @cfg {String} href a tag href
1133  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1134  * 
1135  * @constructor
1136  * Create a new Input
1137  * @param {Object} config The config object
1138  */
1139
1140 Roo.bootstrap.Img = function(config){
1141     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1142     
1143     this.addEvents({
1144         // img events
1145         /**
1146          * @event click
1147          * The img click event for the img.
1148          * @param {Roo.EventObject} e
1149          */
1150         "click" : true
1151     });
1152 };
1153
1154 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1155     
1156     imgResponsive: true,
1157     border: '',
1158     src: '',
1159     href: false,
1160     target: false,
1161
1162     getAutoCreate : function(){
1163         
1164         var cfg = {
1165             tag: 'img',
1166             cls: (this.imgResponsive) ? 'img-responsive' : '',
1167             html : null
1168         }
1169         
1170         cfg.html = this.html || cfg.html;
1171         
1172         cfg.src = this.src || cfg.src;
1173         
1174         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1175             cfg.cls += ' img-' + this.border;
1176         }
1177         
1178         if(this.alt){
1179             cfg.alt = this.alt;
1180         }
1181         
1182         if(this.href){
1183             var a = {
1184                 tag: 'a',
1185                 href: this.href,
1186                 cn: [
1187                     cfg
1188                 ]
1189             }
1190             
1191             if(this.target){
1192                 a.target = this.target;
1193             }
1194             
1195         }
1196         
1197         
1198         return (this.href) ? a : cfg;
1199     },
1200     
1201     initEvents: function() {
1202         
1203         if(!this.href){
1204             this.el.on('click', this.onClick, this);
1205         }
1206     },
1207     
1208     onClick : function(e)
1209     {
1210         Roo.log('img onclick');
1211         this.fireEvent('click', this, e);
1212     }
1213    
1214 });
1215
1216  /*
1217  * - LGPL
1218  *
1219  * image
1220  * 
1221  */
1222
1223
1224 /**
1225  * @class Roo.bootstrap.Link
1226  * @extends Roo.bootstrap.Component
1227  * Bootstrap Link Class
1228  * @cfg {String} alt image alternative text
1229  * @cfg {String} href a tag href
1230  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1231  * @cfg {String} html the content of the link.
1232  * @cfg {String} anchor name for the anchor link
1233
1234  * @cfg {Boolean} preventDefault (true | false) default false
1235
1236  * 
1237  * @constructor
1238  * Create a new Input
1239  * @param {Object} config The config object
1240  */
1241
1242 Roo.bootstrap.Link = function(config){
1243     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1244     
1245     this.addEvents({
1246         // img events
1247         /**
1248          * @event click
1249          * The img click event for the img.
1250          * @param {Roo.EventObject} e
1251          */
1252         "click" : true
1253     });
1254 };
1255
1256 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1257     
1258     href: false,
1259     target: false,
1260     preventDefault: false,
1261     anchor : false,
1262     alt : false,
1263
1264     getAutoCreate : function()
1265     {
1266         
1267         var cfg = {
1268             tag: 'a'
1269         };
1270         // anchor's do not require html/href...
1271         if (this.anchor === false) {
1272             cfg.html = this.html || 'html-missing';
1273             cfg.href = this.href || '#';
1274         } else {
1275             cfg.name = this.anchor;
1276             if (this.html !== false) {
1277                 cfg.html = this.html;
1278             }
1279             if (this.href !== false) {
1280                 cfg.href = this.href;
1281             }
1282         }
1283         
1284         if(this.alt !== false){
1285             cfg.alt = this.alt;
1286         }
1287         
1288         
1289         if(this.target !== false) {
1290             cfg.target = this.target;
1291         }
1292         
1293         return cfg;
1294     },
1295     
1296     initEvents: function() {
1297         
1298         if(!this.href || this.preventDefault){
1299             this.el.on('click', this.onClick, this);
1300         }
1301     },
1302     
1303     onClick : function(e)
1304     {
1305         if(this.preventDefault){
1306             e.preventDefault();
1307         }
1308         //Roo.log('img onclick');
1309         this.fireEvent('click', this, e);
1310     }
1311    
1312 });
1313
1314  /*
1315  * - LGPL
1316  *
1317  * header
1318  * 
1319  */
1320
1321 /**
1322  * @class Roo.bootstrap.Header
1323  * @extends Roo.bootstrap.Component
1324  * Bootstrap Header class
1325  * @cfg {String} html content of header
1326  * @cfg {Number} level (1|2|3|4|5|6) default 1
1327  * 
1328  * @constructor
1329  * Create a new Header
1330  * @param {Object} config The config object
1331  */
1332
1333
1334 Roo.bootstrap.Header  = function(config){
1335     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1336 };
1337
1338 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1339     
1340     //href : false,
1341     html : false,
1342     level : 1,
1343     
1344     
1345     
1346     getAutoCreate : function(){
1347         
1348         var cfg = {
1349             tag: 'h' + (1 *this.level),
1350             html: this.html || 'fill in html'
1351         } ;
1352         
1353         return cfg;
1354     }
1355    
1356 });
1357
1358  
1359
1360  /*
1361  * Based on:
1362  * Ext JS Library 1.1.1
1363  * Copyright(c) 2006-2007, Ext JS, LLC.
1364  *
1365  * Originally Released Under LGPL - original licence link has changed is not relivant.
1366  *
1367  * Fork - LGPL
1368  * <script type="text/javascript">
1369  */
1370  
1371 /**
1372  * @class Roo.bootstrap.MenuMgr
1373  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1374  * @singleton
1375  */
1376 Roo.bootstrap.MenuMgr = function(){
1377    var menus, active, groups = {}, attached = false, lastShow = new Date();
1378
1379    // private - called when first menu is created
1380    function init(){
1381        menus = {};
1382        active = new Roo.util.MixedCollection();
1383        Roo.get(document).addKeyListener(27, function(){
1384            if(active.length > 0){
1385                hideAll();
1386            }
1387        });
1388    }
1389
1390    // private
1391    function hideAll(){
1392        if(active && active.length > 0){
1393            var c = active.clone();
1394            c.each(function(m){
1395                m.hide();
1396            });
1397        }
1398    }
1399
1400    // private
1401    function onHide(m){
1402        active.remove(m);
1403        if(active.length < 1){
1404            Roo.get(document).un("mouseup", onMouseDown);
1405             
1406            attached = false;
1407        }
1408    }
1409
1410    // private
1411    function onShow(m){
1412        var last = active.last();
1413        lastShow = new Date();
1414        active.add(m);
1415        if(!attached){
1416           Roo.get(document).on("mouseup", onMouseDown);
1417            
1418            attached = true;
1419        }
1420        if(m.parentMenu){
1421           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1422           m.parentMenu.activeChild = m;
1423        }else if(last && last.isVisible()){
1424           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1425        }
1426    }
1427
1428    // private
1429    function onBeforeHide(m){
1430        if(m.activeChild){
1431            m.activeChild.hide();
1432        }
1433        if(m.autoHideTimer){
1434            clearTimeout(m.autoHideTimer);
1435            delete m.autoHideTimer;
1436        }
1437    }
1438
1439    // private
1440    function onBeforeShow(m){
1441        var pm = m.parentMenu;
1442        if(!pm && !m.allowOtherMenus){
1443            hideAll();
1444        }else if(pm && pm.activeChild && active != m){
1445            pm.activeChild.hide();
1446        }
1447    }
1448
1449    // private
1450    function onMouseDown(e){
1451         Roo.log("on MouseDown");
1452         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1453            hideAll();
1454         }
1455         
1456         
1457    }
1458
1459    // private
1460    function onBeforeCheck(mi, state){
1461        if(state){
1462            var g = groups[mi.group];
1463            for(var i = 0, l = g.length; i < l; i++){
1464                if(g[i] != mi){
1465                    g[i].setChecked(false);
1466                }
1467            }
1468        }
1469    }
1470
1471    return {
1472
1473        /**
1474         * Hides all menus that are currently visible
1475         */
1476        hideAll : function(){
1477             hideAll();  
1478        },
1479
1480        // private
1481        register : function(menu){
1482            if(!menus){
1483                init();
1484            }
1485            menus[menu.id] = menu;
1486            menu.on("beforehide", onBeforeHide);
1487            menu.on("hide", onHide);
1488            menu.on("beforeshow", onBeforeShow);
1489            menu.on("show", onShow);
1490            var g = menu.group;
1491            if(g && menu.events["checkchange"]){
1492                if(!groups[g]){
1493                    groups[g] = [];
1494                }
1495                groups[g].push(menu);
1496                menu.on("checkchange", onCheck);
1497            }
1498        },
1499
1500         /**
1501          * Returns a {@link Roo.menu.Menu} object
1502          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1503          * be used to generate and return a new Menu instance.
1504          */
1505        get : function(menu){
1506            if(typeof menu == "string"){ // menu id
1507                return menus[menu];
1508            }else if(menu.events){  // menu instance
1509                return menu;
1510            }
1511            /*else if(typeof menu.length == 'number'){ // array of menu items?
1512                return new Roo.bootstrap.Menu({items:menu});
1513            }else{ // otherwise, must be a config
1514                return new Roo.bootstrap.Menu(menu);
1515            }
1516            */
1517            return false;
1518        },
1519
1520        // private
1521        unregister : function(menu){
1522            delete menus[menu.id];
1523            menu.un("beforehide", onBeforeHide);
1524            menu.un("hide", onHide);
1525            menu.un("beforeshow", onBeforeShow);
1526            menu.un("show", onShow);
1527            var g = menu.group;
1528            if(g && menu.events["checkchange"]){
1529                groups[g].remove(menu);
1530                menu.un("checkchange", onCheck);
1531            }
1532        },
1533
1534        // private
1535        registerCheckable : function(menuItem){
1536            var g = menuItem.group;
1537            if(g){
1538                if(!groups[g]){
1539                    groups[g] = [];
1540                }
1541                groups[g].push(menuItem);
1542                menuItem.on("beforecheckchange", onBeforeCheck);
1543            }
1544        },
1545
1546        // private
1547        unregisterCheckable : function(menuItem){
1548            var g = menuItem.group;
1549            if(g){
1550                groups[g].remove(menuItem);
1551                menuItem.un("beforecheckchange", onBeforeCheck);
1552            }
1553        }
1554    };
1555 }();/*
1556  * - LGPL
1557  *
1558  * menu
1559  * 
1560  */
1561
1562 /**
1563  * @class Roo.bootstrap.Menu
1564  * @extends Roo.bootstrap.Component
1565  * Bootstrap Menu class - container for MenuItems
1566  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1567  * 
1568  * @constructor
1569  * Create a new Menu
1570  * @param {Object} config The config object
1571  */
1572
1573
1574 Roo.bootstrap.Menu = function(config){
1575     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1576     if (this.registerMenu) {
1577         Roo.bootstrap.MenuMgr.register(this);
1578     }
1579     this.addEvents({
1580         /**
1581          * @event beforeshow
1582          * Fires before this menu is displayed
1583          * @param {Roo.menu.Menu} this
1584          */
1585         beforeshow : true,
1586         /**
1587          * @event beforehide
1588          * Fires before this menu is hidden
1589          * @param {Roo.menu.Menu} this
1590          */
1591         beforehide : true,
1592         /**
1593          * @event show
1594          * Fires after this menu is displayed
1595          * @param {Roo.menu.Menu} this
1596          */
1597         show : true,
1598         /**
1599          * @event hide
1600          * Fires after this menu is hidden
1601          * @param {Roo.menu.Menu} this
1602          */
1603         hide : true,
1604         /**
1605          * @event click
1606          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1607          * @param {Roo.menu.Menu} this
1608          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1609          * @param {Roo.EventObject} e
1610          */
1611         click : true,
1612         /**
1613          * @event mouseover
1614          * Fires when the mouse is hovering over this menu
1615          * @param {Roo.menu.Menu} this
1616          * @param {Roo.EventObject} e
1617          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1618          */
1619         mouseover : true,
1620         /**
1621          * @event mouseout
1622          * Fires when the mouse exits this menu
1623          * @param {Roo.menu.Menu} this
1624          * @param {Roo.EventObject} e
1625          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1626          */
1627         mouseout : true,
1628         /**
1629          * @event itemclick
1630          * Fires when a menu item contained in this menu is clicked
1631          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1632          * @param {Roo.EventObject} e
1633          */
1634         itemclick: true
1635     });
1636     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1637 };
1638
1639 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1640     
1641    /// html : false,
1642     //align : '',
1643     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1644     type: false,
1645     /**
1646      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1647      */
1648     registerMenu : true,
1649     
1650     menuItems :false, // stores the menu items..
1651     
1652     hidden:true,
1653     
1654     parentMenu : false,
1655     
1656     getChildContainer : function() {
1657         return this.el;  
1658     },
1659     
1660     getAutoCreate : function(){
1661          
1662         //if (['right'].indexOf(this.align)!==-1) {
1663         //    cfg.cn[1].cls += ' pull-right'
1664         //}
1665         
1666         
1667         var cfg = {
1668             tag : 'ul',
1669             cls : 'dropdown-menu' ,
1670             style : 'z-index:1000'
1671             
1672         }
1673         
1674         if (this.type === 'submenu') {
1675             cfg.cls = 'submenu active';
1676         }
1677         if (this.type === 'treeview') {
1678             cfg.cls = 'treeview-menu';
1679         }
1680         
1681         return cfg;
1682     },
1683     initEvents : function() {
1684         
1685        // Roo.log("ADD event");
1686        // Roo.log(this.triggerEl.dom);
1687         this.triggerEl.on('click', this.onTriggerPress, this);
1688         this.triggerEl.addClass('dropdown-toggle');
1689         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1690
1691         this.el.on("mouseover", this.onMouseOver, this);
1692         this.el.on("mouseout", this.onMouseOut, this);
1693         
1694         
1695     },
1696     findTargetItem : function(e){
1697         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1698         if(!t){
1699             return false;
1700         }
1701         //Roo.log(t);         Roo.log(t.id);
1702         if(t && t.id){
1703             //Roo.log(this.menuitems);
1704             return this.menuitems.get(t.id);
1705             
1706             //return this.items.get(t.menuItemId);
1707         }
1708         
1709         return false;
1710     },
1711     onClick : function(e){
1712         Roo.log("menu.onClick");
1713         var t = this.findTargetItem(e);
1714         if(!t || t.isContainer){
1715             return;
1716         }
1717         Roo.log(e);
1718         /*
1719         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1720             if(t == this.activeItem && t.shouldDeactivate(e)){
1721                 this.activeItem.deactivate();
1722                 delete this.activeItem;
1723                 return;
1724             }
1725             if(t.canActivate){
1726                 this.setActiveItem(t, true);
1727             }
1728             return;
1729             
1730             
1731         }
1732         */
1733        
1734         Roo.log('pass click event');
1735         
1736         t.onClick(e);
1737         
1738         this.fireEvent("click", this, t, e);
1739         
1740         this.hide();
1741     },
1742      onMouseOver : function(e){
1743         var t  = this.findTargetItem(e);
1744         //Roo.log(t);
1745         //if(t){
1746         //    if(t.canActivate && !t.disabled){
1747         //        this.setActiveItem(t, true);
1748         //    }
1749         //}
1750         
1751         this.fireEvent("mouseover", this, e, t);
1752     },
1753     isVisible : function(){
1754         return !this.hidden;
1755     },
1756      onMouseOut : function(e){
1757         var t  = this.findTargetItem(e);
1758         
1759         //if(t ){
1760         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1761         //        this.activeItem.deactivate();
1762         //        delete this.activeItem;
1763         //    }
1764         //}
1765         this.fireEvent("mouseout", this, e, t);
1766     },
1767     
1768     
1769     /**
1770      * Displays this menu relative to another element
1771      * @param {String/HTMLElement/Roo.Element} element The element to align to
1772      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1773      * the element (defaults to this.defaultAlign)
1774      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1775      */
1776     show : function(el, pos, parentMenu){
1777         this.parentMenu = parentMenu;
1778         if(!this.el){
1779             this.render();
1780         }
1781         this.fireEvent("beforeshow", this);
1782         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1783     },
1784      /**
1785      * Displays this menu at a specific xy position
1786      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1787      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1788      */
1789     showAt : function(xy, parentMenu, /* private: */_e){
1790         this.parentMenu = parentMenu;
1791         if(!this.el){
1792             this.render();
1793         }
1794         if(_e !== false){
1795             this.fireEvent("beforeshow", this);
1796             
1797             //xy = this.el.adjustForConstraints(xy);
1798         }
1799         //this.el.setXY(xy);
1800         //this.el.show();
1801         this.hideMenuItems();
1802         this.hidden = false;
1803         this.triggerEl.addClass('open');
1804         this.focus();
1805         this.fireEvent("show", this);
1806     },
1807     
1808     focus : function(){
1809         return;
1810         if(!this.hidden){
1811             this.doFocus.defer(50, this);
1812         }
1813     },
1814
1815     doFocus : function(){
1816         if(!this.hidden){
1817             this.focusEl.focus();
1818         }
1819     },
1820
1821     /**
1822      * Hides this menu and optionally all parent menus
1823      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1824      */
1825     hide : function(deep){
1826         
1827         this.hideMenuItems();
1828         if(this.el && this.isVisible()){
1829             this.fireEvent("beforehide", this);
1830             if(this.activeItem){
1831                 this.activeItem.deactivate();
1832                 this.activeItem = null;
1833             }
1834             this.triggerEl.removeClass('open');;
1835             this.hidden = true;
1836             this.fireEvent("hide", this);
1837         }
1838         if(deep === true && this.parentMenu){
1839             this.parentMenu.hide(true);
1840         }
1841     },
1842     
1843     onTriggerPress  : function(e)
1844     {
1845         
1846         Roo.log('trigger press');
1847         //Roo.log(e.getTarget());
1848        // Roo.log(this.triggerEl.dom);
1849         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1850             return;
1851         }
1852         if (this.isVisible()) {
1853             Roo.log('hide');
1854             this.hide();
1855         } else {
1856             this.show(this.triggerEl, false, false);
1857         }
1858         
1859         
1860     },
1861     
1862          
1863        
1864     
1865     hideMenuItems : function()
1866     {
1867         //$(backdrop).remove()
1868         Roo.select('.open',true).each(function(aa) {
1869             
1870             aa.removeClass('open');
1871           //var parent = getParent($(this))
1872           //var relatedTarget = { relatedTarget: this }
1873           
1874            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1875           //if (e.isDefaultPrevented()) return
1876            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1877         })
1878     },
1879     addxtypeChild : function (tree, cntr) {
1880         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1881           
1882         this.menuitems.add(comp);
1883         return comp;
1884
1885     },
1886     getEl : function()
1887     {
1888         Roo.log(this.el);
1889         return this.el;
1890     }
1891 });
1892
1893  
1894  /*
1895  * - LGPL
1896  *
1897  * menu item
1898  * 
1899  */
1900
1901
1902 /**
1903  * @class Roo.bootstrap.MenuItem
1904  * @extends Roo.bootstrap.Component
1905  * Bootstrap MenuItem class
1906  * @cfg {String} html the menu label
1907  * @cfg {String} href the link
1908  * @cfg {Boolean} preventDefault (true | false) default true
1909  * @cfg {Boolean} isContainer (true | false) default false
1910  * 
1911  * 
1912  * @constructor
1913  * Create a new MenuItem
1914  * @param {Object} config The config object
1915  */
1916
1917
1918 Roo.bootstrap.MenuItem = function(config){
1919     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1920     this.addEvents({
1921         // raw events
1922         /**
1923          * @event click
1924          * The raw click event for the entire grid.
1925          * @param {Roo.EventObject} e
1926          */
1927         "click" : true
1928     });
1929 };
1930
1931 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1932     
1933     href : false,
1934     html : false,
1935     preventDefault: true,
1936     isContainer : false,
1937     
1938     getAutoCreate : function(){
1939         
1940         if(this.isContainer){
1941             return {
1942                 tag: 'li',
1943                 cls: 'dropdown-menu-item'
1944             };
1945         }
1946         
1947         var cfg= {
1948             tag: 'li',
1949             cls: 'dropdown-menu-item',
1950             cn: [
1951                     {
1952                         tag : 'a',
1953                         href : '#',
1954                         html : 'Link'
1955                     }
1956                 ]
1957         };
1958         if (this.parent().type == 'treeview') {
1959             cfg.cls = 'treeview-menu';
1960         }
1961         
1962         cfg.cn[0].href = this.href || cfg.cn[0].href ;
1963         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1964         return cfg;
1965     },
1966     
1967     initEvents: function() {
1968         
1969         //this.el.select('a').on('click', this.onClick, this);
1970         
1971     },
1972     onClick : function(e)
1973     {
1974         Roo.log('item on click ');
1975         //if(this.preventDefault){
1976         //    e.preventDefault();
1977         //}
1978         //this.parent().hideMenuItems();
1979         
1980         this.fireEvent('click', this, e);
1981     },
1982     getEl : function()
1983     {
1984         return this.el;
1985     }
1986 });
1987
1988  
1989
1990  /*
1991  * - LGPL
1992  *
1993  * menu separator
1994  * 
1995  */
1996
1997
1998 /**
1999  * @class Roo.bootstrap.MenuSeparator
2000  * @extends Roo.bootstrap.Component
2001  * Bootstrap MenuSeparator class
2002  * 
2003  * @constructor
2004  * Create a new MenuItem
2005  * @param {Object} config The config object
2006  */
2007
2008
2009 Roo.bootstrap.MenuSeparator = function(config){
2010     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2011 };
2012
2013 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2014     
2015     getAutoCreate : function(){
2016         var cfg = {
2017             cls: 'divider',
2018             tag : 'li'
2019         };
2020         
2021         return cfg;
2022     }
2023    
2024 });
2025
2026  
2027
2028  
2029 /*
2030 <div class="modal fade">
2031   <div class="modal-dialog">
2032     <div class="modal-content">
2033       <div class="modal-header">
2034         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
2035         <h4 class="modal-title">Modal title</h4>
2036       </div>
2037       <div class="modal-body">
2038         <p>One fine body&hellip;</p>
2039       </div>
2040       <div class="modal-footer">
2041         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2042         <button type="button" class="btn btn-primary">Save changes</button>
2043       </div>
2044     </div><!-- /.modal-content -->
2045   </div><!-- /.modal-dialog -->
2046 </div><!-- /.modal -->
2047 */
2048 /*
2049  * - LGPL
2050  *
2051  * page contgainer.
2052  * 
2053  */
2054
2055 /**
2056  * @class Roo.bootstrap.Modal
2057  * @extends Roo.bootstrap.Component
2058  * Bootstrap Modal class
2059  * @cfg {String} title Title of dialog
2060  * @cfg {Boolean} specificTitle (true|false) default false
2061  * @cfg {Array} buttons Array of buttons or standard button set..
2062  * @cfg {String} buttonPosition (left|right|center) default right
2063  * @cfg {Boolean} animate (true | false) default true
2064  * 
2065  * @constructor
2066  * Create a new Modal Dialog
2067  * @param {Object} config The config object
2068  */
2069
2070 Roo.bootstrap.Modal = function(config){
2071     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2072     this.addEvents({
2073         // raw events
2074         /**
2075          * @event btnclick
2076          * The raw btnclick event for the button
2077          * @param {Roo.EventObject} e
2078          */
2079         "btnclick" : true
2080     });
2081     this.buttons = this.buttons || [];
2082 };
2083
2084 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2085     
2086     title : 'test dialog',
2087    
2088     buttons : false,
2089     
2090     // set on load...
2091     body:  false,
2092     
2093     specificTitle: false,
2094     
2095     buttonPosition: 'right',
2096     
2097     animate : true,
2098     
2099     onRender : function(ct, position)
2100     {
2101         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2102      
2103         if(!this.el){
2104             var cfg = Roo.apply({},  this.getAutoCreate());
2105             cfg.id = Roo.id();
2106             //if(!cfg.name){
2107             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2108             //}
2109             //if (!cfg.name.length) {
2110             //    delete cfg.name;
2111            // }
2112             if (this.cls) {
2113                 cfg.cls += ' ' + this.cls;
2114             }
2115             if (this.style) {
2116                 cfg.style = this.style;
2117             }
2118             this.el = Roo.get(document.body).createChild(cfg, position);
2119         }
2120         //var type = this.el.dom.type;
2121         
2122         if(this.tabIndex !== undefined){
2123             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2124         }
2125         
2126         
2127         
2128         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2129         this.maskEl.enableDisplayMode("block");
2130         this.maskEl.hide();
2131         //this.el.addClass("x-dlg-modal");
2132     
2133         if (this.buttons.length) {
2134             Roo.each(this.buttons, function(bb) {
2135                 b = Roo.apply({}, bb);
2136                 b.xns = b.xns || Roo.bootstrap;
2137                 b.xtype = b.xtype || 'Button';
2138                 if (typeof(b.listeners) == 'undefined') {
2139                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2140                 }
2141                 
2142                 var btn = Roo.factory(b);
2143                 
2144                 btn.onRender(this.el.select('.modal-footer div').first());
2145                 
2146             },this);
2147         }
2148         // render the children.
2149         var nitems = [];
2150         
2151         if(typeof(this.items) != 'undefined'){
2152             var items = this.items;
2153             delete this.items;
2154
2155             for(var i =0;i < items.length;i++) {
2156                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2157             }
2158         }
2159         
2160         this.items = nitems;
2161         
2162         this.body = this.el.select('.modal-body',true).first();
2163         this.close = this.el.select('.modal-header .close', true).first();
2164         this.footer = this.el.select('.modal-footer',true).first();
2165         this.initEvents();
2166         //this.el.addClass([this.fieldClass, this.cls]);
2167         
2168     },
2169     getAutoCreate : function(){
2170         
2171         
2172         var bdy = {
2173                 cls : 'modal-body',
2174                 html : this.html || ''
2175         };
2176         
2177         var title = {
2178             tag: 'h4',
2179             cls : 'modal-title',
2180             html : this.title
2181         };
2182         
2183         if(this.specificTitle){
2184             title = this.title;
2185         };
2186         
2187         var modal = {
2188             cls: "modal",
2189             style : 'display: none',
2190             cn : [
2191                 {
2192                     cls: "modal-dialog",
2193                     cn : [
2194                         {
2195                             cls : "modal-content",
2196                             cn : [
2197                                 {
2198                                     cls : 'modal-header',
2199                                     cn : [
2200                                         {
2201                                             tag: 'button',
2202                                             cls : 'close',
2203                                             html : '&times'
2204                                         },
2205                                         title
2206                                     ]
2207                                 },
2208                                 bdy,
2209                                 {
2210                                     cls : 'modal-footer',
2211                                     cn : [
2212                                         {
2213                                             tag: 'div',
2214                                             cls: 'btn-' + this.buttonPosition
2215                                         }
2216                                     ]
2217                                     
2218                                 }
2219                                 
2220                                 
2221                             ]
2222                             
2223                         }
2224                     ]
2225                         
2226                 }
2227             ]
2228         };
2229         
2230         if(this.animate){
2231             modal.cls += ' fade';
2232         }
2233         
2234         return modal;
2235           
2236     },
2237     getChildContainer : function() {
2238          
2239          return this.el.select('.modal-body',true).first();
2240         
2241     },
2242     getButtonContainer : function() {
2243          return this.el.select('.modal-footer div',true).first();
2244         
2245     },
2246     initEvents : function()
2247     {
2248         this.el.select('.modal-header .close').on('click', this.hide, this);
2249 //        
2250 //        this.addxtype(this);
2251     },
2252     show : function() {
2253         
2254         if (!this.rendered) {
2255             this.render();
2256         }
2257         
2258         this.el.setStyle('display', 'block');
2259         
2260         if(this.animate){
2261             var _this = this;
2262             (function(){ _this.el.addClass('in'); }).defer(50);
2263         }else{
2264             this.el.addClass('in');
2265         }
2266         
2267         Roo.get(document.body).addClass("x-body-masked");
2268         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2269         this.maskEl.show();
2270         this.el.setStyle('zIndex', '10001');
2271         this.fireEvent('show', this);
2272         
2273         
2274     },
2275     hide : function()
2276     {
2277         this.maskEl.hide();
2278         Roo.get(document.body).removeClass("x-body-masked");
2279         this.el.removeClass('in');
2280         
2281         if(this.animate){
2282             var _this = this;
2283             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2284         }else{
2285             this.el.setStyle('display', 'none');
2286         }
2287         
2288         this.fireEvent('hide', this);
2289     },
2290     
2291     addButton : function(str, cb)
2292     {
2293          
2294         
2295         var b = Roo.apply({}, { html : str } );
2296         b.xns = b.xns || Roo.bootstrap;
2297         b.xtype = b.xtype || 'Button';
2298         if (typeof(b.listeners) == 'undefined') {
2299             b.listeners = { click : cb.createDelegate(this)  };
2300         }
2301         
2302         var btn = Roo.factory(b);
2303            
2304         btn.onRender(this.el.select('.modal-footer div').first());
2305         
2306         return btn;   
2307        
2308     },
2309     
2310     setDefaultButton : function(btn)
2311     {
2312         //this.el.select('.modal-footer').()
2313     },
2314     resizeTo: function(w,h)
2315     {
2316         // skip..
2317     },
2318     setContentSize  : function(w, h)
2319     {
2320         
2321     },
2322     onButtonClick: function(btn,e)
2323     {
2324         //Roo.log([a,b,c]);
2325         this.fireEvent('btnclick', btn.name, e);
2326     },
2327     setTitle: function(str) {
2328         this.el.select('.modal-title',true).first().dom.innerHTML = str;
2329         
2330     }
2331 });
2332
2333
2334 Roo.apply(Roo.bootstrap.Modal,  {
2335     /**
2336          * Button config that displays a single OK button
2337          * @type Object
2338          */
2339         OK :  [{
2340             name : 'ok',
2341             weight : 'primary',
2342             html : 'OK'
2343         }], 
2344         /**
2345          * Button config that displays Yes and No buttons
2346          * @type Object
2347          */
2348         YESNO : [
2349             {
2350                 name  : 'no',
2351                 html : 'No'
2352             },
2353             {
2354                 name  :'yes',
2355                 weight : 'primary',
2356                 html : 'Yes'
2357             }
2358         ],
2359         
2360         /**
2361          * Button config that displays OK and Cancel buttons
2362          * @type Object
2363          */
2364         OKCANCEL : [
2365             {
2366                name : 'cancel',
2367                 html : 'Cancel'
2368             },
2369             {
2370                 name : 'ok',
2371                 weight : 'primary',
2372                 html : 'OK'
2373             }
2374         ],
2375         /**
2376          * Button config that displays Yes, No and Cancel buttons
2377          * @type Object
2378          */
2379         YESNOCANCEL : [
2380             {
2381                 name : 'yes',
2382                 weight : 'primary',
2383                 html : 'Yes'
2384             },
2385             {
2386                 name : 'no',
2387                 html : 'No'
2388             },
2389             {
2390                 name : 'cancel',
2391                 html : 'Cancel'
2392             }
2393         ]
2394 });
2395  /*
2396  * - LGPL
2397  *
2398  * messagebox - can be used as a replace
2399  * 
2400  */
2401 /**
2402  * @class Roo.MessageBox
2403  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2404  * Example usage:
2405  *<pre><code>
2406 // Basic alert:
2407 Roo.Msg.alert('Status', 'Changes saved successfully.');
2408
2409 // Prompt for user data:
2410 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2411     if (btn == 'ok'){
2412         // process text value...
2413     }
2414 });
2415
2416 // Show a dialog using config options:
2417 Roo.Msg.show({
2418    title:'Save Changes?',
2419    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2420    buttons: Roo.Msg.YESNOCANCEL,
2421    fn: processResult,
2422    animEl: 'elId'
2423 });
2424 </code></pre>
2425  * @singleton
2426  */
2427 Roo.bootstrap.MessageBox = function(){
2428     var dlg, opt, mask, waitTimer;
2429     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2430     var buttons, activeTextEl, bwidth;
2431
2432     
2433     // private
2434     var handleButton = function(button){
2435         dlg.hide();
2436         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2437     };
2438
2439     // private
2440     var handleHide = function(){
2441         if(opt && opt.cls){
2442             dlg.el.removeClass(opt.cls);
2443         }
2444         //if(waitTimer){
2445         //    Roo.TaskMgr.stop(waitTimer);
2446         //    waitTimer = null;
2447         //}
2448     };
2449
2450     // private
2451     var updateButtons = function(b){
2452         var width = 0;
2453         if(!b){
2454             buttons["ok"].hide();
2455             buttons["cancel"].hide();
2456             buttons["yes"].hide();
2457             buttons["no"].hide();
2458             //dlg.footer.dom.style.display = 'none';
2459             return width;
2460         }
2461         dlg.footer.dom.style.display = '';
2462         for(var k in buttons){
2463             if(typeof buttons[k] != "function"){
2464                 if(b[k]){
2465                     buttons[k].show();
2466                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2467                     width += buttons[k].el.getWidth()+15;
2468                 }else{
2469                     buttons[k].hide();
2470                 }
2471             }
2472         }
2473         return width;
2474     };
2475
2476     // private
2477     var handleEsc = function(d, k, e){
2478         if(opt && opt.closable !== false){
2479             dlg.hide();
2480         }
2481         if(e){
2482             e.stopEvent();
2483         }
2484     };
2485
2486     return {
2487         /**
2488          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2489          * @return {Roo.BasicDialog} The BasicDialog element
2490          */
2491         getDialog : function(){
2492            if(!dlg){
2493                 dlg = new Roo.bootstrap.Modal( {
2494                     //draggable: true,
2495                     //resizable:false,
2496                     //constraintoviewport:false,
2497                     //fixedcenter:true,
2498                     //collapsible : false,
2499                     //shim:true,
2500                     //modal: true,
2501                   //  width:400,
2502                   //  height:100,
2503                     //buttonAlign:"center",
2504                     closeClick : function(){
2505                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2506                             handleButton("no");
2507                         }else{
2508                             handleButton("cancel");
2509                         }
2510                     }
2511                 });
2512                 dlg.render();
2513                 dlg.on("hide", handleHide);
2514                 mask = dlg.mask;
2515                 //dlg.addKeyListener(27, handleEsc);
2516                 buttons = {};
2517                 this.buttons = buttons;
2518                 var bt = this.buttonText;
2519                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2520                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2521                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2522                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2523                 Roo.log(buttons)
2524                 bodyEl = dlg.body.createChild({
2525
2526                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2527                         '<textarea class="roo-mb-textarea"></textarea>' +
2528                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2529                 });
2530                 msgEl = bodyEl.dom.firstChild;
2531                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2532                 textboxEl.enableDisplayMode();
2533                 textboxEl.addKeyListener([10,13], function(){
2534                     if(dlg.isVisible() && opt && opt.buttons){
2535                         if(opt.buttons.ok){
2536                             handleButton("ok");
2537                         }else if(opt.buttons.yes){
2538                             handleButton("yes");
2539                         }
2540                     }
2541                 });
2542                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2543                 textareaEl.enableDisplayMode();
2544                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2545                 progressEl.enableDisplayMode();
2546                 var pf = progressEl.dom.firstChild;
2547                 if (pf) {
2548                     pp = Roo.get(pf.firstChild);
2549                     pp.setHeight(pf.offsetHeight);
2550                 }
2551                 
2552             }
2553             return dlg;
2554         },
2555
2556         /**
2557          * Updates the message box body text
2558          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2559          * the XHTML-compliant non-breaking space character '&amp;#160;')
2560          * @return {Roo.MessageBox} This message box
2561          */
2562         updateText : function(text){
2563             if(!dlg.isVisible() && !opt.width){
2564                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2565             }
2566             msgEl.innerHTML = text || '&#160;';
2567       
2568             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2569             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2570             var w = Math.max(
2571                     Math.min(opt.width || cw , this.maxWidth), 
2572                     Math.max(opt.minWidth || this.minWidth, bwidth)
2573             );
2574             if(opt.prompt){
2575                 activeTextEl.setWidth(w);
2576             }
2577             if(dlg.isVisible()){
2578                 dlg.fixedcenter = false;
2579             }
2580             // to big, make it scroll. = But as usual stupid IE does not support
2581             // !important..
2582             
2583             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2584                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2585                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2586             } else {
2587                 bodyEl.dom.style.height = '';
2588                 bodyEl.dom.style.overflowY = '';
2589             }
2590             if (cw > w) {
2591                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2592             } else {
2593                 bodyEl.dom.style.overflowX = '';
2594             }
2595             
2596             dlg.setContentSize(w, bodyEl.getHeight());
2597             if(dlg.isVisible()){
2598                 dlg.fixedcenter = true;
2599             }
2600             return this;
2601         },
2602
2603         /**
2604          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2605          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2606          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2607          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2608          * @return {Roo.MessageBox} This message box
2609          */
2610         updateProgress : function(value, text){
2611             if(text){
2612                 this.updateText(text);
2613             }
2614             if (pp) { // weird bug on my firefox - for some reason this is not defined
2615                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2616             }
2617             return this;
2618         },        
2619
2620         /**
2621          * Returns true if the message box is currently displayed
2622          * @return {Boolean} True if the message box is visible, else false
2623          */
2624         isVisible : function(){
2625             return dlg && dlg.isVisible();  
2626         },
2627
2628         /**
2629          * Hides the message box if it is displayed
2630          */
2631         hide : function(){
2632             if(this.isVisible()){
2633                 dlg.hide();
2634             }  
2635         },
2636
2637         /**
2638          * Displays a new message box, or reinitializes an existing message box, based on the config options
2639          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2640          * The following config object properties are supported:
2641          * <pre>
2642 Property    Type             Description
2643 ----------  ---------------  ------------------------------------------------------------------------------------
2644 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2645                                    closes (defaults to undefined)
2646 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2647                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2648 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2649                                    progress and wait dialogs will ignore this property and always hide the
2650                                    close button as they can only be closed programmatically.
2651 cls               String           A custom CSS class to apply to the message box element
2652 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2653                                    displayed (defaults to 75)
2654 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2655                                    function will be btn (the name of the button that was clicked, if applicable,
2656                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2657                                    Progress and wait dialogs will ignore this option since they do not respond to
2658                                    user actions and can only be closed programmatically, so any required function
2659                                    should be called by the same code after it closes the dialog.
2660 icon              String           A CSS class that provides a background image to be used as an icon for
2661                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2662 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2663 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2664 modal             Boolean          False to allow user interaction with the page while the message box is
2665                                    displayed (defaults to true)
2666 msg               String           A string that will replace the existing message box body text (defaults
2667                                    to the XHTML-compliant non-breaking space character '&#160;')
2668 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2669 progress          Boolean          True to display a progress bar (defaults to false)
2670 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2671 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2672 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2673 title             String           The title text
2674 value             String           The string value to set into the active textbox element if displayed
2675 wait              Boolean          True to display a progress bar (defaults to false)
2676 width             Number           The width of the dialog in pixels
2677 </pre>
2678          *
2679          * Example usage:
2680          * <pre><code>
2681 Roo.Msg.show({
2682    title: 'Address',
2683    msg: 'Please enter your address:',
2684    width: 300,
2685    buttons: Roo.MessageBox.OKCANCEL,
2686    multiline: true,
2687    fn: saveAddress,
2688    animEl: 'addAddressBtn'
2689 });
2690 </code></pre>
2691          * @param {Object} config Configuration options
2692          * @return {Roo.MessageBox} This message box
2693          */
2694         show : function(options)
2695         {
2696             
2697             // this causes nightmares if you show one dialog after another
2698             // especially on callbacks..
2699              
2700             if(this.isVisible()){
2701                 
2702                 this.hide();
2703                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2704                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2705                 Roo.log("New Dialog Message:" +  options.msg )
2706                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2707                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2708                 
2709             }
2710             var d = this.getDialog();
2711             opt = options;
2712             d.setTitle(opt.title || "&#160;");
2713             d.close.setDisplayed(opt.closable !== false);
2714             activeTextEl = textboxEl;
2715             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2716             if(opt.prompt){
2717                 if(opt.multiline){
2718                     textboxEl.hide();
2719                     textareaEl.show();
2720                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2721                         opt.multiline : this.defaultTextHeight);
2722                     activeTextEl = textareaEl;
2723                 }else{
2724                     textboxEl.show();
2725                     textareaEl.hide();
2726                 }
2727             }else{
2728                 textboxEl.hide();
2729                 textareaEl.hide();
2730             }
2731             progressEl.setDisplayed(opt.progress === true);
2732             this.updateProgress(0);
2733             activeTextEl.dom.value = opt.value || "";
2734             if(opt.prompt){
2735                 dlg.setDefaultButton(activeTextEl);
2736             }else{
2737                 var bs = opt.buttons;
2738                 var db = null;
2739                 if(bs && bs.ok){
2740                     db = buttons["ok"];
2741                 }else if(bs && bs.yes){
2742                     db = buttons["yes"];
2743                 }
2744                 dlg.setDefaultButton(db);
2745             }
2746             bwidth = updateButtons(opt.buttons);
2747             this.updateText(opt.msg);
2748             if(opt.cls){
2749                 d.el.addClass(opt.cls);
2750             }
2751             d.proxyDrag = opt.proxyDrag === true;
2752             d.modal = opt.modal !== false;
2753             d.mask = opt.modal !== false ? mask : false;
2754             if(!d.isVisible()){
2755                 // force it to the end of the z-index stack so it gets a cursor in FF
2756                 document.body.appendChild(dlg.el.dom);
2757                 d.animateTarget = null;
2758                 d.show(options.animEl);
2759             }
2760             return this;
2761         },
2762
2763         /**
2764          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2765          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2766          * and closing the message box when the process is complete.
2767          * @param {String} title The title bar text
2768          * @param {String} msg The message box body text
2769          * @return {Roo.MessageBox} This message box
2770          */
2771         progress : function(title, msg){
2772             this.show({
2773                 title : title,
2774                 msg : msg,
2775                 buttons: false,
2776                 progress:true,
2777                 closable:false,
2778                 minWidth: this.minProgressWidth,
2779                 modal : true
2780             });
2781             return this;
2782         },
2783
2784         /**
2785          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2786          * If a callback function is passed it will be called after the user clicks the button, and the
2787          * id of the button that was clicked will be passed as the only parameter to the callback
2788          * (could also be the top-right close button).
2789          * @param {String} title The title bar text
2790          * @param {String} msg The message box body text
2791          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2792          * @param {Object} scope (optional) The scope of the callback function
2793          * @return {Roo.MessageBox} This message box
2794          */
2795         alert : function(title, msg, fn, scope){
2796             this.show({
2797                 title : title,
2798                 msg : msg,
2799                 buttons: this.OK,
2800                 fn: fn,
2801                 scope : scope,
2802                 modal : true
2803             });
2804             return this;
2805         },
2806
2807         /**
2808          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2809          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2810          * You are responsible for closing the message box when the process is complete.
2811          * @param {String} msg The message box body text
2812          * @param {String} title (optional) The title bar text
2813          * @return {Roo.MessageBox} This message box
2814          */
2815         wait : function(msg, title){
2816             this.show({
2817                 title : title,
2818                 msg : msg,
2819                 buttons: false,
2820                 closable:false,
2821                 progress:true,
2822                 modal:true,
2823                 width:300,
2824                 wait:true
2825             });
2826             waitTimer = Roo.TaskMgr.start({
2827                 run: function(i){
2828                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2829                 },
2830                 interval: 1000
2831             });
2832             return this;
2833         },
2834
2835         /**
2836          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2837          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2838          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2839          * @param {String} title The title bar text
2840          * @param {String} msg The message box body text
2841          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2842          * @param {Object} scope (optional) The scope of the callback function
2843          * @return {Roo.MessageBox} This message box
2844          */
2845         confirm : function(title, msg, fn, scope){
2846             this.show({
2847                 title : title,
2848                 msg : msg,
2849                 buttons: this.YESNO,
2850                 fn: fn,
2851                 scope : scope,
2852                 modal : true
2853             });
2854             return this;
2855         },
2856
2857         /**
2858          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2859          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2860          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2861          * (could also be the top-right close button) and the text that was entered will be passed as the two
2862          * parameters to the callback.
2863          * @param {String} title The title bar text
2864          * @param {String} msg The message box body text
2865          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2866          * @param {Object} scope (optional) The scope of the callback function
2867          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2868          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2869          * @return {Roo.MessageBox} This message box
2870          */
2871         prompt : function(title, msg, fn, scope, multiline){
2872             this.show({
2873                 title : title,
2874                 msg : msg,
2875                 buttons: this.OKCANCEL,
2876                 fn: fn,
2877                 minWidth:250,
2878                 scope : scope,
2879                 prompt:true,
2880                 multiline: multiline,
2881                 modal : true
2882             });
2883             return this;
2884         },
2885
2886         /**
2887          * Button config that displays a single OK button
2888          * @type Object
2889          */
2890         OK : {ok:true},
2891         /**
2892          * Button config that displays Yes and No buttons
2893          * @type Object
2894          */
2895         YESNO : {yes:true, no:true},
2896         /**
2897          * Button config that displays OK and Cancel buttons
2898          * @type Object
2899          */
2900         OKCANCEL : {ok:true, cancel:true},
2901         /**
2902          * Button config that displays Yes, No and Cancel buttons
2903          * @type Object
2904          */
2905         YESNOCANCEL : {yes:true, no:true, cancel:true},
2906
2907         /**
2908          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2909          * @type Number
2910          */
2911         defaultTextHeight : 75,
2912         /**
2913          * The maximum width in pixels of the message box (defaults to 600)
2914          * @type Number
2915          */
2916         maxWidth : 600,
2917         /**
2918          * The minimum width in pixels of the message box (defaults to 100)
2919          * @type Number
2920          */
2921         minWidth : 100,
2922         /**
2923          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
2924          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2925          * @type Number
2926          */
2927         minProgressWidth : 250,
2928         /**
2929          * An object containing the default button text strings that can be overriden for localized language support.
2930          * Supported properties are: ok, cancel, yes and no.
2931          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2932          * @type Object
2933          */
2934         buttonText : {
2935             ok : "OK",
2936             cancel : "Cancel",
2937             yes : "Yes",
2938             no : "No"
2939         }
2940     };
2941 }();
2942
2943 /**
2944  * Shorthand for {@link Roo.MessageBox}
2945  */
2946 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox 
2947 Roo.Msg = Roo.Msg || Roo.MessageBox;
2948 /*
2949  * - LGPL
2950  *
2951  * navbar
2952  * 
2953  */
2954
2955 /**
2956  * @class Roo.bootstrap.Navbar
2957  * @extends Roo.bootstrap.Component
2958  * Bootstrap Navbar class
2959
2960  * @constructor
2961  * Create a new Navbar
2962  * @param {Object} config The config object
2963  */
2964
2965
2966 Roo.bootstrap.Navbar = function(config){
2967     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2968     
2969 };
2970
2971 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
2972     
2973     
2974    
2975     // private
2976     navItems : false,
2977     loadMask : false,
2978     
2979     
2980     getAutoCreate : function(){
2981         
2982         
2983         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2984         
2985     },
2986     
2987     initEvents :function ()
2988     {
2989         //Roo.log(this.el.select('.navbar-toggle',true));
2990         this.el.select('.navbar-toggle',true).on('click', function() {
2991            // Roo.log('click');
2992             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
2993         }, this);
2994         
2995         var mark = {
2996             tag: "div",
2997             cls:"x-dlg-mask"
2998         }
2999         
3000         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3001         
3002         var size = this.el.getSize();
3003         this.maskEl.setSize(size.width, size.height);
3004         this.maskEl.enableDisplayMode("block");
3005         this.maskEl.hide();
3006         
3007         if(this.loadMask){
3008             this.maskEl.show();
3009         }
3010     },
3011     
3012     
3013     getChildContainer : function()
3014     {
3015         if (this.el.select('.collapse').getCount()) {
3016             return this.el.select('.collapse',true).first();
3017         }
3018         
3019         return this.el;
3020     },
3021     
3022     mask : function()
3023     {
3024         this.maskEl.show();
3025     },
3026     
3027     unmask : function()
3028     {
3029         this.maskEl.hide();
3030     } 
3031     
3032     
3033     
3034     
3035 });
3036
3037
3038
3039  
3040
3041  /*
3042  * - LGPL
3043  *
3044  * navbar
3045  * 
3046  */
3047
3048 /**
3049  * @class Roo.bootstrap.NavSimplebar
3050  * @extends Roo.bootstrap.Navbar
3051  * Bootstrap Sidebar class
3052  *
3053  * @cfg {Boolean} inverse is inverted color
3054  * 
3055  * @cfg {String} type (nav | pills | tabs)
3056  * @cfg {Boolean} arrangement stacked | justified
3057  * @cfg {String} align (left | right) alignment
3058  * 
3059  * @cfg {Boolean} main (true|false) main nav bar? default false
3060  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3061  * 
3062  * @cfg {String} tag (header|footer|nav|div) default is nav 
3063
3064  * 
3065  * 
3066  * 
3067  * @constructor
3068  * Create a new Sidebar
3069  * @param {Object} config The config object
3070  */
3071
3072
3073 Roo.bootstrap.NavSimplebar = function(config){
3074     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3075 };
3076
3077 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3078     
3079     inverse: false,
3080     
3081     type: false,
3082     arrangement: '',
3083     align : false,
3084     
3085     
3086     
3087     main : false,
3088     
3089     
3090     tag : false,
3091     
3092     
3093     getAutoCreate : function(){
3094         
3095         
3096         var cfg = {
3097             tag : this.tag || 'div',
3098             cls : 'navbar'
3099         };
3100           
3101         
3102         cfg.cn = [
3103             {
3104                 cls: 'nav',
3105                 tag : 'ul'
3106             }
3107         ];
3108         
3109          
3110         this.type = this.type || 'nav';
3111         if (['tabs','pills'].indexOf(this.type)!==-1) {
3112             cfg.cn[0].cls += ' nav-' + this.type
3113         
3114         
3115         } else {
3116             if (this.type!=='nav') {
3117                 Roo.log('nav type must be nav/tabs/pills')
3118             }
3119             cfg.cn[0].cls += ' navbar-nav'
3120         }
3121         
3122         
3123         
3124         
3125         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3126             cfg.cn[0].cls += ' nav-' + this.arrangement;
3127         }
3128         
3129         
3130         if (this.align === 'right') {
3131             cfg.cn[0].cls += ' navbar-right';
3132         }
3133         
3134         if (this.inverse) {
3135             cfg.cls += ' navbar-inverse';
3136             
3137         }
3138         
3139         
3140         return cfg;
3141     
3142         
3143     }
3144     
3145     
3146     
3147 });
3148
3149
3150
3151  
3152
3153  
3154        /*
3155  * - LGPL
3156  *
3157  * navbar
3158  * 
3159  */
3160
3161 /**
3162  * @class Roo.bootstrap.NavHeaderbar
3163  * @extends Roo.bootstrap.NavSimplebar
3164  * Bootstrap Sidebar class
3165  *
3166  * @cfg {String} brand what is brand
3167  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3168  * @cfg {String} brand_href href of the brand
3169  * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3170  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3171  * 
3172  * @constructor
3173  * Create a new Sidebar
3174  * @param {Object} config The config object
3175  */
3176
3177
3178 Roo.bootstrap.NavHeaderbar = function(config){
3179     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3180 };
3181
3182 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3183     
3184     position: '',
3185     brand: '',
3186     brand_href: false,
3187     srButton : true,
3188     autohide : false,
3189     
3190     getAutoCreate : function(){
3191         
3192         var   cfg = {
3193             tag: this.nav || 'nav',
3194             cls: 'navbar',
3195             role: 'navigation',
3196             cn: []
3197         };
3198         
3199         if(this.srButton){
3200             cfg.cn.push({
3201                 tag: 'div',
3202                 cls: 'navbar-header',
3203                 cn: [
3204                     {
3205                         tag: 'button',
3206                         type: 'button',
3207                         cls: 'navbar-toggle',
3208                         'data-toggle': 'collapse',
3209                         cn: [
3210                             {
3211                                 tag: 'span',
3212                                 cls: 'sr-only',
3213                                 html: 'Toggle navigation'
3214                             },
3215                             {
3216                                 tag: 'span',
3217                                 cls: 'icon-bar'
3218                             },
3219                             {
3220                                 tag: 'span',
3221                                 cls: 'icon-bar'
3222                             },
3223                             {
3224                                 tag: 'span',
3225                                 cls: 'icon-bar'
3226                             }
3227                         ]
3228                     }
3229                 ]
3230             });
3231         }
3232         
3233         cfg.cn.push({
3234             tag: 'div',
3235             cls: 'collapse navbar-collapse',
3236             cn : []
3237         });
3238         
3239         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3240         
3241         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3242             cfg.cls += ' navbar-' + this.position;
3243             
3244             // tag can override this..
3245             
3246             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3247         }
3248         
3249         if (this.brand !== '') {
3250             cfg.cn[0].cn.push({
3251                 tag: 'a',
3252                 href: this.brand_href ? this.brand_href : '#',
3253                 cls: 'navbar-brand',
3254                 cn: [
3255                 this.brand
3256                 ]
3257             });
3258         }
3259         
3260         if(this.main){
3261             cfg.cls += ' main-nav';
3262         }
3263         
3264         
3265         return cfg;
3266
3267         
3268     },
3269     initEvents : function()
3270     {
3271         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3272         
3273         if (this.autohide) {
3274             
3275             var prevScroll = 0;
3276             var ft = this.el;
3277             
3278             Roo.get(document).on('scroll',function(e) {
3279                 var ns = Roo.get(document).getScroll().top;
3280                 var os = prevScroll;
3281                 prevScroll = ns;
3282                 
3283                 if(ns > os){
3284                     ft.removeClass('slideDown');
3285                     ft.addClass('slideUp');
3286                     return;
3287                 }
3288                 ft.removeClass('slideUp');
3289                 ft.addClass('slideDown');
3290                  
3291               
3292           },this);
3293         }
3294     }    
3295           
3296       
3297     
3298     
3299 });
3300
3301
3302
3303  
3304
3305  /*
3306  * - LGPL
3307  *
3308  * navbar
3309  * 
3310  */
3311
3312 /**
3313  * @class Roo.bootstrap.NavSidebar
3314  * @extends Roo.bootstrap.Navbar
3315  * Bootstrap Sidebar class
3316  * 
3317  * @constructor
3318  * Create a new Sidebar
3319  * @param {Object} config The config object
3320  */
3321
3322
3323 Roo.bootstrap.NavSidebar = function(config){
3324     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3325 };
3326
3327 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3328     
3329     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3330     
3331     getAutoCreate : function(){
3332         
3333         
3334         return  {
3335             tag: 'div',
3336             cls: 'sidebar sidebar-nav'
3337         };
3338     
3339         
3340     }
3341     
3342     
3343     
3344 });
3345
3346
3347
3348  
3349
3350  /*
3351  * - LGPL
3352  *
3353  * nav group
3354  * 
3355  */
3356
3357 /**
3358  * @class Roo.bootstrap.NavGroup
3359  * @extends Roo.bootstrap.Component
3360  * Bootstrap NavGroup class
3361  * @cfg {String} align left | right
3362  * @cfg {Boolean} inverse false | true
3363  * @cfg {String} type (nav|pills|tab) default nav
3364  * @cfg {String} navId - reference Id for navbar.
3365
3366  * 
3367  * @constructor
3368  * Create a new nav group
3369  * @param {Object} config The config object
3370  */
3371
3372 Roo.bootstrap.NavGroup = function(config){
3373     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3374     this.navItems = [];
3375    
3376     Roo.bootstrap.NavGroup.register(this);
3377      this.addEvents({
3378         /**
3379              * @event changed
3380              * Fires when the active item changes
3381              * @param {Roo.bootstrap.NavGroup} this
3382              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3383              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3384          */
3385         'changed': true
3386      });
3387     
3388 };
3389
3390 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3391     
3392     align: '',
3393     inverse: false,
3394     form: false,
3395     type: 'nav',
3396     navId : '',
3397     // private
3398     
3399     navItems : false, 
3400     
3401     getAutoCreate : function()
3402     {
3403         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3404         
3405         cfg = {
3406             tag : 'ul',
3407             cls: 'nav' 
3408         }
3409         
3410         if (['tabs','pills'].indexOf(this.type)!==-1) {
3411             cfg.cls += ' nav-' + this.type
3412         } else {
3413             if (this.type!=='nav') {
3414                 Roo.log('nav type must be nav/tabs/pills')
3415             }
3416             cfg.cls += ' navbar-nav'
3417         }
3418         
3419         if (this.parent().sidebar) {
3420             cfg = {
3421                 tag: 'ul',
3422                 cls: 'dashboard-menu sidebar-menu'
3423             }
3424             
3425             return cfg;
3426         }
3427         
3428         if (this.form === true) {
3429             cfg = {
3430                 tag: 'form',
3431                 cls: 'navbar-form'
3432             }
3433             
3434             if (this.align === 'right') {
3435                 cfg.cls += ' navbar-right';
3436             } else {
3437                 cfg.cls += ' navbar-left';
3438             }
3439         }
3440         
3441         if (this.align === 'right') {
3442             cfg.cls += ' navbar-right';
3443         }
3444         
3445         if (this.inverse) {
3446             cfg.cls += ' navbar-inverse';
3447             
3448         }
3449         
3450         
3451         return cfg;
3452     },
3453     /**
3454     * sets the active Navigation item
3455     * @param {Roo.bootstrap.NavItem} the new current navitem
3456     */
3457     setActiveItem : function(item)
3458     {
3459         var prev = false;
3460         Roo.each(this.navItems, function(v){
3461             if (v == item) {
3462                 return ;
3463             }
3464             if (v.isActive()) {
3465                 v.setActive(false, true);
3466                 prev = v;
3467                 
3468             }
3469             
3470         });
3471
3472         item.setActive(true, true);
3473         this.fireEvent('changed', this, item, prev);
3474         
3475         
3476     },
3477     /**
3478     * gets the active Navigation item
3479     * @return {Roo.bootstrap.NavItem} the current navitem
3480     */
3481     getActive : function()
3482     {
3483         
3484         var prev = false;
3485         Roo.each(this.navItems, function(v){
3486             
3487             if (v.isActive()) {
3488                 prev = v;
3489                 
3490             }
3491             
3492         });
3493         return prev;
3494     },
3495     
3496     indexOfNav : function()
3497     {
3498         
3499         var prev = false;
3500         Roo.each(this.navItems, function(v,i){
3501             
3502             if (v.isActive()) {
3503                 prev = i;
3504                 
3505             }
3506             
3507         });
3508         return prev;
3509     },
3510     /**
3511     * adds a Navigation item
3512     * @param {Roo.bootstrap.NavItem} the navitem to add
3513     */
3514     addItem : function(cfg)
3515     {
3516         var cn = new Roo.bootstrap.NavItem(cfg);
3517         this.register(cn);
3518         cn.parentId = this.id;
3519         cn.onRender(this.el, null);
3520         return cn;
3521     },
3522     /**
3523     * register a Navigation item
3524     * @param {Roo.bootstrap.NavItem} the navitem to add
3525     */
3526     register : function(item)
3527     {
3528         this.navItems.push( item);
3529         item.navId = this.navId;
3530     
3531     },
3532     
3533     /**
3534     * clear all the Navigation item
3535     */
3536    
3537     clearAll : function()
3538     {
3539         this.navItems = [];
3540         this.el.dom.innerHTML = '';
3541     },
3542     
3543     getNavItem: function(tabId)
3544     {
3545         var ret = false;
3546         Roo.each(this.navItems, function(e) {
3547             if (e.tabId == tabId) {
3548                ret =  e;
3549                return false;
3550             }
3551             return true;
3552             
3553         });
3554         return ret;
3555     },
3556     
3557     setActiveNext : function()
3558     {
3559         var i = this.indexOfNav(this.getActive());
3560         if (i > this.navItems.length) {
3561             return;
3562         }
3563         this.setActiveItem(this.navItems[i+1]);
3564     },
3565     setActivePrev : function()
3566     {
3567         var i = this.indexOfNav(this.getActive());
3568         if (i  < 1) {
3569             return;
3570         }
3571         this.setActiveItem(this.navItems[i-1]);
3572     },
3573     clearWasActive : function(except) {
3574         Roo.each(this.navItems, function(e) {
3575             if (e.tabId != except.tabId && e.was_active) {
3576                e.was_active = false;
3577                return false;
3578             }
3579             return true;
3580             
3581         });
3582     },
3583     getWasActive : function ()
3584     {
3585         var r = false;
3586         Roo.each(this.navItems, function(e) {
3587             if (e.was_active) {
3588                r = e;
3589                return false;
3590             }
3591             return true;
3592             
3593         });
3594         return r;
3595     }
3596     
3597     
3598 });
3599
3600  
3601 Roo.apply(Roo.bootstrap.NavGroup, {
3602     
3603     groups: {},
3604      /**
3605     * register a Navigation Group
3606     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3607     */
3608     register : function(navgrp)
3609     {
3610         this.groups[navgrp.navId] = navgrp;
3611         
3612     },
3613     /**
3614     * fetch a Navigation Group based on the navigation ID
3615     * @param {string} the navgroup to add
3616     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3617     */
3618     get: function(navId) {
3619         if (typeof(this.groups[navId]) == 'undefined') {
3620             return false;
3621             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3622         }
3623         return this.groups[navId] ;
3624     }
3625     
3626     
3627     
3628 });
3629
3630  /*
3631  * - LGPL
3632  *
3633  * row
3634  * 
3635  */
3636
3637 /**
3638  * @class Roo.bootstrap.NavItem
3639  * @extends Roo.bootstrap.Component
3640  * Bootstrap Navbar.NavItem class
3641  * @cfg {String} href  link to
3642  * @cfg {String} html content of button
3643  * @cfg {String} badge text inside badge
3644  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3645  * @cfg {String} glyphicon name of glyphicon
3646  * @cfg {String} icon name of font awesome icon
3647  * @cfg {Boolean} active Is item active
3648  * @cfg {Boolean} disabled Is item disabled
3649  
3650  * @cfg {Boolean} preventDefault (true | false) default false
3651  * @cfg {String} tabId the tab that this item activates.
3652  * @cfg {String} tagtype (a|span) render as a href or span?
3653   
3654  * @constructor
3655  * Create a new Navbar Item
3656  * @param {Object} config The config object
3657  */
3658 Roo.bootstrap.NavItem = function(config){
3659     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3660     this.addEvents({
3661         // raw events
3662         /**
3663          * @event click
3664          * The raw click event for the entire grid.
3665          * @param {Roo.EventObject} e
3666          */
3667         "click" : true,
3668          /**
3669             * @event changed
3670             * Fires when the active item active state changes
3671             * @param {Roo.bootstrap.NavItem} this
3672             * @param {boolean} state the new state
3673              
3674          */
3675         'changed': true
3676     });
3677    
3678 };
3679
3680 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3681     
3682     href: false,
3683     html: '',
3684     badge: '',
3685     icon: false,
3686     glyphicon: false,
3687     active: false,
3688     preventDefault : false,
3689     tabId : false,
3690     tagtype : 'a',
3691     disabled : false,
3692     
3693     was_active : false,
3694     
3695     getAutoCreate : function(){
3696          
3697         var cfg = {
3698             tag: 'li',
3699             cls: 'nav-item'
3700             
3701         }
3702         if (this.active) {
3703             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3704         }
3705         if (this.disabled) {
3706             cfg.cls += ' disabled';
3707         }
3708         
3709         if (this.href || this.html || this.glyphicon || this.icon) {
3710             cfg.cn = [
3711                 {
3712                     tag: this.tagtype,
3713                     href : this.href || "#",
3714                     html: this.html || ''
3715                 }
3716             ];
3717             
3718             if (this.icon) {
3719                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3720             }
3721
3722             if(this.glyphicon) {
3723                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3724             }
3725             
3726             if (this.menu) {
3727                 
3728                 cfg.cn[0].html += " <span class='caret'></span>";
3729              
3730             }
3731             
3732             if (this.badge !== '') {
3733                  
3734                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3735             }
3736         }
3737         
3738         
3739         
3740         return cfg;
3741     },
3742     initEvents: function() 
3743     {
3744         if (typeof (this.menu) != 'undefined') {
3745             this.menu.parentType = this.xtype;
3746             this.menu.triggerEl = this.el;
3747             this.addxtype(Roo.apply({}, this.menu));
3748         }
3749         
3750         this.el.select('a',true).on('click', this.onClick, this);
3751         
3752         if(this.tagtype == 'span'){
3753             this.el.select('span',true).on('click', this.onClick, this);
3754         }
3755        
3756         // at this point parent should be available..
3757         this.parent().register(this);
3758     },
3759     
3760     onClick : function(e)
3761     {
3762          
3763         if(this.preventDefault){
3764             e.preventDefault();
3765         }
3766         if (this.disabled) {
3767             return;
3768         }
3769         
3770         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3771         if (tg && tg.transition) {
3772             Roo.log("waiting for the transitionend");
3773             return;
3774         }
3775         
3776         Roo.log("fire event clicked");
3777         if(this.fireEvent('click', this, e) === false){
3778             return;
3779         };
3780         
3781         if(this.tagtype == 'span'){
3782             return;
3783         }
3784         
3785         var p = this.parent();
3786         if (['tabs','pills'].indexOf(p.type)!==-1) {
3787             if (typeof(p.setActiveItem) !== 'undefined') {
3788                 p.setActiveItem(this);
3789             }
3790         }
3791         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3792         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3793             // remove the collapsed menu expand...
3794             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3795         }
3796         
3797     },
3798     
3799     isActive: function () {
3800         return this.active
3801     },
3802     setActive : function(state, fire, is_was_active)
3803     {
3804         if (this.active && !state & this.navId) {
3805             this.was_active = true;
3806             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3807             if (nv) {
3808                 nv.clearWasActive(this);
3809             }
3810             
3811         }
3812         this.active = state;
3813         
3814         if (!state ) {
3815             this.el.removeClass('active');
3816         } else if (!this.el.hasClass('active')) {
3817             this.el.addClass('active');
3818         }
3819         if (fire) {
3820             this.fireEvent('changed', this, state);
3821         }
3822         
3823         // show a panel if it's registered and related..
3824         
3825         if (!this.navId || !this.tabId || !state || is_was_active) {
3826             return;
3827         }
3828         
3829         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3830         if (!tg) {
3831             return;
3832         }
3833         var pan = tg.getPanelByName(this.tabId);
3834         if (!pan) {
3835             return;
3836         }
3837         // if we can not flip to new panel - go back to old nav highlight..
3838         if (false == tg.showPanel(pan)) {
3839             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3840             if (nv) {
3841                 var onav = nv.getWasActive();
3842                 if (onav) {
3843                     onav.setActive(true, false, true);
3844                 }
3845             }
3846             
3847         }
3848         
3849         
3850         
3851     },
3852      // this should not be here...
3853     setDisabled : function(state)
3854     {
3855         this.disabled = state;
3856         if (!state ) {
3857             this.el.removeClass('disabled');
3858         } else if (!this.el.hasClass('disabled')) {
3859             this.el.addClass('disabled');
3860         }
3861         
3862     }
3863 });
3864  
3865
3866  /*
3867  * - LGPL
3868  *
3869  * sidebar item
3870  *
3871  *  li
3872  *    <span> icon </span>
3873  *    <span> text </span>
3874  *    <span>badge </span>
3875  */
3876
3877 /**
3878  * @class Roo.bootstrap.NavSidebarItem
3879  * @extends Roo.bootstrap.NavItem
3880  * Bootstrap Navbar.NavSidebarItem class
3881  * @constructor
3882  * Create a new Navbar Button
3883  * @param {Object} config The config object
3884  */
3885 Roo.bootstrap.NavSidebarItem = function(config){
3886     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3887     this.addEvents({
3888         // raw events
3889         /**
3890          * @event click
3891          * The raw click event for the entire grid.
3892          * @param {Roo.EventObject} e
3893          */
3894         "click" : true,
3895          /**
3896             * @event changed
3897             * Fires when the active item active state changes
3898             * @param {Roo.bootstrap.NavSidebarItem} this
3899             * @param {boolean} state the new state
3900              
3901          */
3902         'changed': true
3903     });
3904    
3905 };
3906
3907 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
3908     
3909     
3910     getAutoCreate : function(){
3911         
3912         
3913         var a = {
3914                 tag: 'a',
3915                 href : this.href || '#',
3916                 cls: '',
3917                 html : '',
3918                 cn : []
3919         };
3920         var cfg = {
3921             tag: 'li',
3922             cls: '',
3923             cn: [ a ]
3924         }
3925         var span = {
3926             tag: 'span',
3927             html : this.html || ''
3928         }
3929         
3930         
3931         if (this.active) {
3932             cfg.cls += ' active';
3933         }
3934         
3935         // left icon..
3936         if (this.glyphicon || this.icon) {
3937             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
3938             a.cn.push({ tag : 'i', cls : c }) ;
3939         }
3940         // html..
3941         a.cn.push(span);
3942         // then badge..
3943         if (this.badge !== '') {
3944             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
3945         }
3946         // fi
3947         if (this.menu) {
3948             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3949             a.cls += 'dropdown-toggle treeview' ;
3950             
3951         }
3952         
3953         
3954         
3955         return cfg;
3956          
3957            
3958     }
3959    
3960      
3961  
3962 });
3963  
3964
3965  /*
3966  * - LGPL
3967  *
3968  * row
3969  * 
3970  */
3971
3972 /**
3973  * @class Roo.bootstrap.Row
3974  * @extends Roo.bootstrap.Component
3975  * Bootstrap Row class (contains columns...)
3976  * 
3977  * @constructor
3978  * Create a new Row
3979  * @param {Object} config The config object
3980  */
3981
3982 Roo.bootstrap.Row = function(config){
3983     Roo.bootstrap.Row.superclass.constructor.call(this, config);
3984 };
3985
3986 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
3987     
3988     getAutoCreate : function(){
3989        return {
3990             cls: 'row clearfix'
3991        };
3992     }
3993     
3994     
3995 });
3996
3997  
3998
3999  /*
4000  * - LGPL
4001  *
4002  * element
4003  * 
4004  */
4005
4006 /**
4007  * @class Roo.bootstrap.Element
4008  * @extends Roo.bootstrap.Component
4009  * Bootstrap Element class
4010  * @cfg {String} html contents of the element
4011  * @cfg {String} tag tag of the element
4012  * @cfg {String} cls class of the element
4013  * 
4014  * @constructor
4015  * Create a new Element
4016  * @param {Object} config The config object
4017  */
4018
4019 Roo.bootstrap.Element = function(config){
4020     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4021 };
4022
4023 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4024     
4025     tag: 'div',
4026     cls: '',
4027     html: '',
4028      
4029     
4030     getAutoCreate : function(){
4031         
4032         var cfg = {
4033             tag: this.tag,
4034             cls: this.cls,
4035             html: this.html
4036         }
4037         
4038         
4039         
4040         return cfg;
4041     }
4042    
4043 });
4044
4045  
4046
4047  /*
4048  * - LGPL
4049  *
4050  * pagination
4051  * 
4052  */
4053
4054 /**
4055  * @class Roo.bootstrap.Pagination
4056  * @extends Roo.bootstrap.Component
4057  * Bootstrap Pagination class
4058  * @cfg {String} size xs | sm | md | lg
4059  * @cfg {Boolean} inverse false | true
4060  * 
4061  * @constructor
4062  * Create a new Pagination
4063  * @param {Object} config The config object
4064  */
4065
4066 Roo.bootstrap.Pagination = function(config){
4067     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4068 };
4069
4070 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4071     
4072     cls: false,
4073     size: false,
4074     inverse: false,
4075     
4076     getAutoCreate : function(){
4077         var cfg = {
4078             tag: 'ul',
4079                 cls: 'pagination'
4080         };
4081         if (this.inverse) {
4082             cfg.cls += ' inverse';
4083         }
4084         if (this.html) {
4085             cfg.html=this.html;
4086         }
4087         if (this.cls) {
4088             cfg.cls += " " + this.cls;
4089         }
4090         return cfg;
4091     }
4092    
4093 });
4094
4095  
4096
4097  /*
4098  * - LGPL
4099  *
4100  * Pagination item
4101  * 
4102  */
4103
4104
4105 /**
4106  * @class Roo.bootstrap.PaginationItem
4107  * @extends Roo.bootstrap.Component
4108  * Bootstrap PaginationItem class
4109  * @cfg {String} html text
4110  * @cfg {String} href the link
4111  * @cfg {Boolean} preventDefault (true | false) default true
4112  * @cfg {Boolean} active (true | false) default false
4113  * 
4114  * 
4115  * @constructor
4116  * Create a new PaginationItem
4117  * @param {Object} config The config object
4118  */
4119
4120
4121 Roo.bootstrap.PaginationItem = function(config){
4122     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4123     this.addEvents({
4124         // raw events
4125         /**
4126          * @event click
4127          * The raw click event for the entire grid.
4128          * @param {Roo.EventObject} e
4129          */
4130         "click" : true
4131     });
4132 };
4133
4134 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4135     
4136     href : false,
4137     html : false,
4138     preventDefault: true,
4139     active : false,
4140     cls : false,
4141     
4142     getAutoCreate : function(){
4143         var cfg= {
4144             tag: 'li',
4145             cn: [
4146                 {
4147                     tag : 'a',
4148                     href : this.href ? this.href : '#',
4149                     html : this.html ? this.html : ''
4150                 }
4151             ]
4152         };
4153         
4154         if(this.cls){
4155             cfg.cls = this.cls;
4156         }
4157         
4158         if(this.active){
4159             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4160         }
4161         
4162         return cfg;
4163     },
4164     
4165     initEvents: function() {
4166         
4167         this.el.on('click', this.onClick, this);
4168         
4169     },
4170     onClick : function(e)
4171     {
4172         Roo.log('PaginationItem on click ');
4173         if(this.preventDefault){
4174             e.preventDefault();
4175         }
4176         
4177         this.fireEvent('click', this, e);
4178     }
4179    
4180 });
4181
4182  
4183
4184  /*
4185  * - LGPL
4186  *
4187  * slider
4188  * 
4189  */
4190
4191
4192 /**
4193  * @class Roo.bootstrap.Slider
4194  * @extends Roo.bootstrap.Component
4195  * Bootstrap Slider class
4196  *    
4197  * @constructor
4198  * Create a new Slider
4199  * @param {Object} config The config object
4200  */
4201
4202 Roo.bootstrap.Slider = function(config){
4203     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4204 };
4205
4206 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4207     
4208     getAutoCreate : function(){
4209         
4210         var cfg = {
4211             tag: 'div',
4212             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4213             cn: [
4214                 {
4215                     tag: 'a',
4216                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4217                 }
4218             ]
4219         }
4220         
4221         return cfg;
4222     }
4223    
4224 });
4225
4226  /*
4227  * Based on:
4228  * Ext JS Library 1.1.1
4229  * Copyright(c) 2006-2007, Ext JS, LLC.
4230  *
4231  * Originally Released Under LGPL - original licence link has changed is not relivant.
4232  *
4233  * Fork - LGPL
4234  * <script type="text/javascript">
4235  */
4236  
4237
4238 /**
4239  * @class Roo.grid.ColumnModel
4240  * @extends Roo.util.Observable
4241  * This is the default implementation of a ColumnModel used by the Grid. It defines
4242  * the columns in the grid.
4243  * <br>Usage:<br>
4244  <pre><code>
4245  var colModel = new Roo.grid.ColumnModel([
4246         {header: "Ticker", width: 60, sortable: true, locked: true},
4247         {header: "Company Name", width: 150, sortable: true},
4248         {header: "Market Cap.", width: 100, sortable: true},
4249         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4250         {header: "Employees", width: 100, sortable: true, resizable: false}
4251  ]);
4252  </code></pre>
4253  * <p>
4254  
4255  * The config options listed for this class are options which may appear in each
4256  * individual column definition.
4257  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4258  * @constructor
4259  * @param {Object} config An Array of column config objects. See this class's
4260  * config objects for details.
4261 */
4262 Roo.grid.ColumnModel = function(config){
4263         /**
4264      * The config passed into the constructor
4265      */
4266     this.config = config;
4267     this.lookup = {};
4268
4269     // if no id, create one
4270     // if the column does not have a dataIndex mapping,
4271     // map it to the order it is in the config
4272     for(var i = 0, len = config.length; i < len; i++){
4273         var c = config[i];
4274         if(typeof c.dataIndex == "undefined"){
4275             c.dataIndex = i;
4276         }
4277         if(typeof c.renderer == "string"){
4278             c.renderer = Roo.util.Format[c.renderer];
4279         }
4280         if(typeof c.id == "undefined"){
4281             c.id = Roo.id();
4282         }
4283         if(c.editor && c.editor.xtype){
4284             c.editor  = Roo.factory(c.editor, Roo.grid);
4285         }
4286         if(c.editor && c.editor.isFormField){
4287             c.editor = new Roo.grid.GridEditor(c.editor);
4288         }
4289         this.lookup[c.id] = c;
4290     }
4291
4292     /**
4293      * The width of columns which have no width specified (defaults to 100)
4294      * @type Number
4295      */
4296     this.defaultWidth = 100;
4297
4298     /**
4299      * Default sortable of columns which have no sortable specified (defaults to false)
4300      * @type Boolean
4301      */
4302     this.defaultSortable = false;
4303
4304     this.addEvents({
4305         /**
4306              * @event widthchange
4307              * Fires when the width of a column changes.
4308              * @param {ColumnModel} this
4309              * @param {Number} columnIndex The column index
4310              * @param {Number} newWidth The new width
4311              */
4312             "widthchange": true,
4313         /**
4314              * @event headerchange
4315              * Fires when the text of a header changes.
4316              * @param {ColumnModel} this
4317              * @param {Number} columnIndex The column index
4318              * @param {Number} newText The new header text
4319              */
4320             "headerchange": true,
4321         /**
4322              * @event hiddenchange
4323              * Fires when a column is hidden or "unhidden".
4324              * @param {ColumnModel} this
4325              * @param {Number} columnIndex The column index
4326              * @param {Boolean} hidden true if hidden, false otherwise
4327              */
4328             "hiddenchange": true,
4329             /**
4330          * @event columnmoved
4331          * Fires when a column is moved.
4332          * @param {ColumnModel} this
4333          * @param {Number} oldIndex
4334          * @param {Number} newIndex
4335          */
4336         "columnmoved" : true,
4337         /**
4338          * @event columlockchange
4339          * Fires when a column's locked state is changed
4340          * @param {ColumnModel} this
4341          * @param {Number} colIndex
4342          * @param {Boolean} locked true if locked
4343          */
4344         "columnlockchange" : true
4345     });
4346     Roo.grid.ColumnModel.superclass.constructor.call(this);
4347 };
4348 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4349     /**
4350      * @cfg {String} header The header text to display in the Grid view.
4351      */
4352     /**
4353      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4354      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4355      * specified, the column's index is used as an index into the Record's data Array.
4356      */
4357     /**
4358      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4359      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4360      */
4361     /**
4362      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4363      * Defaults to the value of the {@link #defaultSortable} property.
4364      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4365      */
4366     /**
4367      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4368      */
4369     /**
4370      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4371      */
4372     /**
4373      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4374      */
4375     /**
4376      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4377      */
4378     /**
4379      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4380      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4381      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4382      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4383      */
4384        /**
4385      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4386      */
4387     /**
4388      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4389      */
4390
4391     /**
4392      * Returns the id of the column at the specified index.
4393      * @param {Number} index The column index
4394      * @return {String} the id
4395      */
4396     getColumnId : function(index){
4397         return this.config[index].id;
4398     },
4399
4400     /**
4401      * Returns the column for a specified id.
4402      * @param {String} id The column id
4403      * @return {Object} the column
4404      */
4405     getColumnById : function(id){
4406         return this.lookup[id];
4407     },
4408
4409     
4410     /**
4411      * Returns the column for a specified dataIndex.
4412      * @param {String} dataIndex The column dataIndex
4413      * @return {Object|Boolean} the column or false if not found
4414      */
4415     getColumnByDataIndex: function(dataIndex){
4416         var index = this.findColumnIndex(dataIndex);
4417         return index > -1 ? this.config[index] : false;
4418     },
4419     
4420     /**
4421      * Returns the index for a specified column id.
4422      * @param {String} id The column id
4423      * @return {Number} the index, or -1 if not found
4424      */
4425     getIndexById : function(id){
4426         for(var i = 0, len = this.config.length; i < len; i++){
4427             if(this.config[i].id == id){
4428                 return i;
4429             }
4430         }
4431         return -1;
4432     },
4433     
4434     /**
4435      * Returns the index for a specified column dataIndex.
4436      * @param {String} dataIndex The column dataIndex
4437      * @return {Number} the index, or -1 if not found
4438      */
4439     
4440     findColumnIndex : function(dataIndex){
4441         for(var i = 0, len = this.config.length; i < len; i++){
4442             if(this.config[i].dataIndex == dataIndex){
4443                 return i;
4444             }
4445         }
4446         return -1;
4447     },
4448     
4449     
4450     moveColumn : function(oldIndex, newIndex){
4451         var c = this.config[oldIndex];
4452         this.config.splice(oldIndex, 1);
4453         this.config.splice(newIndex, 0, c);
4454         this.dataMap = null;
4455         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4456     },
4457
4458     isLocked : function(colIndex){
4459         return this.config[colIndex].locked === true;
4460     },
4461
4462     setLocked : function(colIndex, value, suppressEvent){
4463         if(this.isLocked(colIndex) == value){
4464             return;
4465         }
4466         this.config[colIndex].locked = value;
4467         if(!suppressEvent){
4468             this.fireEvent("columnlockchange", this, colIndex, value);
4469         }
4470     },
4471
4472     getTotalLockedWidth : function(){
4473         var totalWidth = 0;
4474         for(var i = 0; i < this.config.length; i++){
4475             if(this.isLocked(i) && !this.isHidden(i)){
4476                 this.totalWidth += this.getColumnWidth(i);
4477             }
4478         }
4479         return totalWidth;
4480     },
4481
4482     getLockedCount : function(){
4483         for(var i = 0, len = this.config.length; i < len; i++){
4484             if(!this.isLocked(i)){
4485                 return i;
4486             }
4487         }
4488     },
4489
4490     /**
4491      * Returns the number of columns.
4492      * @return {Number}
4493      */
4494     getColumnCount : function(visibleOnly){
4495         if(visibleOnly === true){
4496             var c = 0;
4497             for(var i = 0, len = this.config.length; i < len; i++){
4498                 if(!this.isHidden(i)){
4499                     c++;
4500                 }
4501             }
4502             return c;
4503         }
4504         return this.config.length;
4505     },
4506
4507     /**
4508      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4509      * @param {Function} fn
4510      * @param {Object} scope (optional)
4511      * @return {Array} result
4512      */
4513     getColumnsBy : function(fn, scope){
4514         var r = [];
4515         for(var i = 0, len = this.config.length; i < len; i++){
4516             var c = this.config[i];
4517             if(fn.call(scope||this, c, i) === true){
4518                 r[r.length] = c;
4519             }
4520         }
4521         return r;
4522     },
4523
4524     /**
4525      * Returns true if the specified column is sortable.
4526      * @param {Number} col The column index
4527      * @return {Boolean}
4528      */
4529     isSortable : function(col){
4530         if(typeof this.config[col].sortable == "undefined"){
4531             return this.defaultSortable;
4532         }
4533         return this.config[col].sortable;
4534     },
4535
4536     /**
4537      * Returns the rendering (formatting) function defined for the column.
4538      * @param {Number} col The column index.
4539      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4540      */
4541     getRenderer : function(col){
4542         if(!this.config[col].renderer){
4543             return Roo.grid.ColumnModel.defaultRenderer;
4544         }
4545         return this.config[col].renderer;
4546     },
4547
4548     /**
4549      * Sets the rendering (formatting) function for a column.
4550      * @param {Number} col The column index
4551      * @param {Function} fn The function to use to process the cell's raw data
4552      * to return HTML markup for the grid view. The render function is called with
4553      * the following parameters:<ul>
4554      * <li>Data value.</li>
4555      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4556      * <li>css A CSS style string to apply to the table cell.</li>
4557      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4558      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4559      * <li>Row index</li>
4560      * <li>Column index</li>
4561      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4562      */
4563     setRenderer : function(col, fn){
4564         this.config[col].renderer = fn;
4565     },
4566
4567     /**
4568      * Returns the width for the specified column.
4569      * @param {Number} col The column index
4570      * @return {Number}
4571      */
4572     getColumnWidth : function(col){
4573         return this.config[col].width * 1 || this.defaultWidth;
4574     },
4575
4576     /**
4577      * Sets the width for a column.
4578      * @param {Number} col The column index
4579      * @param {Number} width The new width
4580      */
4581     setColumnWidth : function(col, width, suppressEvent){
4582         this.config[col].width = width;
4583         this.totalWidth = null;
4584         if(!suppressEvent){
4585              this.fireEvent("widthchange", this, col, width);
4586         }
4587     },
4588
4589     /**
4590      * Returns the total width of all columns.
4591      * @param {Boolean} includeHidden True to include hidden column widths
4592      * @return {Number}
4593      */
4594     getTotalWidth : function(includeHidden){
4595         if(!this.totalWidth){
4596             this.totalWidth = 0;
4597             for(var i = 0, len = this.config.length; i < len; i++){
4598                 if(includeHidden || !this.isHidden(i)){
4599                     this.totalWidth += this.getColumnWidth(i);
4600                 }
4601             }
4602         }
4603         return this.totalWidth;
4604     },
4605
4606     /**
4607      * Returns the header for the specified column.
4608      * @param {Number} col The column index
4609      * @return {String}
4610      */
4611     getColumnHeader : function(col){
4612         return this.config[col].header;
4613     },
4614
4615     /**
4616      * Sets the header for a column.
4617      * @param {Number} col The column index
4618      * @param {String} header The new header
4619      */
4620     setColumnHeader : function(col, header){
4621         this.config[col].header = header;
4622         this.fireEvent("headerchange", this, col, header);
4623     },
4624
4625     /**
4626      * Returns the tooltip for the specified column.
4627      * @param {Number} col The column index
4628      * @return {String}
4629      */
4630     getColumnTooltip : function(col){
4631             return this.config[col].tooltip;
4632     },
4633     /**
4634      * Sets the tooltip for a column.
4635      * @param {Number} col The column index
4636      * @param {String} tooltip The new tooltip
4637      */
4638     setColumnTooltip : function(col, tooltip){
4639             this.config[col].tooltip = tooltip;
4640     },
4641
4642     /**
4643      * Returns the dataIndex for the specified column.
4644      * @param {Number} col The column index
4645      * @return {Number}
4646      */
4647     getDataIndex : function(col){
4648         return this.config[col].dataIndex;
4649     },
4650
4651     /**
4652      * Sets the dataIndex for a column.
4653      * @param {Number} col The column index
4654      * @param {Number} dataIndex The new dataIndex
4655      */
4656     setDataIndex : function(col, dataIndex){
4657         this.config[col].dataIndex = dataIndex;
4658     },
4659
4660     
4661     
4662     /**
4663      * Returns true if the cell is editable.
4664      * @param {Number} colIndex The column index
4665      * @param {Number} rowIndex The row index
4666      * @return {Boolean}
4667      */
4668     isCellEditable : function(colIndex, rowIndex){
4669         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4670     },
4671
4672     /**
4673      * Returns the editor defined for the cell/column.
4674      * return false or null to disable editing.
4675      * @param {Number} colIndex The column index
4676      * @param {Number} rowIndex The row index
4677      * @return {Object}
4678      */
4679     getCellEditor : function(colIndex, rowIndex){
4680         return this.config[colIndex].editor;
4681     },
4682
4683     /**
4684      * Sets if a column is editable.
4685      * @param {Number} col The column index
4686      * @param {Boolean} editable True if the column is editable
4687      */
4688     setEditable : function(col, editable){
4689         this.config[col].editable = editable;
4690     },
4691
4692
4693     /**
4694      * Returns true if the column is hidden.
4695      * @param {Number} colIndex The column index
4696      * @return {Boolean}
4697      */
4698     isHidden : function(colIndex){
4699         return this.config[colIndex].hidden;
4700     },
4701
4702
4703     /**
4704      * Returns true if the column width cannot be changed
4705      */
4706     isFixed : function(colIndex){
4707         return this.config[colIndex].fixed;
4708     },
4709
4710     /**
4711      * Returns true if the column can be resized
4712      * @return {Boolean}
4713      */
4714     isResizable : function(colIndex){
4715         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4716     },
4717     /**
4718      * Sets if a column is hidden.
4719      * @param {Number} colIndex The column index
4720      * @param {Boolean} hidden True if the column is hidden
4721      */
4722     setHidden : function(colIndex, hidden){
4723         this.config[colIndex].hidden = hidden;
4724         this.totalWidth = null;
4725         this.fireEvent("hiddenchange", this, colIndex, hidden);
4726     },
4727
4728     /**
4729      * Sets the editor for a column.
4730      * @param {Number} col The column index
4731      * @param {Object} editor The editor object
4732      */
4733     setEditor : function(col, editor){
4734         this.config[col].editor = editor;
4735     }
4736 });
4737
4738 Roo.grid.ColumnModel.defaultRenderer = function(value){
4739         if(typeof value == "string" && value.length < 1){
4740             return "&#160;";
4741         }
4742         return value;
4743 };
4744
4745 // Alias for backwards compatibility
4746 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4747 /*
4748  * Based on:
4749  * Ext JS Library 1.1.1
4750  * Copyright(c) 2006-2007, Ext JS, LLC.
4751  *
4752  * Originally Released Under LGPL - original licence link has changed is not relivant.
4753  *
4754  * Fork - LGPL
4755  * <script type="text/javascript">
4756  */
4757  
4758 /**
4759  * @class Roo.LoadMask
4760  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4761  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4762  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4763  * element's UpdateManager load indicator and will be destroyed after the initial load.
4764  * @constructor
4765  * Create a new LoadMask
4766  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4767  * @param {Object} config The config object
4768  */
4769 Roo.LoadMask = function(el, config){
4770     this.el = Roo.get(el);
4771     Roo.apply(this, config);
4772     if(this.store){
4773         this.store.on('beforeload', this.onBeforeLoad, this);
4774         this.store.on('load', this.onLoad, this);
4775         this.store.on('loadexception', this.onLoadException, this);
4776         this.removeMask = false;
4777     }else{
4778         var um = this.el.getUpdateManager();
4779         um.showLoadIndicator = false; // disable the default indicator
4780         um.on('beforeupdate', this.onBeforeLoad, this);
4781         um.on('update', this.onLoad, this);
4782         um.on('failure', this.onLoad, this);
4783         this.removeMask = true;
4784     }
4785 };
4786
4787 Roo.LoadMask.prototype = {
4788     /**
4789      * @cfg {Boolean} removeMask
4790      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4791      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4792      */
4793     /**
4794      * @cfg {String} msg
4795      * The text to display in a centered loading message box (defaults to 'Loading...')
4796      */
4797     msg : 'Loading...',
4798     /**
4799      * @cfg {String} msgCls
4800      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4801      */
4802     msgCls : 'x-mask-loading',
4803
4804     /**
4805      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4806      * @type Boolean
4807      */
4808     disabled: false,
4809
4810     /**
4811      * Disables the mask to prevent it from being displayed
4812      */
4813     disable : function(){
4814        this.disabled = true;
4815     },
4816
4817     /**
4818      * Enables the mask so that it can be displayed
4819      */
4820     enable : function(){
4821         this.disabled = false;
4822     },
4823     
4824     onLoadException : function()
4825     {
4826         Roo.log(arguments);
4827         
4828         if (typeof(arguments[3]) != 'undefined') {
4829             Roo.MessageBox.alert("Error loading",arguments[3]);
4830         } 
4831         /*
4832         try {
4833             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4834                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4835             }   
4836         } catch(e) {
4837             
4838         }
4839         */
4840     
4841         
4842         
4843         this.el.unmask(this.removeMask);
4844     },
4845     // private
4846     onLoad : function()
4847     {
4848         this.el.unmask(this.removeMask);
4849     },
4850
4851     // private
4852     onBeforeLoad : function(){
4853         if(!this.disabled){
4854             this.el.mask(this.msg, this.msgCls);
4855         }
4856     },
4857
4858     // private
4859     destroy : function(){
4860         if(this.store){
4861             this.store.un('beforeload', this.onBeforeLoad, this);
4862             this.store.un('load', this.onLoad, this);
4863             this.store.un('loadexception', this.onLoadException, this);
4864         }else{
4865             var um = this.el.getUpdateManager();
4866             um.un('beforeupdate', this.onBeforeLoad, this);
4867             um.un('update', this.onLoad, this);
4868             um.un('failure', this.onLoad, this);
4869         }
4870     }
4871 };/*
4872  * - LGPL
4873  *
4874  * table
4875  * 
4876  */
4877
4878 /**
4879  * @class Roo.bootstrap.Table
4880  * @extends Roo.bootstrap.Component
4881  * Bootstrap Table class
4882  * @cfg {String} cls table class
4883  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4884  * @cfg {String} bgcolor Specifies the background color for a table
4885  * @cfg {Number} border Specifies whether the table cells should have borders or not
4886  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4887  * @cfg {Number} cellspacing Specifies the space between cells
4888  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4889  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4890  * @cfg {String} sortable Specifies that the table should be sortable
4891  * @cfg {String} summary Specifies a summary of the content of a table
4892  * @cfg {Number} width Specifies the width of a table
4893  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4894  * 
4895  * @cfg {boolean} striped Should the rows be alternative striped
4896  * @cfg {boolean} bordered Add borders to the table
4897  * @cfg {boolean} hover Add hover highlighting
4898  * @cfg {boolean} condensed Format condensed
4899  * @cfg {boolean} responsive Format condensed
4900  * @cfg {Boolean} loadMask (true|false) default false
4901  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4902  * @cfg {Boolean} thead (true|false) generate thead, default true
4903  * @cfg {Boolean} RowSelection (true|false) default false
4904  * @cfg {Boolean} CellSelection (true|false) default false
4905  *
4906  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
4907  
4908  * 
4909  * @constructor
4910  * Create a new Table
4911  * @param {Object} config The config object
4912  */
4913
4914 Roo.bootstrap.Table = function(config){
4915     Roo.bootstrap.Table.superclass.constructor.call(this, config);
4916     
4917     if (this.sm) {
4918         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4919         this.sm = this.selModel;
4920         this.sm.xmodule = this.xmodule || false;
4921     }
4922     if (this.cm && typeof(this.cm.config) == 'undefined') {
4923         this.colModel = new Roo.grid.ColumnModel(this.cm);
4924         this.cm = this.colModel;
4925         this.cm.xmodule = this.xmodule || false;
4926     }
4927     if (this.store) {
4928         this.store= Roo.factory(this.store, Roo.data);
4929         this.ds = this.store;
4930         this.ds.xmodule = this.xmodule || false;
4931          
4932     }
4933     if (this.footer && this.store) {
4934         this.footer.dataSource = this.ds;
4935         this.footer = Roo.factory(this.footer);
4936     }
4937     
4938     /** @private */
4939     this.addEvents({
4940         /**
4941          * @event cellclick
4942          * Fires when a cell is clicked
4943          * @param {Roo.bootstrap.Table} this
4944          * @param {Roo.Element} el
4945          * @param {Number} rowIndex
4946          * @param {Number} columnIndex
4947          * @param {Roo.EventObject} e
4948          */
4949         "cellclick" : true,
4950         /**
4951          * @event celldblclick
4952          * Fires when a cell is double clicked
4953          * @param {Roo.bootstrap.Table} this
4954          * @param {Roo.Element} el
4955          * @param {Number} rowIndex
4956          * @param {Number} columnIndex
4957          * @param {Roo.EventObject} e
4958          */
4959         "celldblclick" : true,
4960         /**
4961          * @event rowclick
4962          * Fires when a row is clicked
4963          * @param {Roo.bootstrap.Table} this
4964          * @param {Roo.Element} el
4965          * @param {Number} rowIndex
4966          * @param {Roo.EventObject} e
4967          */
4968         "rowclick" : true,
4969         /**
4970          * @event rowdblclick
4971          * Fires when a row is double clicked
4972          * @param {Roo.bootstrap.Table} this
4973          * @param {Roo.Element} el
4974          * @param {Number} rowIndex
4975          * @param {Roo.EventObject} e
4976          */
4977         "rowdblclick" : true,
4978         /**
4979          * @event mouseover
4980          * Fires when a mouseover occur
4981          * @param {Roo.bootstrap.Table} this
4982          * @param {Roo.Element} el
4983          * @param {Number} rowIndex
4984          * @param {Number} columnIndex
4985          * @param {Roo.EventObject} e
4986          */
4987         "mouseover" : true,
4988         /**
4989          * @event mouseout
4990          * Fires when a mouseout occur
4991          * @param {Roo.bootstrap.Table} this
4992          * @param {Roo.Element} el
4993          * @param {Number} rowIndex
4994          * @param {Number} columnIndex
4995          * @param {Roo.EventObject} e
4996          */
4997         "mouseout" : true,
4998         /**
4999          * @event rowclass
5000          * Fires when a row is rendered, so you can change add a style to it.
5001          * @param {Roo.bootstrap.Table} this
5002          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5003          */
5004         'rowclass' : true
5005         
5006     });
5007 };
5008
5009 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5010     
5011     cls: false,
5012     align: false,
5013     bgcolor: false,
5014     border: false,
5015     cellpadding: false,
5016     cellspacing: false,
5017     frame: false,
5018     rules: false,
5019     sortable: false,
5020     summary: false,
5021     width: false,
5022     striped : false,
5023     bordered: false,
5024     hover:  false,
5025     condensed : false,
5026     responsive : false,
5027     sm : false,
5028     cm : false,
5029     store : false,
5030     loadMask : false,
5031     tfoot : true,
5032     thead : true,
5033     RowSelection : false,
5034     CellSelection : false,
5035     layout : false,
5036     
5037     // Roo.Element - the tbody
5038     mainBody: false, 
5039     
5040     getAutoCreate : function(){
5041         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5042         
5043         cfg = {
5044             tag: 'table',
5045             cls : 'table',
5046             cn : []
5047         }
5048             
5049         if (this.striped) {
5050             cfg.cls += ' table-striped';
5051         }
5052         
5053         if (this.hover) {
5054             cfg.cls += ' table-hover';
5055         }
5056         if (this.bordered) {
5057             cfg.cls += ' table-bordered';
5058         }
5059         if (this.condensed) {
5060             cfg.cls += ' table-condensed';
5061         }
5062         if (this.responsive) {
5063             cfg.cls += ' table-responsive';
5064         }
5065         
5066         if (this.cls) {
5067             cfg.cls+=  ' ' +this.cls;
5068         }
5069         
5070         // this lot should be simplifed...
5071         
5072         if (this.align) {
5073             cfg.align=this.align;
5074         }
5075         if (this.bgcolor) {
5076             cfg.bgcolor=this.bgcolor;
5077         }
5078         if (this.border) {
5079             cfg.border=this.border;
5080         }
5081         if (this.cellpadding) {
5082             cfg.cellpadding=this.cellpadding;
5083         }
5084         if (this.cellspacing) {
5085             cfg.cellspacing=this.cellspacing;
5086         }
5087         if (this.frame) {
5088             cfg.frame=this.frame;
5089         }
5090         if (this.rules) {
5091             cfg.rules=this.rules;
5092         }
5093         if (this.sortable) {
5094             cfg.sortable=this.sortable;
5095         }
5096         if (this.summary) {
5097             cfg.summary=this.summary;
5098         }
5099         if (this.width) {
5100             cfg.width=this.width;
5101         }
5102         if (this.layout) {
5103             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5104         }
5105         
5106         if(this.store || this.cm){
5107             if(this.thead){
5108                 cfg.cn.push(this.renderHeader());
5109             }
5110             
5111             cfg.cn.push(this.renderBody());
5112             
5113             if(this.tfoot){
5114                 cfg.cn.push(this.renderFooter());
5115             }
5116             
5117             cfg.cls+=  ' TableGrid';
5118         }
5119         
5120         return { cn : [ cfg ] };
5121     },
5122     
5123     initEvents : function()
5124     {   
5125         if(!this.store || !this.cm){
5126             return;
5127         }
5128         
5129         //Roo.log('initEvents with ds!!!!');
5130         
5131         this.mainBody = this.el.select('tbody', true).first();
5132         
5133         
5134         var _this = this;
5135         
5136         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5137             e.on('click', _this.sort, _this);
5138         });
5139         
5140         this.el.on("click", this.onClick, this);
5141         this.el.on("dblclick", this.onDblClick, this);
5142         
5143         this.parent().el.setStyle('position', 'relative');
5144         if (this.footer) {
5145             this.footer.parentId = this.id;
5146             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5147         }
5148         
5149         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5150         
5151         this.store.on('load', this.onLoad, this);
5152         this.store.on('beforeload', this.onBeforeLoad, this);
5153         this.store.on('update', this.onUpdate, this);
5154         
5155     },
5156     
5157     onMouseover : function(e, el)
5158     {
5159         var cell = Roo.get(el);
5160         
5161         if(!cell){
5162             return;
5163         }
5164         
5165         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5166             cell = cell.findParent('td', false, true);
5167         }
5168         
5169         var row = cell.findParent('tr', false, true);
5170         var cellIndex = cell.dom.cellIndex;
5171         var rowIndex = row.dom.rowIndex - 1; // start from 0
5172         
5173         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5174         
5175     },
5176     
5177     onMouseout : function(e, el)
5178     {
5179         var cell = Roo.get(el);
5180         
5181         if(!cell){
5182             return;
5183         }
5184         
5185         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5186             cell = cell.findParent('td', false, true);
5187         }
5188         
5189         var row = cell.findParent('tr', false, true);
5190         var cellIndex = cell.dom.cellIndex;
5191         var rowIndex = row.dom.rowIndex - 1; // start from 0
5192         
5193         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5194         
5195     },
5196     
5197     onClick : function(e, el)
5198     {
5199         var cell = Roo.get(el);
5200         
5201         if(!cell || (!this.CellSelection && !this.RowSelection)){
5202             return;
5203         }
5204         
5205         
5206         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5207             cell = cell.findParent('td', false, true);
5208         }
5209         
5210         var row = cell.findParent('tr', false, true);
5211         var cellIndex = cell.dom.cellIndex;
5212         var rowIndex = row.dom.rowIndex - 1;
5213         
5214         if(this.CellSelection){
5215             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5216         }
5217         
5218         if(this.RowSelection){
5219             this.fireEvent('rowclick', this, row, rowIndex, e);
5220         }
5221         
5222         
5223     },
5224     
5225     onDblClick : function(e,el)
5226     {
5227         var cell = Roo.get(el);
5228         
5229         if(!cell || (!this.CellSelection && !this.RowSelection)){
5230             return;
5231         }
5232         
5233         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5234             cell = cell.findParent('td', false, true);
5235         }
5236         
5237         var row = cell.findParent('tr', false, true);
5238         var cellIndex = cell.dom.cellIndex;
5239         var rowIndex = row.dom.rowIndex - 1;
5240         
5241         if(this.CellSelection){
5242             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5243         }
5244         
5245         if(this.RowSelection){
5246             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5247         }
5248     },
5249     
5250     sort : function(e,el)
5251     {
5252         var col = Roo.get(el)
5253         
5254         if(!col.hasClass('sortable')){
5255             return;
5256         }
5257         
5258         var sort = col.attr('sort');
5259         var dir = 'ASC';
5260         
5261         if(col.hasClass('glyphicon-arrow-up')){
5262             dir = 'DESC';
5263         }
5264         
5265         this.store.sortInfo = {field : sort, direction : dir};
5266         
5267         if (this.footer) {
5268             Roo.log("calling footer first");
5269             this.footer.onClick('first');
5270         } else {
5271         
5272             this.store.load({ params : { start : 0 } });
5273         }
5274     },
5275     
5276     renderHeader : function()
5277     {
5278         var header = {
5279             tag: 'thead',
5280             cn : []
5281         };
5282         
5283         var cm = this.cm;
5284         
5285         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5286             
5287             var config = cm.config[i];
5288                     
5289             var c = {
5290                 tag: 'th',
5291                 style : '',
5292                 html: cm.getColumnHeader(i)
5293             };
5294             
5295             if(typeof(config.hidden) != 'undefined' && config.hidden){
5296                 c.style += ' display:none;';
5297             }
5298             
5299             if(typeof(config.dataIndex) != 'undefined'){
5300                 c.sort = config.dataIndex;
5301             }
5302             
5303             if(typeof(config.sortable) != 'undefined' && config.sortable){
5304                 c.cls = 'sortable';
5305             }
5306             
5307             if(typeof(config.align) != 'undefined' && config.align.length){
5308                 c.style += ' text-align:' + config.align + ';';
5309             }
5310             
5311             if(typeof(config.width) != 'undefined'){
5312                 c.style += ' width:' + config.width + 'px;';
5313             }
5314             
5315             header.cn.push(c)
5316         }
5317         
5318         return header;
5319     },
5320     
5321     renderBody : function()
5322     {
5323         var body = {
5324             tag: 'tbody',
5325             cn : [
5326                 {
5327                     tag: 'tr',
5328                     cn : [
5329                         {
5330                             tag : 'td',
5331                             colspan :  this.cm.getColumnCount()
5332                         }
5333                     ]
5334                 }
5335             ]
5336         };
5337         
5338         return body;
5339     },
5340     
5341     renderFooter : function()
5342     {
5343         var footer = {
5344             tag: 'tfoot',
5345             cn : [
5346                 {
5347                     tag: 'tr',
5348                     cn : [
5349                         {
5350                             tag : 'td',
5351                             colspan :  this.cm.getColumnCount()
5352                         }
5353                     ]
5354                 }
5355             ]
5356         };
5357         
5358         return footer;
5359     },
5360     
5361     
5362     
5363     onLoad : function()
5364     {
5365         Roo.log('ds onload');
5366         this.clear();
5367         
5368         var _this = this;
5369         var cm = this.cm;
5370         var ds = this.store;
5371         
5372         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5373             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5374             
5375             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5376                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5377             }
5378             
5379             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5380                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5381             }
5382         });
5383         
5384         var tbody =  this.mainBody;
5385               
5386         if(ds.getCount() > 0){
5387             ds.data.each(function(d,rowIndex){
5388                 var row =  this.renderRow(cm, ds, rowIndex);
5389                 
5390                 tbody.createChild(row);
5391                 
5392                 var _this = this;
5393                 
5394                 if(row.cellObjects.length){
5395                     Roo.each(row.cellObjects, function(r){
5396                         _this.renderCellObject(r);
5397                     })
5398                 }
5399                 
5400             }, this);
5401         }
5402         
5403         Roo.each(this.el.select('tbody td', true).elements, function(e){
5404             e.on('mouseover', _this.onMouseover, _this);
5405         });
5406         
5407         Roo.each(this.el.select('tbody td', true).elements, function(e){
5408             e.on('mouseout', _this.onMouseout, _this);
5409         });
5410
5411         //if(this.loadMask){
5412         //    this.maskEl.hide();
5413         //}
5414     },
5415     
5416     
5417     onUpdate : function(ds,record)
5418     {
5419         this.refreshRow(record);
5420     },
5421     onRemove : function(ds, record, index, isUpdate){
5422         if(isUpdate !== true){
5423             this.fireEvent("beforerowremoved", this, index, record);
5424         }
5425         var bt = this.mainBody.dom;
5426         if(bt.rows[index]){
5427             bt.removeChild(bt.rows[index]);
5428         }
5429         
5430         if(isUpdate !== true){
5431             //this.stripeRows(index);
5432             //this.syncRowHeights(index, index);
5433             //this.layout();
5434             this.fireEvent("rowremoved", this, index, record);
5435         }
5436     },
5437     
5438     
5439     refreshRow : function(record){
5440         var ds = this.store, index;
5441         if(typeof record == 'number'){
5442             index = record;
5443             record = ds.getAt(index);
5444         }else{
5445             index = ds.indexOf(record);
5446         }
5447         this.insertRow(ds, index, true);
5448         this.onRemove(ds, record, index+1, true);
5449         //this.syncRowHeights(index, index);
5450         //this.layout();
5451         this.fireEvent("rowupdated", this, index, record);
5452     },
5453     
5454     insertRow : function(dm, rowIndex, isUpdate){
5455         
5456         if(!isUpdate){
5457             this.fireEvent("beforerowsinserted", this, rowIndex);
5458         }
5459             //var s = this.getScrollState();
5460         var row = this.renderRow(this.cm, this.store, rowIndex);
5461         // insert before rowIndex..
5462         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5463         
5464         var _this = this;
5465                 
5466         if(row.cellObjects.length){
5467             Roo.each(row.cellObjects, function(r){
5468                 _this.renderCellObject(r);
5469             })
5470         }
5471             
5472         if(!isUpdate){
5473             this.fireEvent("rowsinserted", this, rowIndex);
5474             //this.syncRowHeights(firstRow, lastRow);
5475             //this.stripeRows(firstRow);
5476             //this.layout();
5477         }
5478         
5479     },
5480     
5481     
5482     getRowDom : function(rowIndex)
5483     {
5484         // not sure if I need to check this.. but let's do it anyway..
5485         return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
5486                 this.mainBody.dom.rows[rowIndex] : false
5487     },
5488     // returns the object tree for a tr..
5489   
5490     
5491     renderRow : function(cm, ds, rowIndex) {
5492         
5493         var d = ds.getAt(rowIndex);
5494         
5495         var row = {
5496             tag : 'tr',
5497             cn : []
5498         };
5499             
5500         var cellObjects = [];
5501         
5502         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5503             var config = cm.config[i];
5504             
5505             var renderer = cm.getRenderer(i);
5506             var value = '';
5507             var id = false;
5508             
5509             if(typeof(renderer) !== 'undefined'){
5510                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5511             }
5512             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5513             // and are rendered into the cells after the row is rendered - using the id for the element.
5514             
5515             if(typeof(value) === 'object'){
5516                 id = Roo.id();
5517                 cellObjects.push({
5518                     container : id,
5519                     cfg : value 
5520                 })
5521             }
5522             
5523             var rowcfg = {
5524                 record: d,
5525                 rowIndex : rowIndex,
5526                 colIndex : i,
5527                 rowClass : ''
5528             }
5529
5530             this.fireEvent('rowclass', this, rowcfg);
5531             
5532             var td = {
5533                 tag: 'td',
5534                 cls : rowcfg.rowClass,
5535                 style: '',
5536                 html: (typeof(value) === 'object') ? '' : value
5537             };
5538             
5539             if (id) {
5540                 td.id = id;
5541             }
5542             
5543             if(typeof(config.hidden) != 'undefined' && config.hidden){
5544                 td.style += ' display:none;';
5545             }
5546             
5547             if(typeof(config.align) != 'undefined' && config.align.length){
5548                 td.style += ' text-align:' + config.align + ';';
5549             }
5550             
5551             if(typeof(config.width) != 'undefined'){
5552                 td.style += ' width:' +  config.width + 'px;';
5553             }
5554              
5555             row.cn.push(td);
5556            
5557         }
5558         
5559         row.cellObjects = cellObjects;
5560         
5561         return row;
5562           
5563     },
5564     
5565     
5566     
5567     onBeforeLoad : function()
5568     {
5569         //Roo.log('ds onBeforeLoad');
5570         
5571         //this.clear();
5572         
5573         //if(this.loadMask){
5574         //    this.maskEl.show();
5575         //}
5576     },
5577     
5578     clear : function()
5579     {
5580         this.el.select('tbody', true).first().dom.innerHTML = '';
5581     },
5582     
5583     getSelectionModel : function(){
5584         if(!this.selModel){
5585             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5586         }
5587         return this.selModel;
5588     },
5589     /*
5590      * Render the Roo.bootstrap object from renderder
5591      */
5592     renderCellObject : function(r)
5593     {
5594         var _this = this;
5595         
5596         var t = r.cfg.render(r.container);
5597         
5598         if(r.cfg.cn){
5599             Roo.each(r.cfg.cn, function(c){
5600                 var child = {
5601                     container: t.getChildContainer(),
5602                     cfg: c
5603                 }
5604                 _this.renderCellObject(child);
5605             })
5606         }
5607     }
5608    
5609 });
5610
5611  
5612
5613  /*
5614  * - LGPL
5615  *
5616  * table cell
5617  * 
5618  */
5619
5620 /**
5621  * @class Roo.bootstrap.TableCell
5622  * @extends Roo.bootstrap.Component
5623  * Bootstrap TableCell class
5624  * @cfg {String} html cell contain text
5625  * @cfg {String} cls cell class
5626  * @cfg {String} tag cell tag (td|th) default td
5627  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5628  * @cfg {String} align Aligns the content in a cell
5629  * @cfg {String} axis Categorizes cells
5630  * @cfg {String} bgcolor Specifies the background color of a cell
5631  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5632  * @cfg {Number} colspan Specifies the number of columns a cell should span
5633  * @cfg {String} headers Specifies one or more header cells a cell is related to
5634  * @cfg {Number} height Sets the height of a cell
5635  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5636  * @cfg {Number} rowspan Sets the number of rows a cell should span
5637  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5638  * @cfg {String} valign Vertical aligns the content in a cell
5639  * @cfg {Number} width Specifies the width of a cell
5640  * 
5641  * @constructor
5642  * Create a new TableCell
5643  * @param {Object} config The config object
5644  */
5645
5646 Roo.bootstrap.TableCell = function(config){
5647     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5648 };
5649
5650 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5651     
5652     html: false,
5653     cls: false,
5654     tag: false,
5655     abbr: false,
5656     align: false,
5657     axis: false,
5658     bgcolor: false,
5659     charoff: false,
5660     colspan: false,
5661     headers: false,
5662     height: false,
5663     nowrap: false,
5664     rowspan: false,
5665     scope: false,
5666     valign: false,
5667     width: false,
5668     
5669     
5670     getAutoCreate : function(){
5671         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5672         
5673         cfg = {
5674             tag: 'td'
5675         }
5676         
5677         if(this.tag){
5678             cfg.tag = this.tag;
5679         }
5680         
5681         if (this.html) {
5682             cfg.html=this.html
5683         }
5684         if (this.cls) {
5685             cfg.cls=this.cls
5686         }
5687         if (this.abbr) {
5688             cfg.abbr=this.abbr
5689         }
5690         if (this.align) {
5691             cfg.align=this.align
5692         }
5693         if (this.axis) {
5694             cfg.axis=this.axis
5695         }
5696         if (this.bgcolor) {
5697             cfg.bgcolor=this.bgcolor
5698         }
5699         if (this.charoff) {
5700             cfg.charoff=this.charoff
5701         }
5702         if (this.colspan) {
5703             cfg.colspan=this.colspan
5704         }
5705         if (this.headers) {
5706             cfg.headers=this.headers
5707         }
5708         if (this.height) {
5709             cfg.height=this.height
5710         }
5711         if (this.nowrap) {
5712             cfg.nowrap=this.nowrap
5713         }
5714         if (this.rowspan) {
5715             cfg.rowspan=this.rowspan
5716         }
5717         if (this.scope) {
5718             cfg.scope=this.scope
5719         }
5720         if (this.valign) {
5721             cfg.valign=this.valign
5722         }
5723         if (this.width) {
5724             cfg.width=this.width
5725         }
5726         
5727         
5728         return cfg;
5729     }
5730    
5731 });
5732
5733  
5734
5735  /*
5736  * - LGPL
5737  *
5738  * table row
5739  * 
5740  */
5741
5742 /**
5743  * @class Roo.bootstrap.TableRow
5744  * @extends Roo.bootstrap.Component
5745  * Bootstrap TableRow class
5746  * @cfg {String} cls row class
5747  * @cfg {String} align Aligns the content in a table row
5748  * @cfg {String} bgcolor Specifies a background color for a table row
5749  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5750  * @cfg {String} valign Vertical aligns the content in a table row
5751  * 
5752  * @constructor
5753  * Create a new TableRow
5754  * @param {Object} config The config object
5755  */
5756
5757 Roo.bootstrap.TableRow = function(config){
5758     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5759 };
5760
5761 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5762     
5763     cls: false,
5764     align: false,
5765     bgcolor: false,
5766     charoff: false,
5767     valign: false,
5768     
5769     getAutoCreate : function(){
5770         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5771         
5772         cfg = {
5773             tag: 'tr'
5774         }
5775             
5776         if(this.cls){
5777             cfg.cls = this.cls;
5778         }
5779         if(this.align){
5780             cfg.align = this.align;
5781         }
5782         if(this.bgcolor){
5783             cfg.bgcolor = this.bgcolor;
5784         }
5785         if(this.charoff){
5786             cfg.charoff = this.charoff;
5787         }
5788         if(this.valign){
5789             cfg.valign = this.valign;
5790         }
5791         
5792         return cfg;
5793     }
5794    
5795 });
5796
5797  
5798
5799  /*
5800  * - LGPL
5801  *
5802  * table body
5803  * 
5804  */
5805
5806 /**
5807  * @class Roo.bootstrap.TableBody
5808  * @extends Roo.bootstrap.Component
5809  * Bootstrap TableBody class
5810  * @cfg {String} cls element class
5811  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5812  * @cfg {String} align Aligns the content inside the element
5813  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5814  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5815  * 
5816  * @constructor
5817  * Create a new TableBody
5818  * @param {Object} config The config object
5819  */
5820
5821 Roo.bootstrap.TableBody = function(config){
5822     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5823 };
5824
5825 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
5826     
5827     cls: false,
5828     tag: false,
5829     align: false,
5830     charoff: false,
5831     valign: false,
5832     
5833     getAutoCreate : function(){
5834         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5835         
5836         cfg = {
5837             tag: 'tbody'
5838         }
5839             
5840         if (this.cls) {
5841             cfg.cls=this.cls
5842         }
5843         if(this.tag){
5844             cfg.tag = this.tag;
5845         }
5846         
5847         if(this.align){
5848             cfg.align = this.align;
5849         }
5850         if(this.charoff){
5851             cfg.charoff = this.charoff;
5852         }
5853         if(this.valign){
5854             cfg.valign = this.valign;
5855         }
5856         
5857         return cfg;
5858     }
5859     
5860     
5861 //    initEvents : function()
5862 //    {
5863 //        
5864 //        if(!this.store){
5865 //            return;
5866 //        }
5867 //        
5868 //        this.store = Roo.factory(this.store, Roo.data);
5869 //        this.store.on('load', this.onLoad, this);
5870 //        
5871 //        this.store.load();
5872 //        
5873 //    },
5874 //    
5875 //    onLoad: function () 
5876 //    {   
5877 //        this.fireEvent('load', this);
5878 //    }
5879 //    
5880 //   
5881 });
5882
5883  
5884
5885  /*
5886  * Based on:
5887  * Ext JS Library 1.1.1
5888  * Copyright(c) 2006-2007, Ext JS, LLC.
5889  *
5890  * Originally Released Under LGPL - original licence link has changed is not relivant.
5891  *
5892  * Fork - LGPL
5893  * <script type="text/javascript">
5894  */
5895
5896 // as we use this in bootstrap.
5897 Roo.namespace('Roo.form');
5898  /**
5899  * @class Roo.form.Action
5900  * Internal Class used to handle form actions
5901  * @constructor
5902  * @param {Roo.form.BasicForm} el The form element or its id
5903  * @param {Object} config Configuration options
5904  */
5905
5906  
5907  
5908 // define the action interface
5909 Roo.form.Action = function(form, options){
5910     this.form = form;
5911     this.options = options || {};
5912 };
5913 /**
5914  * Client Validation Failed
5915  * @const 
5916  */
5917 Roo.form.Action.CLIENT_INVALID = 'client';
5918 /**
5919  * Server Validation Failed
5920  * @const 
5921  */
5922 Roo.form.Action.SERVER_INVALID = 'server';
5923  /**
5924  * Connect to Server Failed
5925  * @const 
5926  */
5927 Roo.form.Action.CONNECT_FAILURE = 'connect';
5928 /**
5929  * Reading Data from Server Failed
5930  * @const 
5931  */
5932 Roo.form.Action.LOAD_FAILURE = 'load';
5933
5934 Roo.form.Action.prototype = {
5935     type : 'default',
5936     failureType : undefined,
5937     response : undefined,
5938     result : undefined,
5939
5940     // interface method
5941     run : function(options){
5942
5943     },
5944
5945     // interface method
5946     success : function(response){
5947
5948     },
5949
5950     // interface method
5951     handleResponse : function(response){
5952
5953     },
5954
5955     // default connection failure
5956     failure : function(response){
5957         
5958         this.response = response;
5959         this.failureType = Roo.form.Action.CONNECT_FAILURE;
5960         this.form.afterAction(this, false);
5961     },
5962
5963     processResponse : function(response){
5964         this.response = response;
5965         if(!response.responseText){
5966             return true;
5967         }
5968         this.result = this.handleResponse(response);
5969         return this.result;
5970     },
5971
5972     // utility functions used internally
5973     getUrl : function(appendParams){
5974         var url = this.options.url || this.form.url || this.form.el.dom.action;
5975         if(appendParams){
5976             var p = this.getParams();
5977             if(p){
5978                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5979             }
5980         }
5981         return url;
5982     },
5983
5984     getMethod : function(){
5985         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5986     },
5987
5988     getParams : function(){
5989         var bp = this.form.baseParams;
5990         var p = this.options.params;
5991         if(p){
5992             if(typeof p == "object"){
5993                 p = Roo.urlEncode(Roo.applyIf(p, bp));
5994             }else if(typeof p == 'string' && bp){
5995                 p += '&' + Roo.urlEncode(bp);
5996             }
5997         }else if(bp){
5998             p = Roo.urlEncode(bp);
5999         }
6000         return p;
6001     },
6002
6003     createCallback : function(){
6004         return {
6005             success: this.success,
6006             failure: this.failure,
6007             scope: this,
6008             timeout: (this.form.timeout*1000),
6009             upload: this.form.fileUpload ? this.success : undefined
6010         };
6011     }
6012 };
6013
6014 Roo.form.Action.Submit = function(form, options){
6015     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6016 };
6017
6018 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6019     type : 'submit',
6020
6021     haveProgress : false,
6022     uploadComplete : false,
6023     
6024     // uploadProgress indicator.
6025     uploadProgress : function()
6026     {
6027         if (!this.form.progressUrl) {
6028             return;
6029         }
6030         
6031         if (!this.haveProgress) {
6032             Roo.MessageBox.progress("Uploading", "Uploading");
6033         }
6034         if (this.uploadComplete) {
6035            Roo.MessageBox.hide();
6036            return;
6037         }
6038         
6039         this.haveProgress = true;
6040    
6041         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6042         
6043         var c = new Roo.data.Connection();
6044         c.request({
6045             url : this.form.progressUrl,
6046             params: {
6047                 id : uid
6048             },
6049             method: 'GET',
6050             success : function(req){
6051                //console.log(data);
6052                 var rdata = false;
6053                 var edata;
6054                 try  {
6055                    rdata = Roo.decode(req.responseText)
6056                 } catch (e) {
6057                     Roo.log("Invalid data from server..");
6058                     Roo.log(edata);
6059                     return;
6060                 }
6061                 if (!rdata || !rdata.success) {
6062                     Roo.log(rdata);
6063                     Roo.MessageBox.alert(Roo.encode(rdata));
6064                     return;
6065                 }
6066                 var data = rdata.data;
6067                 
6068                 if (this.uploadComplete) {
6069                    Roo.MessageBox.hide();
6070                    return;
6071                 }
6072                    
6073                 if (data){
6074                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6075                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6076                     );
6077                 }
6078                 this.uploadProgress.defer(2000,this);
6079             },
6080        
6081             failure: function(data) {
6082                 Roo.log('progress url failed ');
6083                 Roo.log(data);
6084             },
6085             scope : this
6086         });
6087            
6088     },
6089     
6090     
6091     run : function()
6092     {
6093         // run get Values on the form, so it syncs any secondary forms.
6094         this.form.getValues();
6095         
6096         var o = this.options;
6097         var method = this.getMethod();
6098         var isPost = method == 'POST';
6099         if(o.clientValidation === false || this.form.isValid()){
6100             
6101             if (this.form.progressUrl) {
6102                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6103                     (new Date() * 1) + '' + Math.random());
6104                     
6105             } 
6106             
6107             
6108             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6109                 form:this.form.el.dom,
6110                 url:this.getUrl(!isPost),
6111                 method: method,
6112                 params:isPost ? this.getParams() : null,
6113                 isUpload: this.form.fileUpload
6114             }));
6115             
6116             this.uploadProgress();
6117
6118         }else if (o.clientValidation !== false){ // client validation failed
6119             this.failureType = Roo.form.Action.CLIENT_INVALID;
6120             this.form.afterAction(this, false);
6121         }
6122     },
6123
6124     success : function(response)
6125     {
6126         this.uploadComplete= true;
6127         if (this.haveProgress) {
6128             Roo.MessageBox.hide();
6129         }
6130         
6131         
6132         var result = this.processResponse(response);
6133         if(result === true || result.success){
6134             this.form.afterAction(this, true);
6135             return;
6136         }
6137         if(result.errors){
6138             this.form.markInvalid(result.errors);
6139             this.failureType = Roo.form.Action.SERVER_INVALID;
6140         }
6141         this.form.afterAction(this, false);
6142     },
6143     failure : function(response)
6144     {
6145         this.uploadComplete= true;
6146         if (this.haveProgress) {
6147             Roo.MessageBox.hide();
6148         }
6149         
6150         this.response = response;
6151         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6152         this.form.afterAction(this, false);
6153     },
6154     
6155     handleResponse : function(response){
6156         if(this.form.errorReader){
6157             var rs = this.form.errorReader.read(response);
6158             var errors = [];
6159             if(rs.records){
6160                 for(var i = 0, len = rs.records.length; i < len; i++) {
6161                     var r = rs.records[i];
6162                     errors[i] = r.data;
6163                 }
6164             }
6165             if(errors.length < 1){
6166                 errors = null;
6167             }
6168             return {
6169                 success : rs.success,
6170                 errors : errors
6171             };
6172         }
6173         var ret = false;
6174         try {
6175             ret = Roo.decode(response.responseText);
6176         } catch (e) {
6177             ret = {
6178                 success: false,
6179                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6180                 errors : []
6181             };
6182         }
6183         return ret;
6184         
6185     }
6186 });
6187
6188
6189 Roo.form.Action.Load = function(form, options){
6190     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6191     this.reader = this.form.reader;
6192 };
6193
6194 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6195     type : 'load',
6196
6197     run : function(){
6198         
6199         Roo.Ajax.request(Roo.apply(
6200                 this.createCallback(), {
6201                     method:this.getMethod(),
6202                     url:this.getUrl(false),
6203                     params:this.getParams()
6204         }));
6205     },
6206
6207     success : function(response){
6208         
6209         var result = this.processResponse(response);
6210         if(result === true || !result.success || !result.data){
6211             this.failureType = Roo.form.Action.LOAD_FAILURE;
6212             this.form.afterAction(this, false);
6213             return;
6214         }
6215         this.form.clearInvalid();
6216         this.form.setValues(result.data);
6217         this.form.afterAction(this, true);
6218     },
6219
6220     handleResponse : function(response){
6221         if(this.form.reader){
6222             var rs = this.form.reader.read(response);
6223             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6224             return {
6225                 success : rs.success,
6226                 data : data
6227             };
6228         }
6229         return Roo.decode(response.responseText);
6230     }
6231 });
6232
6233 Roo.form.Action.ACTION_TYPES = {
6234     'load' : Roo.form.Action.Load,
6235     'submit' : Roo.form.Action.Submit
6236 };/*
6237  * - LGPL
6238  *
6239  * form
6240  * 
6241  */
6242
6243 /**
6244  * @class Roo.bootstrap.Form
6245  * @extends Roo.bootstrap.Component
6246  * Bootstrap Form class
6247  * @cfg {String} method  GET | POST (default POST)
6248  * @cfg {String} labelAlign top | left (default top)
6249  * @cfg {String} align left  | right - for navbars
6250  * @cfg {Boolean} loadMask load mask when submit (default true)
6251
6252  * 
6253  * @constructor
6254  * Create a new Form
6255  * @param {Object} config The config object
6256  */
6257
6258
6259 Roo.bootstrap.Form = function(config){
6260     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6261     this.addEvents({
6262         /**
6263          * @event clientvalidation
6264          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6265          * @param {Form} this
6266          * @param {Boolean} valid true if the form has passed client-side validation
6267          */
6268         clientvalidation: true,
6269         /**
6270          * @event beforeaction
6271          * Fires before any action is performed. Return false to cancel the action.
6272          * @param {Form} this
6273          * @param {Action} action The action to be performed
6274          */
6275         beforeaction: true,
6276         /**
6277          * @event actionfailed
6278          * Fires when an action fails.
6279          * @param {Form} this
6280          * @param {Action} action The action that failed
6281          */
6282         actionfailed : true,
6283         /**
6284          * @event actioncomplete
6285          * Fires when an action is completed.
6286          * @param {Form} this
6287          * @param {Action} action The action that completed
6288          */
6289         actioncomplete : true
6290     });
6291     
6292 };
6293
6294 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6295       
6296      /**
6297      * @cfg {String} method
6298      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6299      */
6300     method : 'POST',
6301     /**
6302      * @cfg {String} url
6303      * The URL to use for form actions if one isn't supplied in the action options.
6304      */
6305     /**
6306      * @cfg {Boolean} fileUpload
6307      * Set to true if this form is a file upload.
6308      */
6309      
6310     /**
6311      * @cfg {Object} baseParams
6312      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6313      */
6314       
6315     /**
6316      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6317      */
6318     timeout: 30,
6319     /**
6320      * @cfg {Sting} align (left|right) for navbar forms
6321      */
6322     align : 'left',
6323
6324     // private
6325     activeAction : null,
6326  
6327     /**
6328      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6329      * element by passing it or its id or mask the form itself by passing in true.
6330      * @type Mixed
6331      */
6332     waitMsgTarget : false,
6333     
6334     loadMask : true,
6335     
6336     getAutoCreate : function(){
6337         
6338         var cfg = {
6339             tag: 'form',
6340             method : this.method || 'POST',
6341             id : this.id || Roo.id(),
6342             cls : ''
6343         }
6344         if (this.parent().xtype.match(/^Nav/)) {
6345             cfg.cls = 'navbar-form navbar-' + this.align;
6346             
6347         }
6348         
6349         if (this.labelAlign == 'left' ) {
6350             cfg.cls += ' form-horizontal';
6351         }
6352         
6353         
6354         return cfg;
6355     },
6356     initEvents : function()
6357     {
6358         this.el.on('submit', this.onSubmit, this);
6359         // this was added as random key presses on the form where triggering form submit.
6360         this.el.on('keypress', function(e) {
6361             if (e.getCharCode() != 13) {
6362                 return true;
6363             }
6364             // we might need to allow it for textareas.. and some other items.
6365             // check e.getTarget().
6366             
6367             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6368                 return true;
6369             }
6370         
6371             Roo.log("keypress blocked");
6372             
6373             e.preventDefault();
6374             return false;
6375         });
6376         
6377     },
6378     // private
6379     onSubmit : function(e){
6380         e.stopEvent();
6381     },
6382     
6383      /**
6384      * Returns true if client-side validation on the form is successful.
6385      * @return Boolean
6386      */
6387     isValid : function(){
6388         var items = this.getItems();
6389         var valid = true;
6390         items.each(function(f){
6391            if(!f.validate()){
6392                valid = false;
6393                
6394            }
6395         });
6396         return valid;
6397     },
6398     /**
6399      * Returns true if any fields in this form have changed since their original load.
6400      * @return Boolean
6401      */
6402     isDirty : function(){
6403         var dirty = false;
6404         var items = this.getItems();
6405         items.each(function(f){
6406            if(f.isDirty()){
6407                dirty = true;
6408                return false;
6409            }
6410            return true;
6411         });
6412         return dirty;
6413     },
6414      /**
6415      * Performs a predefined action (submit or load) or custom actions you define on this form.
6416      * @param {String} actionName The name of the action type
6417      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6418      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6419      * accept other config options):
6420      * <pre>
6421 Property          Type             Description
6422 ----------------  ---------------  ----------------------------------------------------------------------------------
6423 url               String           The url for the action (defaults to the form's url)
6424 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6425 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6426 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6427                                    validate the form on the client (defaults to false)
6428      * </pre>
6429      * @return {BasicForm} this
6430      */
6431     doAction : function(action, options){
6432         if(typeof action == 'string'){
6433             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6434         }
6435         if(this.fireEvent('beforeaction', this, action) !== false){
6436             this.beforeAction(action);
6437             action.run.defer(100, action);
6438         }
6439         return this;
6440     },
6441     
6442     // private
6443     beforeAction : function(action){
6444         var o = action.options;
6445         
6446         if(this.loadMask){
6447             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6448         }
6449         // not really supported yet.. ??
6450         
6451         //if(this.waitMsgTarget === true){
6452         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6453         //}else if(this.waitMsgTarget){
6454         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6455         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6456         //}else {
6457         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6458        // }
6459          
6460     },
6461
6462     // private
6463     afterAction : function(action, success){
6464         this.activeAction = null;
6465         var o = action.options;
6466         
6467         //if(this.waitMsgTarget === true){
6468             this.el.unmask();
6469         //}else if(this.waitMsgTarget){
6470         //    this.waitMsgTarget.unmask();
6471         //}else{
6472         //    Roo.MessageBox.updateProgress(1);
6473         //    Roo.MessageBox.hide();
6474        // }
6475         // 
6476         if(success){
6477             if(o.reset){
6478                 this.reset();
6479             }
6480             Roo.callback(o.success, o.scope, [this, action]);
6481             this.fireEvent('actioncomplete', this, action);
6482             
6483         }else{
6484             
6485             // failure condition..
6486             // we have a scenario where updates need confirming.
6487             // eg. if a locking scenario exists..
6488             // we look for { errors : { needs_confirm : true }} in the response.
6489             if (
6490                 (typeof(action.result) != 'undefined')  &&
6491                 (typeof(action.result.errors) != 'undefined')  &&
6492                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6493            ){
6494                 var _t = this;
6495                 Roo.log("not supported yet");
6496                  /*
6497                 
6498                 Roo.MessageBox.confirm(
6499                     "Change requires confirmation",
6500                     action.result.errorMsg,
6501                     function(r) {
6502                         if (r != 'yes') {
6503                             return;
6504                         }
6505                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6506                     }
6507                     
6508                 );
6509                 */
6510                 
6511                 
6512                 return;
6513             }
6514             
6515             Roo.callback(o.failure, o.scope, [this, action]);
6516             // show an error message if no failed handler is set..
6517             if (!this.hasListener('actionfailed')) {
6518                 Roo.log("need to add dialog support");
6519                 /*
6520                 Roo.MessageBox.alert("Error",
6521                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6522                         action.result.errorMsg :
6523                         "Saving Failed, please check your entries or try again"
6524                 );
6525                 */
6526             }
6527             
6528             this.fireEvent('actionfailed', this, action);
6529         }
6530         
6531     },
6532     /**
6533      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6534      * @param {String} id The value to search for
6535      * @return Field
6536      */
6537     findField : function(id){
6538         var items = this.getItems();
6539         var field = items.get(id);
6540         if(!field){
6541              items.each(function(f){
6542                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6543                     field = f;
6544                     return false;
6545                 }
6546                 return true;
6547             });
6548         }
6549         return field || null;
6550     },
6551      /**
6552      * Mark fields in this form invalid in bulk.
6553      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6554      * @return {BasicForm} this
6555      */
6556     markInvalid : function(errors){
6557         if(errors instanceof Array){
6558             for(var i = 0, len = errors.length; i < len; i++){
6559                 var fieldError = errors[i];
6560                 var f = this.findField(fieldError.id);
6561                 if(f){
6562                     f.markInvalid(fieldError.msg);
6563                 }
6564             }
6565         }else{
6566             var field, id;
6567             for(id in errors){
6568                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6569                     field.markInvalid(errors[id]);
6570                 }
6571             }
6572         }
6573         //Roo.each(this.childForms || [], function (f) {
6574         //    f.markInvalid(errors);
6575         //});
6576         
6577         return this;
6578     },
6579
6580     /**
6581      * Set values for fields in this form in bulk.
6582      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6583      * @return {BasicForm} this
6584      */
6585     setValues : function(values){
6586         if(values instanceof Array){ // array of objects
6587             for(var i = 0, len = values.length; i < len; i++){
6588                 var v = values[i];
6589                 var f = this.findField(v.id);
6590                 if(f){
6591                     f.setValue(v.value);
6592                     if(this.trackResetOnLoad){
6593                         f.originalValue = f.getValue();
6594                     }
6595                 }
6596             }
6597         }else{ // object hash
6598             var field, id;
6599             for(id in values){
6600                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6601                     
6602                     if (field.setFromData && 
6603                         field.valueField && 
6604                         field.displayField &&
6605                         // combos' with local stores can 
6606                         // be queried via setValue()
6607                         // to set their value..
6608                         (field.store && !field.store.isLocal)
6609                         ) {
6610                         // it's a combo
6611                         var sd = { };
6612                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6613                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6614                         field.setFromData(sd);
6615                         
6616                     } else {
6617                         field.setValue(values[id]);
6618                     }
6619                     
6620                     
6621                     if(this.trackResetOnLoad){
6622                         field.originalValue = field.getValue();
6623                     }
6624                 }
6625             }
6626         }
6627          
6628         //Roo.each(this.childForms || [], function (f) {
6629         //    f.setValues(values);
6630         //});
6631                 
6632         return this;
6633     },
6634
6635     /**
6636      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6637      * they are returned as an array.
6638      * @param {Boolean} asString
6639      * @return {Object}
6640      */
6641     getValues : function(asString){
6642         //if (this.childForms) {
6643             // copy values from the child forms
6644         //    Roo.each(this.childForms, function (f) {
6645         //        this.setValues(f.getValues());
6646         //    }, this);
6647         //}
6648         
6649         
6650         
6651         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6652         if(asString === true){
6653             return fs;
6654         }
6655         return Roo.urlDecode(fs);
6656     },
6657     
6658     /**
6659      * Returns the fields in this form as an object with key/value pairs. 
6660      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6661      * @return {Object}
6662      */
6663     getFieldValues : function(with_hidden)
6664     {
6665         var items = this.getItems();
6666         var ret = {};
6667         items.each(function(f){
6668             if (!f.getName()) {
6669                 return;
6670             }
6671             var v = f.getValue();
6672             if (f.inputType =='radio') {
6673                 if (typeof(ret[f.getName()]) == 'undefined') {
6674                     ret[f.getName()] = ''; // empty..
6675                 }
6676                 
6677                 if (!f.el.dom.checked) {
6678                     return;
6679                     
6680                 }
6681                 v = f.el.dom.value;
6682                 
6683             }
6684             
6685             // not sure if this supported any more..
6686             if ((typeof(v) == 'object') && f.getRawValue) {
6687                 v = f.getRawValue() ; // dates..
6688             }
6689             // combo boxes where name != hiddenName...
6690             if (f.name != f.getName()) {
6691                 ret[f.name] = f.getRawValue();
6692             }
6693             ret[f.getName()] = v;
6694         });
6695         
6696         return ret;
6697     },
6698
6699     /**
6700      * Clears all invalid messages in this form.
6701      * @return {BasicForm} this
6702      */
6703     clearInvalid : function(){
6704         var items = this.getItems();
6705         
6706         items.each(function(f){
6707            f.clearInvalid();
6708         });
6709         
6710         
6711         
6712         return this;
6713     },
6714
6715     /**
6716      * Resets this form.
6717      * @return {BasicForm} this
6718      */
6719     reset : function(){
6720         var items = this.getItems();
6721         items.each(function(f){
6722             f.reset();
6723         });
6724         
6725         Roo.each(this.childForms || [], function (f) {
6726             f.reset();
6727         });
6728        
6729         
6730         return this;
6731     },
6732     getItems : function()
6733     {
6734         var r=new Roo.util.MixedCollection(false, function(o){
6735             return o.id || (o.id = Roo.id());
6736         });
6737         var iter = function(el) {
6738             if (el.inputEl) {
6739                 r.add(el);
6740             }
6741             if (!el.items) {
6742                 return;
6743             }
6744             Roo.each(el.items,function(e) {
6745                 iter(e);
6746             });
6747             
6748             
6749         };
6750         iter(this);
6751         return r;
6752         
6753         
6754         
6755         
6756     }
6757     
6758 });
6759
6760  
6761 /*
6762  * Based on:
6763  * Ext JS Library 1.1.1
6764  * Copyright(c) 2006-2007, Ext JS, LLC.
6765  *
6766  * Originally Released Under LGPL - original licence link has changed is not relivant.
6767  *
6768  * Fork - LGPL
6769  * <script type="text/javascript">
6770  */
6771 /**
6772  * @class Roo.form.VTypes
6773  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6774  * @singleton
6775  */
6776 Roo.form.VTypes = function(){
6777     // closure these in so they are only created once.
6778     var alpha = /^[a-zA-Z_]+$/;
6779     var alphanum = /^[a-zA-Z0-9_]+$/;
6780     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6781     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6782
6783     // All these messages and functions are configurable
6784     return {
6785         /**
6786          * The function used to validate email addresses
6787          * @param {String} value The email address
6788          */
6789         'email' : function(v){
6790             return email.test(v);
6791         },
6792         /**
6793          * The error text to display when the email validation function returns false
6794          * @type String
6795          */
6796         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6797         /**
6798          * The keystroke filter mask to be applied on email input
6799          * @type RegExp
6800          */
6801         'emailMask' : /[a-z0-9_\.\-@]/i,
6802
6803         /**
6804          * The function used to validate URLs
6805          * @param {String} value The URL
6806          */
6807         'url' : function(v){
6808             return url.test(v);
6809         },
6810         /**
6811          * The error text to display when the url validation function returns false
6812          * @type String
6813          */
6814         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6815         
6816         /**
6817          * The function used to validate alpha values
6818          * @param {String} value The value
6819          */
6820         'alpha' : function(v){
6821             return alpha.test(v);
6822         },
6823         /**
6824          * The error text to display when the alpha validation function returns false
6825          * @type String
6826          */
6827         'alphaText' : 'This field should only contain letters and _',
6828         /**
6829          * The keystroke filter mask to be applied on alpha input
6830          * @type RegExp
6831          */
6832         'alphaMask' : /[a-z_]/i,
6833
6834         /**
6835          * The function used to validate alphanumeric values
6836          * @param {String} value The value
6837          */
6838         'alphanum' : function(v){
6839             return alphanum.test(v);
6840         },
6841         /**
6842          * The error text to display when the alphanumeric validation function returns false
6843          * @type String
6844          */
6845         'alphanumText' : 'This field should only contain letters, numbers and _',
6846         /**
6847          * The keystroke filter mask to be applied on alphanumeric input
6848          * @type RegExp
6849          */
6850         'alphanumMask' : /[a-z0-9_]/i
6851     };
6852 }();/*
6853  * - LGPL
6854  *
6855  * Input
6856  * 
6857  */
6858
6859 /**
6860  * @class Roo.bootstrap.Input
6861  * @extends Roo.bootstrap.Component
6862  * Bootstrap Input class
6863  * @cfg {Boolean} disabled is it disabled
6864  * @cfg {String} fieldLabel - the label associated
6865  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6866  * @cfg {String} name name of the input
6867  * @cfg {string} fieldLabel - the label associated
6868  * @cfg {string}  inputType - input / file submit ...
6869  * @cfg {string} placeholder - placeholder to put in text.
6870  * @cfg {string}  before - input group add on before
6871  * @cfg {string} after - input group add on after
6872  * @cfg {string} size - (lg|sm) or leave empty..
6873  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6874  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6875  * @cfg {Number} md colspan out of 12 for computer-sized screens
6876  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6877  * @cfg {string} value default value of the input
6878  * @cfg {Number} labelWidth set the width of label (0-12)
6879  * @cfg {String} labelAlign (top|left)
6880  * @cfg {Boolean} readOnly Specifies that the field should be read-only
6881  * @cfg {String} align (left|center|right) Default left
6882  * 
6883  * 
6884  * @constructor
6885  * Create a new Input
6886  * @param {Object} config The config object
6887  */
6888
6889 Roo.bootstrap.Input = function(config){
6890     Roo.bootstrap.Input.superclass.constructor.call(this, config);
6891    
6892         this.addEvents({
6893             /**
6894              * @event focus
6895              * Fires when this field receives input focus.
6896              * @param {Roo.form.Field} this
6897              */
6898             focus : true,
6899             /**
6900              * @event blur
6901              * Fires when this field loses input focus.
6902              * @param {Roo.form.Field} this
6903              */
6904             blur : true,
6905             /**
6906              * @event specialkey
6907              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
6908              * {@link Roo.EventObject#getKey} to determine which key was pressed.
6909              * @param {Roo.form.Field} this
6910              * @param {Roo.EventObject} e The event object
6911              */
6912             specialkey : true,
6913             /**
6914              * @event change
6915              * Fires just before the field blurs if the field value has changed.
6916              * @param {Roo.form.Field} this
6917              * @param {Mixed} newValue The new value
6918              * @param {Mixed} oldValue The original value
6919              */
6920             change : true,
6921             /**
6922              * @event invalid
6923              * Fires after the field has been marked as invalid.
6924              * @param {Roo.form.Field} this
6925              * @param {String} msg The validation message
6926              */
6927             invalid : true,
6928             /**
6929              * @event valid
6930              * Fires after the field has been validated with no errors.
6931              * @param {Roo.form.Field} this
6932              */
6933             valid : true,
6934              /**
6935              * @event keyup
6936              * Fires after the key up
6937              * @param {Roo.form.Field} this
6938              * @param {Roo.EventObject}  e The event Object
6939              */
6940             keyup : true
6941         });
6942 };
6943
6944 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
6945      /**
6946      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6947       automatic validation (defaults to "keyup").
6948      */
6949     validationEvent : "keyup",
6950      /**
6951      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6952      */
6953     validateOnBlur : true,
6954     /**
6955      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6956      */
6957     validationDelay : 250,
6958      /**
6959      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6960      */
6961     focusClass : "x-form-focus",  // not needed???
6962     
6963        
6964     /**
6965      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6966      */
6967     invalidClass : "has-error",
6968     
6969     /**
6970      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6971      */
6972     selectOnFocus : false,
6973     
6974      /**
6975      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6976      */
6977     maskRe : null,
6978        /**
6979      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6980      */
6981     vtype : null,
6982     
6983       /**
6984      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6985      */
6986     disableKeyFilter : false,
6987     
6988        /**
6989      * @cfg {Boolean} disabled True to disable the field (defaults to false).
6990      */
6991     disabled : false,
6992      /**
6993      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6994      */
6995     allowBlank : true,
6996     /**
6997      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6998      */
6999     blankText : "This field is required",
7000     
7001      /**
7002      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7003      */
7004     minLength : 0,
7005     /**
7006      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7007      */
7008     maxLength : Number.MAX_VALUE,
7009     /**
7010      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7011      */
7012     minLengthText : "The minimum length for this field is {0}",
7013     /**
7014      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7015      */
7016     maxLengthText : "The maximum length for this field is {0}",
7017   
7018     
7019     /**
7020      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7021      * If available, this function will be called only after the basic validators all return true, and will be passed the
7022      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7023      */
7024     validator : null,
7025     /**
7026      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7027      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7028      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7029      */
7030     regex : null,
7031     /**
7032      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7033      */
7034     regexText : "",
7035     
7036     
7037     
7038     fieldLabel : '',
7039     inputType : 'text',
7040     
7041     name : false,
7042     placeholder: false,
7043     before : false,
7044     after : false,
7045     size : false,
7046     // private
7047     hasFocus : false,
7048     preventMark: false,
7049     isFormField : true,
7050     value : '',
7051     labelWidth : 2,
7052     labelAlign : false,
7053     readOnly : false,
7054     align : false,
7055     formatedValue : false,
7056     
7057     parentLabelAlign : function()
7058     {
7059         var parent = this;
7060         while (parent.parent()) {
7061             parent = parent.parent();
7062             if (typeof(parent.labelAlign) !='undefined') {
7063                 return parent.labelAlign;
7064             }
7065         }
7066         return 'left';
7067         
7068     },
7069     
7070     getAutoCreate : function(){
7071         
7072         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7073         
7074         var id = Roo.id();
7075         
7076         var cfg = {};
7077         
7078         if(this.inputType != 'hidden'){
7079             cfg.cls = 'form-group' //input-group
7080         }
7081         
7082         var input =  {
7083             tag: 'input',
7084             id : id,
7085             type : this.inputType,
7086             value : this.value,
7087             cls : 'form-control',
7088             placeholder : this.placeholder || ''
7089             
7090         };
7091         
7092         if(this.align){
7093             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7094         }
7095         
7096         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7097             input.maxLength = this.maxLength;
7098         }
7099         
7100         if (this.disabled) {
7101             input.disabled=true;
7102         }
7103         
7104         if (this.readOnly) {
7105             input.readonly=true;
7106         }
7107         
7108         if (this.name) {
7109             input.name = this.name;
7110         }
7111         if (this.size) {
7112             input.cls += ' input-' + this.size;
7113         }
7114         var settings=this;
7115         ['xs','sm','md','lg'].map(function(size){
7116             if (settings[size]) {
7117                 cfg.cls += ' col-' + size + '-' + settings[size];
7118             }
7119         });
7120         
7121         var inputblock = input;
7122         
7123         if (this.before || this.after) {
7124             
7125             inputblock = {
7126                 cls : 'input-group',
7127                 cn :  [] 
7128             };
7129             if (this.before && typeof(this.before) == 'string') {
7130                 
7131                 inputblock.cn.push({
7132                     tag :'span',
7133                     cls : 'roo-input-before input-group-addon',
7134                     html : this.before
7135                 });
7136             }
7137             if (this.before && typeof(this.before) == 'object') {
7138                 this.before = Roo.factory(this.before);
7139                 Roo.log(this.before);
7140                 inputblock.cn.push({
7141                     tag :'span',
7142                     cls : 'roo-input-before input-group-' +
7143                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7144                 });
7145             }
7146             
7147             inputblock.cn.push(input);
7148             
7149             if (this.after && typeof(this.after) == 'string') {
7150                 inputblock.cn.push({
7151                     tag :'span',
7152                     cls : 'roo-input-after input-group-addon',
7153                     html : this.after
7154                 });
7155             }
7156             if (this.after && typeof(this.after) == 'object') {
7157                 this.after = Roo.factory(this.after);
7158                 Roo.log(this.after);
7159                 inputblock.cn.push({
7160                     tag :'span',
7161                     cls : 'roo-input-after input-group-' +
7162                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7163                 });
7164             }
7165         };
7166         
7167         if (align ==='left' && this.fieldLabel.length) {
7168                 Roo.log("left and has label");
7169                 cfg.cn = [
7170                     
7171                     {
7172                         tag: 'label',
7173                         'for' :  id,
7174                         cls : 'control-label col-sm-' + this.labelWidth,
7175                         html : this.fieldLabel
7176                         
7177                     },
7178                     {
7179                         cls : "col-sm-" + (12 - this.labelWidth), 
7180                         cn: [
7181                             inputblock
7182                         ]
7183                     }
7184                     
7185                 ];
7186         } else if ( this.fieldLabel.length) {
7187                 Roo.log(" label");
7188                  cfg.cn = [
7189                    
7190                     {
7191                         tag: 'label',
7192                         //cls : 'input-group-addon',
7193                         html : this.fieldLabel
7194                         
7195                     },
7196                     
7197                     inputblock
7198                     
7199                 ];
7200
7201         } else {
7202             
7203                 Roo.log(" no label && no align");
7204                 cfg.cn = [
7205                     
7206                         inputblock
7207                     
7208                 ];
7209                 
7210                 
7211         };
7212         Roo.log('input-parentType: ' + this.parentType);
7213         
7214         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7215            cfg.cls += ' navbar-form';
7216            Roo.log(cfg);
7217         }
7218         
7219         return cfg;
7220         
7221     },
7222     /**
7223      * return the real input element.
7224      */
7225     inputEl: function ()
7226     {
7227         return this.el.select('input.form-control',true).first();
7228     },
7229     
7230     tooltipEl : function()
7231     {
7232         return this.inputEl();
7233     },
7234     
7235     setDisabled : function(v)
7236     {
7237         var i  = this.inputEl().dom;
7238         if (!v) {
7239             i.removeAttribute('disabled');
7240             return;
7241             
7242         }
7243         i.setAttribute('disabled','true');
7244     },
7245     initEvents : function()
7246     {
7247           
7248         this.inputEl().on("keydown" , this.fireKey,  this);
7249         this.inputEl().on("focus", this.onFocus,  this);
7250         this.inputEl().on("blur", this.onBlur,  this);
7251         
7252         this.inputEl().relayEvent('keyup', this);
7253
7254         // reference to original value for reset
7255         this.originalValue = this.getValue();
7256         //Roo.form.TextField.superclass.initEvents.call(this);
7257         if(this.validationEvent == 'keyup'){
7258             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7259             this.inputEl().on('keyup', this.filterValidation, this);
7260         }
7261         else if(this.validationEvent !== false){
7262             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7263         }
7264         
7265         if(this.selectOnFocus){
7266             this.on("focus", this.preFocus, this);
7267             
7268         }
7269         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7270             this.inputEl().on("keypress", this.filterKeys, this);
7271         }
7272        /* if(this.grow){
7273             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7274             this.el.on("click", this.autoSize,  this);
7275         }
7276         */
7277         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7278             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7279         }
7280         
7281         if (typeof(this.before) == 'object') {
7282             this.before.render(this.el.select('.roo-input-before',true).first());
7283         }
7284         if (typeof(this.after) == 'object') {
7285             this.after.render(this.el.select('.roo-input-after',true).first());
7286         }
7287         
7288         
7289     },
7290     filterValidation : function(e){
7291         if(!e.isNavKeyPress()){
7292             this.validationTask.delay(this.validationDelay);
7293         }
7294     },
7295      /**
7296      * Validates the field value
7297      * @return {Boolean} True if the value is valid, else false
7298      */
7299     validate : function(){
7300         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7301         if(this.disabled || this.validateValue(this.getRawValue())){
7302             this.clearInvalid();
7303             return true;
7304         }
7305         return false;
7306     },
7307     
7308     
7309     /**
7310      * Validates a value according to the field's validation rules and marks the field as invalid
7311      * if the validation fails
7312      * @param {Mixed} value The value to validate
7313      * @return {Boolean} True if the value is valid, else false
7314      */
7315     validateValue : function(value){
7316         if(value.length < 1)  { // if it's blank
7317              if(this.allowBlank){
7318                 this.clearInvalid();
7319                 return true;
7320              }else{
7321                 this.markInvalid(this.blankText);
7322                 return false;
7323              }
7324         }
7325         if(value.length < this.minLength){
7326             this.markInvalid(String.format(this.minLengthText, this.minLength));
7327             return false;
7328         }
7329         if(value.length > this.maxLength){
7330             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7331             return false;
7332         }
7333         if(this.vtype){
7334             var vt = Roo.form.VTypes;
7335             if(!vt[this.vtype](value, this)){
7336                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7337                 return false;
7338             }
7339         }
7340         if(typeof this.validator == "function"){
7341             var msg = this.validator(value);
7342             if(msg !== true){
7343                 this.markInvalid(msg);
7344                 return false;
7345             }
7346         }
7347         if(this.regex && !this.regex.test(value)){
7348             this.markInvalid(this.regexText);
7349             return false;
7350         }
7351         return true;
7352     },
7353
7354     
7355     
7356      // private
7357     fireKey : function(e){
7358         //Roo.log('field ' + e.getKey());
7359         if(e.isNavKeyPress()){
7360             this.fireEvent("specialkey", this, e);
7361         }
7362     },
7363     focus : function (selectText){
7364         if(this.rendered){
7365             this.inputEl().focus();
7366             if(selectText === true){
7367                 this.inputEl().dom.select();
7368             }
7369         }
7370         return this;
7371     } ,
7372     
7373     onFocus : function(){
7374         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7375            // this.el.addClass(this.focusClass);
7376         }
7377         if(!this.hasFocus){
7378             this.hasFocus = true;
7379             this.startValue = this.getValue();
7380             this.fireEvent("focus", this);
7381         }
7382     },
7383     
7384     beforeBlur : Roo.emptyFn,
7385
7386     
7387     // private
7388     onBlur : function(){
7389         this.beforeBlur();
7390         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7391             //this.el.removeClass(this.focusClass);
7392         }
7393         this.hasFocus = false;
7394         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7395             this.validate();
7396         }
7397         var v = this.getValue();
7398         if(String(v) !== String(this.startValue)){
7399             this.fireEvent('change', this, v, this.startValue);
7400         }
7401         this.fireEvent("blur", this);
7402     },
7403     
7404     /**
7405      * Resets the current field value to the originally loaded value and clears any validation messages
7406      */
7407     reset : function(){
7408         this.setValue(this.originalValue);
7409         this.clearInvalid();
7410     },
7411      /**
7412      * Returns the name of the field
7413      * @return {Mixed} name The name field
7414      */
7415     getName: function(){
7416         return this.name;
7417     },
7418      /**
7419      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7420      * @return {Mixed} value The field value
7421      */
7422     getValue : function(){
7423         
7424         var v = this.inputEl().getValue();
7425         
7426         return v;
7427     },
7428     /**
7429      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7430      * @return {Mixed} value The field value
7431      */
7432     getRawValue : function(){
7433         var v = this.inputEl().getValue();
7434         
7435         return v;
7436     },
7437     
7438     /**
7439      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7440      * @param {Mixed} value The value to set
7441      */
7442     setRawValue : function(v){
7443         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7444     },
7445     
7446     selectText : function(start, end){
7447         var v = this.getRawValue();
7448         if(v.length > 0){
7449             start = start === undefined ? 0 : start;
7450             end = end === undefined ? v.length : end;
7451             var d = this.inputEl().dom;
7452             if(d.setSelectionRange){
7453                 d.setSelectionRange(start, end);
7454             }else if(d.createTextRange){
7455                 var range = d.createTextRange();
7456                 range.moveStart("character", start);
7457                 range.moveEnd("character", v.length-end);
7458                 range.select();
7459             }
7460         }
7461     },
7462     
7463     /**
7464      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7465      * @param {Mixed} value The value to set
7466      */
7467     setValue : function(v){
7468         this.value = v;
7469         if(this.rendered){
7470             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7471             this.validate();
7472         }
7473     },
7474     
7475     /*
7476     processValue : function(value){
7477         if(this.stripCharsRe){
7478             var newValue = value.replace(this.stripCharsRe, '');
7479             if(newValue !== value){
7480                 this.setRawValue(newValue);
7481                 return newValue;
7482             }
7483         }
7484         return value;
7485     },
7486   */
7487     preFocus : function(){
7488         
7489         if(this.selectOnFocus){
7490             this.inputEl().dom.select();
7491         }
7492     },
7493     filterKeys : function(e){
7494         var k = e.getKey();
7495         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7496             return;
7497         }
7498         var c = e.getCharCode(), cc = String.fromCharCode(c);
7499         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7500             return;
7501         }
7502         if(!this.maskRe.test(cc)){
7503             e.stopEvent();
7504         }
7505     },
7506      /**
7507      * Clear any invalid styles/messages for this field
7508      */
7509     clearInvalid : function(){
7510         
7511         if(!this.el || this.preventMark){ // not rendered
7512             return;
7513         }
7514         this.el.removeClass(this.invalidClass);
7515         /*
7516         switch(this.msgTarget){
7517             case 'qtip':
7518                 this.el.dom.qtip = '';
7519                 break;
7520             case 'title':
7521                 this.el.dom.title = '';
7522                 break;
7523             case 'under':
7524                 if(this.errorEl){
7525                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7526                 }
7527                 break;
7528             case 'side':
7529                 if(this.errorIcon){
7530                     this.errorIcon.dom.qtip = '';
7531                     this.errorIcon.hide();
7532                     this.un('resize', this.alignErrorIcon, this);
7533                 }
7534                 break;
7535             default:
7536                 var t = Roo.getDom(this.msgTarget);
7537                 t.innerHTML = '';
7538                 t.style.display = 'none';
7539                 break;
7540         }
7541         */
7542         this.fireEvent('valid', this);
7543     },
7544      /**
7545      * Mark this field as invalid
7546      * @param {String} msg The validation message
7547      */
7548     markInvalid : function(msg){
7549         if(!this.el  || this.preventMark){ // not rendered
7550             return;
7551         }
7552         this.el.addClass(this.invalidClass);
7553         /*
7554         msg = msg || this.invalidText;
7555         switch(this.msgTarget){
7556             case 'qtip':
7557                 this.el.dom.qtip = msg;
7558                 this.el.dom.qclass = 'x-form-invalid-tip';
7559                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7560                     Roo.QuickTips.enable();
7561                 }
7562                 break;
7563             case 'title':
7564                 this.el.dom.title = msg;
7565                 break;
7566             case 'under':
7567                 if(!this.errorEl){
7568                     var elp = this.el.findParent('.x-form-element', 5, true);
7569                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7570                     this.errorEl.setWidth(elp.getWidth(true)-20);
7571                 }
7572                 this.errorEl.update(msg);
7573                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7574                 break;
7575             case 'side':
7576                 if(!this.errorIcon){
7577                     var elp = this.el.findParent('.x-form-element', 5, true);
7578                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7579                 }
7580                 this.alignErrorIcon();
7581                 this.errorIcon.dom.qtip = msg;
7582                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7583                 this.errorIcon.show();
7584                 this.on('resize', this.alignErrorIcon, this);
7585                 break;
7586             default:
7587                 var t = Roo.getDom(this.msgTarget);
7588                 t.innerHTML = msg;
7589                 t.style.display = this.msgDisplay;
7590                 break;
7591         }
7592         */
7593         this.fireEvent('invalid', this, msg);
7594     },
7595     // private
7596     SafariOnKeyDown : function(event)
7597     {
7598         // this is a workaround for a password hang bug on chrome/ webkit.
7599         
7600         var isSelectAll = false;
7601         
7602         if(this.inputEl().dom.selectionEnd > 0){
7603             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7604         }
7605         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7606             event.preventDefault();
7607             this.setValue('');
7608             return;
7609         }
7610         
7611         if(isSelectAll){ // backspace and delete key
7612             
7613             event.preventDefault();
7614             // this is very hacky as keydown always get's upper case.
7615             //
7616             var cc = String.fromCharCode(event.getCharCode());
7617             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7618             
7619         }
7620     },
7621     adjustWidth : function(tag, w){
7622         tag = tag.toLowerCase();
7623         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7624             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7625                 if(tag == 'input'){
7626                     return w + 2;
7627                 }
7628                 if(tag == 'textarea'){
7629                     return w-2;
7630                 }
7631             }else if(Roo.isOpera){
7632                 if(tag == 'input'){
7633                     return w + 2;
7634                 }
7635                 if(tag == 'textarea'){
7636                     return w-2;
7637                 }
7638             }
7639         }
7640         return w;
7641     }
7642     
7643 });
7644
7645  
7646 /*
7647  * - LGPL
7648  *
7649  * Input
7650  * 
7651  */
7652
7653 /**
7654  * @class Roo.bootstrap.TextArea
7655  * @extends Roo.bootstrap.Input
7656  * Bootstrap TextArea class
7657  * @cfg {Number} cols Specifies the visible width of a text area
7658  * @cfg {Number} rows Specifies the visible number of lines in a text area
7659  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7660  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7661  * @cfg {string} html text
7662  * 
7663  * @constructor
7664  * Create a new TextArea
7665  * @param {Object} config The config object
7666  */
7667
7668 Roo.bootstrap.TextArea = function(config){
7669     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7670    
7671 };
7672
7673 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7674      
7675     cols : false,
7676     rows : 5,
7677     readOnly : false,
7678     warp : 'soft',
7679     resize : false,
7680     value: false,
7681     html: false,
7682     
7683     getAutoCreate : function(){
7684         
7685         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7686         
7687         var id = Roo.id();
7688         
7689         var cfg = {};
7690         
7691         var input =  {
7692             tag: 'textarea',
7693             id : id,
7694             warp : this.warp,
7695             rows : this.rows,
7696             value : this.value || '',
7697             html: this.html || '',
7698             cls : 'form-control',
7699             placeholder : this.placeholder || '' 
7700             
7701         };
7702         
7703         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7704             input.maxLength = this.maxLength;
7705         }
7706         
7707         if(this.resize){
7708             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7709         }
7710         
7711         if(this.cols){
7712             input.cols = this.cols;
7713         }
7714         
7715         if (this.readOnly) {
7716             input.readonly = true;
7717         }
7718         
7719         if (this.name) {
7720             input.name = this.name;
7721         }
7722         
7723         if (this.size) {
7724             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7725         }
7726         
7727         var settings=this;
7728         ['xs','sm','md','lg'].map(function(size){
7729             if (settings[size]) {
7730                 cfg.cls += ' col-' + size + '-' + settings[size];
7731             }
7732         });
7733         
7734         var inputblock = input;
7735         
7736         if (this.before || this.after) {
7737             
7738             inputblock = {
7739                 cls : 'input-group',
7740                 cn :  [] 
7741             };
7742             if (this.before) {
7743                 inputblock.cn.push({
7744                     tag :'span',
7745                     cls : 'input-group-addon',
7746                     html : this.before
7747                 });
7748             }
7749             inputblock.cn.push(input);
7750             if (this.after) {
7751                 inputblock.cn.push({
7752                     tag :'span',
7753                     cls : 'input-group-addon',
7754                     html : this.after
7755                 });
7756             }
7757             
7758         }
7759         
7760         if (align ==='left' && this.fieldLabel.length) {
7761                 Roo.log("left and has label");
7762                 cfg.cn = [
7763                     
7764                     {
7765                         tag: 'label',
7766                         'for' :  id,
7767                         cls : 'control-label col-sm-' + this.labelWidth,
7768                         html : this.fieldLabel
7769                         
7770                     },
7771                     {
7772                         cls : "col-sm-" + (12 - this.labelWidth), 
7773                         cn: [
7774                             inputblock
7775                         ]
7776                     }
7777                     
7778                 ];
7779         } else if ( this.fieldLabel.length) {
7780                 Roo.log(" label");
7781                  cfg.cn = [
7782                    
7783                     {
7784                         tag: 'label',
7785                         //cls : 'input-group-addon',
7786                         html : this.fieldLabel
7787                         
7788                     },
7789                     
7790                     inputblock
7791                     
7792                 ];
7793
7794         } else {
7795             
7796                    Roo.log(" no label && no align");
7797                 cfg.cn = [
7798                     
7799                         inputblock
7800                     
7801                 ];
7802                 
7803                 
7804         }
7805         
7806         if (this.disabled) {
7807             input.disabled=true;
7808         }
7809         
7810         return cfg;
7811         
7812     },
7813     /**
7814      * return the real textarea element.
7815      */
7816     inputEl: function ()
7817     {
7818         return this.el.select('textarea.form-control',true).first();
7819     }
7820 });
7821
7822  
7823 /*
7824  * - LGPL
7825  *
7826  * trigger field - base class for combo..
7827  * 
7828  */
7829  
7830 /**
7831  * @class Roo.bootstrap.TriggerField
7832  * @extends Roo.bootstrap.Input
7833  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7834  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7835  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7836  * for which you can provide a custom implementation.  For example:
7837  * <pre><code>
7838 var trigger = new Roo.bootstrap.TriggerField();
7839 trigger.onTriggerClick = myTriggerFn;
7840 trigger.applyTo('my-field');
7841 </code></pre>
7842  *
7843  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7844  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7845  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
7846  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7847  * @constructor
7848  * Create a new TriggerField.
7849  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7850  * to the base TextField)
7851  */
7852 Roo.bootstrap.TriggerField = function(config){
7853     this.mimicing = false;
7854     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7855 };
7856
7857 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
7858     /**
7859      * @cfg {String} triggerClass A CSS class to apply to the trigger
7860      */
7861      /**
7862      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7863      */
7864     hideTrigger:false,
7865
7866     /** @cfg {Boolean} grow @hide */
7867     /** @cfg {Number} growMin @hide */
7868     /** @cfg {Number} growMax @hide */
7869
7870     /**
7871      * @hide 
7872      * @method
7873      */
7874     autoSize: Roo.emptyFn,
7875     // private
7876     monitorTab : true,
7877     // private
7878     deferHeight : true,
7879
7880     
7881     actionMode : 'wrap',
7882     
7883     
7884     
7885     getAutoCreate : function(){
7886        
7887         var align = this.labelAlign || this.parentLabelAlign();
7888         
7889         var id = Roo.id();
7890         
7891         var cfg = {
7892             cls: 'form-group' //input-group
7893         };
7894         
7895         
7896         var input =  {
7897             tag: 'input',
7898             id : id,
7899             type : this.inputType,
7900             cls : 'form-control',
7901             autocomplete: 'off',
7902             placeholder : this.placeholder || '' 
7903             
7904         };
7905         if (this.name) {
7906             input.name = this.name;
7907         }
7908         if (this.size) {
7909             input.cls += ' input-' + this.size;
7910         }
7911         
7912         if (this.disabled) {
7913             input.disabled=true;
7914         }
7915         
7916         var inputblock = input;
7917         
7918         if (this.before || this.after) {
7919             
7920             inputblock = {
7921                 cls : 'input-group',
7922                 cn :  [] 
7923             };
7924             if (this.before) {
7925                 inputblock.cn.push({
7926                     tag :'span',
7927                     cls : 'input-group-addon',
7928                     html : this.before
7929                 });
7930             }
7931             inputblock.cn.push(input);
7932             if (this.after) {
7933                 inputblock.cn.push({
7934                     tag :'span',
7935                     cls : 'input-group-addon',
7936                     html : this.after
7937                 });
7938             }
7939             
7940         };
7941         
7942         var box = {
7943             tag: 'div',
7944             cn: [
7945                 {
7946                     tag: 'input',
7947                     type : 'hidden',
7948                     cls: 'form-hidden-field'
7949                 },
7950                 inputblock
7951             ]
7952             
7953         };
7954         
7955         if(this.multiple){
7956             Roo.log('multiple');
7957             
7958             box = {
7959                 tag: 'div',
7960                 cn: [
7961                     {
7962                         tag: 'input',
7963                         type : 'hidden',
7964                         cls: 'form-hidden-field'
7965                     },
7966                     {
7967                         tag: 'ul',
7968                         cls: 'select2-choices',
7969                         cn:[
7970                             {
7971                                 tag: 'li',
7972                                 cls: 'select2-search-field',
7973                                 cn: [
7974
7975                                     inputblock
7976                                 ]
7977                             }
7978                         ]
7979                     }
7980                 ]
7981             }
7982         };
7983         
7984         var combobox = {
7985             cls: 'select2-container input-group',
7986             cn: [
7987                 box
7988 //                {
7989 //                    tag: 'ul',
7990 //                    cls: 'typeahead typeahead-long dropdown-menu',
7991 //                    style: 'display:none'
7992 //                }
7993             ]
7994         };
7995         
7996         if(!this.multiple && this.showToggleBtn){
7997             combobox.cn.push({
7998                 tag :'span',
7999                 cls : 'input-group-addon btn dropdown-toggle',
8000                 cn : [
8001                     {
8002                         tag: 'span',
8003                         cls: 'caret'
8004                     },
8005                     {
8006                         tag: 'span',
8007                         cls: 'combobox-clear',
8008                         cn  : [
8009                             {
8010                                 tag : 'i',
8011                                 cls: 'icon-remove'
8012                             }
8013                         ]
8014                     }
8015                 ]
8016
8017             })
8018         }
8019         
8020         if(this.multiple){
8021             combobox.cls += ' select2-container-multi';
8022         }
8023         
8024         if (align ==='left' && this.fieldLabel.length) {
8025             
8026                 Roo.log("left and has label");
8027                 cfg.cn = [
8028                     
8029                     {
8030                         tag: 'label',
8031                         'for' :  id,
8032                         cls : 'control-label col-sm-' + this.labelWidth,
8033                         html : this.fieldLabel
8034                         
8035                     },
8036                     {
8037                         cls : "col-sm-" + (12 - this.labelWidth), 
8038                         cn: [
8039                             combobox
8040                         ]
8041                     }
8042                     
8043                 ];
8044         } else if ( this.fieldLabel.length) {
8045                 Roo.log(" label");
8046                  cfg.cn = [
8047                    
8048                     {
8049                         tag: 'label',
8050                         //cls : 'input-group-addon',
8051                         html : this.fieldLabel
8052                         
8053                     },
8054                     
8055                     combobox
8056                     
8057                 ];
8058
8059         } else {
8060             
8061                 Roo.log(" no label && no align");
8062                 cfg = combobox
8063                      
8064                 
8065         }
8066          
8067         var settings=this;
8068         ['xs','sm','md','lg'].map(function(size){
8069             if (settings[size]) {
8070                 cfg.cls += ' col-' + size + '-' + settings[size];
8071             }
8072         });
8073         
8074         return cfg;
8075         
8076     },
8077     
8078     
8079     
8080     // private
8081     onResize : function(w, h){
8082 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8083 //        if(typeof w == 'number'){
8084 //            var x = w - this.trigger.getWidth();
8085 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8086 //            this.trigger.setStyle('left', x+'px');
8087 //        }
8088     },
8089
8090     // private
8091     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8092
8093     // private
8094     getResizeEl : function(){
8095         return this.inputEl();
8096     },
8097
8098     // private
8099     getPositionEl : function(){
8100         return this.inputEl();
8101     },
8102
8103     // private
8104     alignErrorIcon : function(){
8105         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8106     },
8107
8108     // private
8109     initEvents : function(){
8110         
8111         this.createList();
8112         
8113         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8114         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8115         if(!this.multiple && this.showToggleBtn){
8116             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8117             if(this.hideTrigger){
8118                 this.trigger.setDisplayed(false);
8119             }
8120             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8121         }
8122         
8123         if(this.multiple){
8124             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8125         }
8126         
8127         //this.trigger.addClassOnOver('x-form-trigger-over');
8128         //this.trigger.addClassOnClick('x-form-trigger-click');
8129         
8130         //if(!this.width){
8131         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8132         //}
8133     },
8134     
8135     createList : function()
8136     {
8137         this.list = Roo.get(document.body).createChild({
8138             tag: 'ul',
8139             cls: 'typeahead typeahead-long dropdown-menu',
8140             style: 'display:none'
8141         });
8142         
8143         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8144         
8145     },
8146
8147     // private
8148     initTrigger : function(){
8149        
8150     },
8151
8152     // private
8153     onDestroy : function(){
8154         if(this.trigger){
8155             this.trigger.removeAllListeners();
8156           //  this.trigger.remove();
8157         }
8158         //if(this.wrap){
8159         //    this.wrap.remove();
8160         //}
8161         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8162     },
8163
8164     // private
8165     onFocus : function(){
8166         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8167         /*
8168         if(!this.mimicing){
8169             this.wrap.addClass('x-trigger-wrap-focus');
8170             this.mimicing = true;
8171             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8172             if(this.monitorTab){
8173                 this.el.on("keydown", this.checkTab, this);
8174             }
8175         }
8176         */
8177     },
8178
8179     // private
8180     checkTab : function(e){
8181         if(e.getKey() == e.TAB){
8182             this.triggerBlur();
8183         }
8184     },
8185
8186     // private
8187     onBlur : function(){
8188         // do nothing
8189     },
8190
8191     // private
8192     mimicBlur : function(e, t){
8193         /*
8194         if(!this.wrap.contains(t) && this.validateBlur()){
8195             this.triggerBlur();
8196         }
8197         */
8198     },
8199
8200     // private
8201     triggerBlur : function(){
8202         this.mimicing = false;
8203         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8204         if(this.monitorTab){
8205             this.el.un("keydown", this.checkTab, this);
8206         }
8207         //this.wrap.removeClass('x-trigger-wrap-focus');
8208         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8209     },
8210
8211     // private
8212     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8213     validateBlur : function(e, t){
8214         return true;
8215     },
8216
8217     // private
8218     onDisable : function(){
8219         this.inputEl().dom.disabled = true;
8220         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8221         //if(this.wrap){
8222         //    this.wrap.addClass('x-item-disabled');
8223         //}
8224     },
8225
8226     // private
8227     onEnable : function(){
8228         this.inputEl().dom.disabled = false;
8229         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8230         //if(this.wrap){
8231         //    this.el.removeClass('x-item-disabled');
8232         //}
8233     },
8234
8235     // private
8236     onShow : function(){
8237         var ae = this.getActionEl();
8238         
8239         if(ae){
8240             ae.dom.style.display = '';
8241             ae.dom.style.visibility = 'visible';
8242         }
8243     },
8244
8245     // private
8246     
8247     onHide : function(){
8248         var ae = this.getActionEl();
8249         ae.dom.style.display = 'none';
8250     },
8251
8252     /**
8253      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8254      * by an implementing function.
8255      * @method
8256      * @param {EventObject} e
8257      */
8258     onTriggerClick : Roo.emptyFn
8259 });
8260  /*
8261  * Based on:
8262  * Ext JS Library 1.1.1
8263  * Copyright(c) 2006-2007, Ext JS, LLC.
8264  *
8265  * Originally Released Under LGPL - original licence link has changed is not relivant.
8266  *
8267  * Fork - LGPL
8268  * <script type="text/javascript">
8269  */
8270
8271
8272 /**
8273  * @class Roo.data.SortTypes
8274  * @singleton
8275  * Defines the default sorting (casting?) comparison functions used when sorting data.
8276  */
8277 Roo.data.SortTypes = {
8278     /**
8279      * Default sort that does nothing
8280      * @param {Mixed} s The value being converted
8281      * @return {Mixed} The comparison value
8282      */
8283     none : function(s){
8284         return s;
8285     },
8286     
8287     /**
8288      * The regular expression used to strip tags
8289      * @type {RegExp}
8290      * @property
8291      */
8292     stripTagsRE : /<\/?[^>]+>/gi,
8293     
8294     /**
8295      * Strips all HTML tags to sort on text only
8296      * @param {Mixed} s The value being converted
8297      * @return {String} The comparison value
8298      */
8299     asText : function(s){
8300         return String(s).replace(this.stripTagsRE, "");
8301     },
8302     
8303     /**
8304      * Strips all HTML tags to sort on text only - Case insensitive
8305      * @param {Mixed} s The value being converted
8306      * @return {String} The comparison value
8307      */
8308     asUCText : function(s){
8309         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8310     },
8311     
8312     /**
8313      * Case insensitive string
8314      * @param {Mixed} s The value being converted
8315      * @return {String} The comparison value
8316      */
8317     asUCString : function(s) {
8318         return String(s).toUpperCase();
8319     },
8320     
8321     /**
8322      * Date sorting
8323      * @param {Mixed} s The value being converted
8324      * @return {Number} The comparison value
8325      */
8326     asDate : function(s) {
8327         if(!s){
8328             return 0;
8329         }
8330         if(s instanceof Date){
8331             return s.getTime();
8332         }
8333         return Date.parse(String(s));
8334     },
8335     
8336     /**
8337      * Float sorting
8338      * @param {Mixed} s The value being converted
8339      * @return {Float} The comparison value
8340      */
8341     asFloat : function(s) {
8342         var val = parseFloat(String(s).replace(/,/g, ""));
8343         if(isNaN(val)) val = 0;
8344         return val;
8345     },
8346     
8347     /**
8348      * Integer sorting
8349      * @param {Mixed} s The value being converted
8350      * @return {Number} The comparison value
8351      */
8352     asInt : function(s) {
8353         var val = parseInt(String(s).replace(/,/g, ""));
8354         if(isNaN(val)) val = 0;
8355         return val;
8356     }
8357 };/*
8358  * Based on:
8359  * Ext JS Library 1.1.1
8360  * Copyright(c) 2006-2007, Ext JS, LLC.
8361  *
8362  * Originally Released Under LGPL - original licence link has changed is not relivant.
8363  *
8364  * Fork - LGPL
8365  * <script type="text/javascript">
8366  */
8367
8368 /**
8369 * @class Roo.data.Record
8370  * Instances of this class encapsulate both record <em>definition</em> information, and record
8371  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8372  * to access Records cached in an {@link Roo.data.Store} object.<br>
8373  * <p>
8374  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8375  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8376  * objects.<br>
8377  * <p>
8378  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8379  * @constructor
8380  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8381  * {@link #create}. The parameters are the same.
8382  * @param {Array} data An associative Array of data values keyed by the field name.
8383  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8384  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8385  * not specified an integer id is generated.
8386  */
8387 Roo.data.Record = function(data, id){
8388     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8389     this.data = data;
8390 };
8391
8392 /**
8393  * Generate a constructor for a specific record layout.
8394  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8395  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8396  * Each field definition object may contain the following properties: <ul>
8397  * <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,
8398  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8399  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8400  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8401  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8402  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8403  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8404  * this may be omitted.</p></li>
8405  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8406  * <ul><li>auto (Default, implies no conversion)</li>
8407  * <li>string</li>
8408  * <li>int</li>
8409  * <li>float</li>
8410  * <li>boolean</li>
8411  * <li>date</li></ul></p></li>
8412  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8413  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8414  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8415  * by the Reader into an object that will be stored in the Record. It is passed the
8416  * following parameters:<ul>
8417  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8418  * </ul></p></li>
8419  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8420  * </ul>
8421  * <br>usage:<br><pre><code>
8422 var TopicRecord = Roo.data.Record.create(
8423     {name: 'title', mapping: 'topic_title'},
8424     {name: 'author', mapping: 'username'},
8425     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8426     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8427     {name: 'lastPoster', mapping: 'user2'},
8428     {name: 'excerpt', mapping: 'post_text'}
8429 );
8430
8431 var myNewRecord = new TopicRecord({
8432     title: 'Do my job please',
8433     author: 'noobie',
8434     totalPosts: 1,
8435     lastPost: new Date(),
8436     lastPoster: 'Animal',
8437     excerpt: 'No way dude!'
8438 });
8439 myStore.add(myNewRecord);
8440 </code></pre>
8441  * @method create
8442  * @static
8443  */
8444 Roo.data.Record.create = function(o){
8445     var f = function(){
8446         f.superclass.constructor.apply(this, arguments);
8447     };
8448     Roo.extend(f, Roo.data.Record);
8449     var p = f.prototype;
8450     p.fields = new Roo.util.MixedCollection(false, function(field){
8451         return field.name;
8452     });
8453     for(var i = 0, len = o.length; i < len; i++){
8454         p.fields.add(new Roo.data.Field(o[i]));
8455     }
8456     f.getField = function(name){
8457         return p.fields.get(name);  
8458     };
8459     return f;
8460 };
8461
8462 Roo.data.Record.AUTO_ID = 1000;
8463 Roo.data.Record.EDIT = 'edit';
8464 Roo.data.Record.REJECT = 'reject';
8465 Roo.data.Record.COMMIT = 'commit';
8466
8467 Roo.data.Record.prototype = {
8468     /**
8469      * Readonly flag - true if this record has been modified.
8470      * @type Boolean
8471      */
8472     dirty : false,
8473     editing : false,
8474     error: null,
8475     modified: null,
8476
8477     // private
8478     join : function(store){
8479         this.store = store;
8480     },
8481
8482     /**
8483      * Set the named field to the specified value.
8484      * @param {String} name The name of the field to set.
8485      * @param {Object} value The value to set the field to.
8486      */
8487     set : function(name, value){
8488         if(this.data[name] == value){
8489             return;
8490         }
8491         this.dirty = true;
8492         if(!this.modified){
8493             this.modified = {};
8494         }
8495         if(typeof this.modified[name] == 'undefined'){
8496             this.modified[name] = this.data[name];
8497         }
8498         this.data[name] = value;
8499         if(!this.editing && this.store){
8500             this.store.afterEdit(this);
8501         }       
8502     },
8503
8504     /**
8505      * Get the value of the named field.
8506      * @param {String} name The name of the field to get the value of.
8507      * @return {Object} The value of the field.
8508      */
8509     get : function(name){
8510         return this.data[name]; 
8511     },
8512
8513     // private
8514     beginEdit : function(){
8515         this.editing = true;
8516         this.modified = {}; 
8517     },
8518
8519     // private
8520     cancelEdit : function(){
8521         this.editing = false;
8522         delete this.modified;
8523     },
8524
8525     // private
8526     endEdit : function(){
8527         this.editing = false;
8528         if(this.dirty && this.store){
8529             this.store.afterEdit(this);
8530         }
8531     },
8532
8533     /**
8534      * Usually called by the {@link Roo.data.Store} which owns the Record.
8535      * Rejects all changes made to the Record since either creation, or the last commit operation.
8536      * Modified fields are reverted to their original values.
8537      * <p>
8538      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8539      * of reject operations.
8540      */
8541     reject : function(){
8542         var m = this.modified;
8543         for(var n in m){
8544             if(typeof m[n] != "function"){
8545                 this.data[n] = m[n];
8546             }
8547         }
8548         this.dirty = false;
8549         delete this.modified;
8550         this.editing = false;
8551         if(this.store){
8552             this.store.afterReject(this);
8553         }
8554     },
8555
8556     /**
8557      * Usually called by the {@link Roo.data.Store} which owns the Record.
8558      * Commits all changes made to the Record since either creation, or the last commit operation.
8559      * <p>
8560      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8561      * of commit operations.
8562      */
8563     commit : function(){
8564         this.dirty = false;
8565         delete this.modified;
8566         this.editing = false;
8567         if(this.store){
8568             this.store.afterCommit(this);
8569         }
8570     },
8571
8572     // private
8573     hasError : function(){
8574         return this.error != null;
8575     },
8576
8577     // private
8578     clearError : function(){
8579         this.error = null;
8580     },
8581
8582     /**
8583      * Creates a copy of this record.
8584      * @param {String} id (optional) A new record id if you don't want to use this record's id
8585      * @return {Record}
8586      */
8587     copy : function(newId) {
8588         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8589     }
8590 };/*
8591  * Based on:
8592  * Ext JS Library 1.1.1
8593  * Copyright(c) 2006-2007, Ext JS, LLC.
8594  *
8595  * Originally Released Under LGPL - original licence link has changed is not relivant.
8596  *
8597  * Fork - LGPL
8598  * <script type="text/javascript">
8599  */
8600
8601
8602
8603 /**
8604  * @class Roo.data.Store
8605  * @extends Roo.util.Observable
8606  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8607  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8608  * <p>
8609  * 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
8610  * has no knowledge of the format of the data returned by the Proxy.<br>
8611  * <p>
8612  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8613  * instances from the data object. These records are cached and made available through accessor functions.
8614  * @constructor
8615  * Creates a new Store.
8616  * @param {Object} config A config object containing the objects needed for the Store to access data,
8617  * and read the data into Records.
8618  */
8619 Roo.data.Store = function(config){
8620     this.data = new Roo.util.MixedCollection(false);
8621     this.data.getKey = function(o){
8622         return o.id;
8623     };
8624     this.baseParams = {};
8625     // private
8626     this.paramNames = {
8627         "start" : "start",
8628         "limit" : "limit",
8629         "sort" : "sort",
8630         "dir" : "dir",
8631         "multisort" : "_multisort"
8632     };
8633
8634     if(config && config.data){
8635         this.inlineData = config.data;
8636         delete config.data;
8637     }
8638
8639     Roo.apply(this, config);
8640     
8641     if(this.reader){ // reader passed
8642         this.reader = Roo.factory(this.reader, Roo.data);
8643         this.reader.xmodule = this.xmodule || false;
8644         if(!this.recordType){
8645             this.recordType = this.reader.recordType;
8646         }
8647         if(this.reader.onMetaChange){
8648             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8649         }
8650     }
8651
8652     if(this.recordType){
8653         this.fields = this.recordType.prototype.fields;
8654     }
8655     this.modified = [];
8656
8657     this.addEvents({
8658         /**
8659          * @event datachanged
8660          * Fires when the data cache has changed, and a widget which is using this Store
8661          * as a Record cache should refresh its view.
8662          * @param {Store} this
8663          */
8664         datachanged : true,
8665         /**
8666          * @event metachange
8667          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8668          * @param {Store} this
8669          * @param {Object} meta The JSON metadata
8670          */
8671         metachange : true,
8672         /**
8673          * @event add
8674          * Fires when Records have been added to the Store
8675          * @param {Store} this
8676          * @param {Roo.data.Record[]} records The array of Records added
8677          * @param {Number} index The index at which the record(s) were added
8678          */
8679         add : true,
8680         /**
8681          * @event remove
8682          * Fires when a Record has been removed from the Store
8683          * @param {Store} this
8684          * @param {Roo.data.Record} record The Record that was removed
8685          * @param {Number} index The index at which the record was removed
8686          */
8687         remove : true,
8688         /**
8689          * @event update
8690          * Fires when a Record has been updated
8691          * @param {Store} this
8692          * @param {Roo.data.Record} record The Record that was updated
8693          * @param {String} operation The update operation being performed.  Value may be one of:
8694          * <pre><code>
8695  Roo.data.Record.EDIT
8696  Roo.data.Record.REJECT
8697  Roo.data.Record.COMMIT
8698          * </code></pre>
8699          */
8700         update : true,
8701         /**
8702          * @event clear
8703          * Fires when the data cache has been cleared.
8704          * @param {Store} this
8705          */
8706         clear : true,
8707         /**
8708          * @event beforeload
8709          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8710          * the load action will be canceled.
8711          * @param {Store} this
8712          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8713          */
8714         beforeload : true,
8715         /**
8716          * @event beforeloadadd
8717          * Fires after a new set of Records has been loaded.
8718          * @param {Store} this
8719          * @param {Roo.data.Record[]} records The Records that were loaded
8720          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8721          */
8722         beforeloadadd : true,
8723         /**
8724          * @event load
8725          * Fires after a new set of Records has been loaded, before they are added to the store.
8726          * @param {Store} this
8727          * @param {Roo.data.Record[]} records The Records that were loaded
8728          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8729          * @params {Object} return from reader
8730          */
8731         load : true,
8732         /**
8733          * @event loadexception
8734          * Fires if an exception occurs in the Proxy during loading.
8735          * Called with the signature of the Proxy's "loadexception" event.
8736          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8737          * 
8738          * @param {Proxy} 
8739          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8740          * @param {Object} load options 
8741          * @param {Object} jsonData from your request (normally this contains the Exception)
8742          */
8743         loadexception : true
8744     });
8745     
8746     if(this.proxy){
8747         this.proxy = Roo.factory(this.proxy, Roo.data);
8748         this.proxy.xmodule = this.xmodule || false;
8749         this.relayEvents(this.proxy,  ["loadexception"]);
8750     }
8751     this.sortToggle = {};
8752     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8753
8754     Roo.data.Store.superclass.constructor.call(this);
8755
8756     if(this.inlineData){
8757         this.loadData(this.inlineData);
8758         delete this.inlineData;
8759     }
8760 };
8761
8762 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8763      /**
8764     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8765     * without a remote query - used by combo/forms at present.
8766     */
8767     
8768     /**
8769     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8770     */
8771     /**
8772     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8773     */
8774     /**
8775     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8776     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8777     */
8778     /**
8779     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8780     * on any HTTP request
8781     */
8782     /**
8783     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8784     */
8785     /**
8786     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8787     */
8788     multiSort: false,
8789     /**
8790     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8791     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8792     */
8793     remoteSort : false,
8794
8795     /**
8796     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8797      * loaded or when a record is removed. (defaults to false).
8798     */
8799     pruneModifiedRecords : false,
8800
8801     // private
8802     lastOptions : null,
8803
8804     /**
8805      * Add Records to the Store and fires the add event.
8806      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8807      */
8808     add : function(records){
8809         records = [].concat(records);
8810         for(var i = 0, len = records.length; i < len; i++){
8811             records[i].join(this);
8812         }
8813         var index = this.data.length;
8814         this.data.addAll(records);
8815         this.fireEvent("add", this, records, index);
8816     },
8817
8818     /**
8819      * Remove a Record from the Store and fires the remove event.
8820      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8821      */
8822     remove : function(record){
8823         var index = this.data.indexOf(record);
8824         this.data.removeAt(index);
8825         if(this.pruneModifiedRecords){
8826             this.modified.remove(record);
8827         }
8828         this.fireEvent("remove", this, record, index);
8829     },
8830
8831     /**
8832      * Remove all Records from the Store and fires the clear event.
8833      */
8834     removeAll : function(){
8835         this.data.clear();
8836         if(this.pruneModifiedRecords){
8837             this.modified = [];
8838         }
8839         this.fireEvent("clear", this);
8840     },
8841
8842     /**
8843      * Inserts Records to the Store at the given index and fires the add event.
8844      * @param {Number} index The start index at which to insert the passed Records.
8845      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8846      */
8847     insert : function(index, records){
8848         records = [].concat(records);
8849         for(var i = 0, len = records.length; i < len; i++){
8850             this.data.insert(index, records[i]);
8851             records[i].join(this);
8852         }
8853         this.fireEvent("add", this, records, index);
8854     },
8855
8856     /**
8857      * Get the index within the cache of the passed Record.
8858      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8859      * @return {Number} The index of the passed Record. Returns -1 if not found.
8860      */
8861     indexOf : function(record){
8862         return this.data.indexOf(record);
8863     },
8864
8865     /**
8866      * Get the index within the cache of the Record with the passed id.
8867      * @param {String} id The id of the Record to find.
8868      * @return {Number} The index of the Record. Returns -1 if not found.
8869      */
8870     indexOfId : function(id){
8871         return this.data.indexOfKey(id);
8872     },
8873
8874     /**
8875      * Get the Record with the specified id.
8876      * @param {String} id The id of the Record to find.
8877      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8878      */
8879     getById : function(id){
8880         return this.data.key(id);
8881     },
8882
8883     /**
8884      * Get the Record at the specified index.
8885      * @param {Number} index The index of the Record to find.
8886      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8887      */
8888     getAt : function(index){
8889         return this.data.itemAt(index);
8890     },
8891
8892     /**
8893      * Returns a range of Records between specified indices.
8894      * @param {Number} startIndex (optional) The starting index (defaults to 0)
8895      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8896      * @return {Roo.data.Record[]} An array of Records
8897      */
8898     getRange : function(start, end){
8899         return this.data.getRange(start, end);
8900     },
8901
8902     // private
8903     storeOptions : function(o){
8904         o = Roo.apply({}, o);
8905         delete o.callback;
8906         delete o.scope;
8907         this.lastOptions = o;
8908     },
8909
8910     /**
8911      * Loads the Record cache from the configured Proxy using the configured Reader.
8912      * <p>
8913      * If using remote paging, then the first load call must specify the <em>start</em>
8914      * and <em>limit</em> properties in the options.params property to establish the initial
8915      * position within the dataset, and the number of Records to cache on each read from the Proxy.
8916      * <p>
8917      * <strong>It is important to note that for remote data sources, loading is asynchronous,
8918      * and this call will return before the new data has been loaded. Perform any post-processing
8919      * in a callback function, or in a "load" event handler.</strong>
8920      * <p>
8921      * @param {Object} options An object containing properties which control loading options:<ul>
8922      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8923      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8924      * passed the following arguments:<ul>
8925      * <li>r : Roo.data.Record[]</li>
8926      * <li>options: Options object from the load call</li>
8927      * <li>success: Boolean success indicator</li></ul></li>
8928      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8929      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8930      * </ul>
8931      */
8932     load : function(options){
8933         options = options || {};
8934         if(this.fireEvent("beforeload", this, options) !== false){
8935             this.storeOptions(options);
8936             var p = Roo.apply(options.params || {}, this.baseParams);
8937             // if meta was not loaded from remote source.. try requesting it.
8938             if (!this.reader.metaFromRemote) {
8939                 p._requestMeta = 1;
8940             }
8941             if(this.sortInfo && this.remoteSort){
8942                 var pn = this.paramNames;
8943                 p[pn["sort"]] = this.sortInfo.field;
8944                 p[pn["dir"]] = this.sortInfo.direction;
8945             }
8946             if (this.multiSort) {
8947                 var pn = this.paramNames;
8948                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8949             }
8950             
8951             this.proxy.load(p, this.reader, this.loadRecords, this, options);
8952         }
8953     },
8954
8955     /**
8956      * Reloads the Record cache from the configured Proxy using the configured Reader and
8957      * the options from the last load operation performed.
8958      * @param {Object} options (optional) An object containing properties which may override the options
8959      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8960      * the most recently used options are reused).
8961      */
8962     reload : function(options){
8963         this.load(Roo.applyIf(options||{}, this.lastOptions));
8964     },
8965
8966     // private
8967     // Called as a callback by the Reader during a load operation.
8968     loadRecords : function(o, options, success){
8969         if(!o || success === false){
8970             if(success !== false){
8971                 this.fireEvent("load", this, [], options, o);
8972             }
8973             if(options.callback){
8974                 options.callback.call(options.scope || this, [], options, false);
8975             }
8976             return;
8977         }
8978         // if data returned failure - throw an exception.
8979         if (o.success === false) {
8980             // show a message if no listener is registered.
8981             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8982                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8983             }
8984             // loadmask wil be hooked into this..
8985             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8986             return;
8987         }
8988         var r = o.records, t = o.totalRecords || r.length;
8989         
8990         this.fireEvent("beforeloadadd", this, r, options, o);
8991         
8992         if(!options || options.add !== true){
8993             if(this.pruneModifiedRecords){
8994                 this.modified = [];
8995             }
8996             for(var i = 0, len = r.length; i < len; i++){
8997                 r[i].join(this);
8998             }
8999             if(this.snapshot){
9000                 this.data = this.snapshot;
9001                 delete this.snapshot;
9002             }
9003             this.data.clear();
9004             this.data.addAll(r);
9005             this.totalLength = t;
9006             this.applySort();
9007             this.fireEvent("datachanged", this);
9008         }else{
9009             this.totalLength = Math.max(t, this.data.length+r.length);
9010             this.add(r);
9011         }
9012         this.fireEvent("load", this, r, options, o);
9013         if(options.callback){
9014             options.callback.call(options.scope || this, r, options, true);
9015         }
9016     },
9017
9018
9019     /**
9020      * Loads data from a passed data block. A Reader which understands the format of the data
9021      * must have been configured in the constructor.
9022      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9023      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9024      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9025      */
9026     loadData : function(o, append){
9027         var r = this.reader.readRecords(o);
9028         this.loadRecords(r, {add: append}, true);
9029     },
9030
9031     /**
9032      * Gets the number of cached records.
9033      * <p>
9034      * <em>If using paging, this may not be the total size of the dataset. If the data object
9035      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9036      * the data set size</em>
9037      */
9038     getCount : function(){
9039         return this.data.length || 0;
9040     },
9041
9042     /**
9043      * Gets the total number of records in the dataset as returned by the server.
9044      * <p>
9045      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9046      * the dataset size</em>
9047      */
9048     getTotalCount : function(){
9049         return this.totalLength || 0;
9050     },
9051
9052     /**
9053      * Returns the sort state of the Store as an object with two properties:
9054      * <pre><code>
9055  field {String} The name of the field by which the Records are sorted
9056  direction {String} The sort order, "ASC" or "DESC"
9057      * </code></pre>
9058      */
9059     getSortState : function(){
9060         return this.sortInfo;
9061     },
9062
9063     // private
9064     applySort : function(){
9065         if(this.sortInfo && !this.remoteSort){
9066             var s = this.sortInfo, f = s.field;
9067             var st = this.fields.get(f).sortType;
9068             var fn = function(r1, r2){
9069                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9070                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9071             };
9072             this.data.sort(s.direction, fn);
9073             if(this.snapshot && this.snapshot != this.data){
9074                 this.snapshot.sort(s.direction, fn);
9075             }
9076         }
9077     },
9078
9079     /**
9080      * Sets the default sort column and order to be used by the next load operation.
9081      * @param {String} fieldName The name of the field to sort by.
9082      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9083      */
9084     setDefaultSort : function(field, dir){
9085         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9086     },
9087
9088     /**
9089      * Sort the Records.
9090      * If remote sorting is used, the sort is performed on the server, and the cache is
9091      * reloaded. If local sorting is used, the cache is sorted internally.
9092      * @param {String} fieldName The name of the field to sort by.
9093      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9094      */
9095     sort : function(fieldName, dir){
9096         var f = this.fields.get(fieldName);
9097         if(!dir){
9098             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9099             
9100             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9101                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9102             }else{
9103                 dir = f.sortDir;
9104             }
9105         }
9106         this.sortToggle[f.name] = dir;
9107         this.sortInfo = {field: f.name, direction: dir};
9108         if(!this.remoteSort){
9109             this.applySort();
9110             this.fireEvent("datachanged", this);
9111         }else{
9112             this.load(this.lastOptions);
9113         }
9114     },
9115
9116     /**
9117      * Calls the specified function for each of the Records in the cache.
9118      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9119      * Returning <em>false</em> aborts and exits the iteration.
9120      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9121      */
9122     each : function(fn, scope){
9123         this.data.each(fn, scope);
9124     },
9125
9126     /**
9127      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9128      * (e.g., during paging).
9129      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9130      */
9131     getModifiedRecords : function(){
9132         return this.modified;
9133     },
9134
9135     // private
9136     createFilterFn : function(property, value, anyMatch){
9137         if(!value.exec){ // not a regex
9138             value = String(value);
9139             if(value.length == 0){
9140                 return false;
9141             }
9142             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9143         }
9144         return function(r){
9145             return value.test(r.data[property]);
9146         };
9147     },
9148
9149     /**
9150      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9151      * @param {String} property A field on your records
9152      * @param {Number} start The record index to start at (defaults to 0)
9153      * @param {Number} end The last record index to include (defaults to length - 1)
9154      * @return {Number} The sum
9155      */
9156     sum : function(property, start, end){
9157         var rs = this.data.items, v = 0;
9158         start = start || 0;
9159         end = (end || end === 0) ? end : rs.length-1;
9160
9161         for(var i = start; i <= end; i++){
9162             v += (rs[i].data[property] || 0);
9163         }
9164         return v;
9165     },
9166
9167     /**
9168      * Filter the records by a specified property.
9169      * @param {String} field A field on your records
9170      * @param {String/RegExp} value Either a string that the field
9171      * should start with or a RegExp to test against the field
9172      * @param {Boolean} anyMatch True to match any part not just the beginning
9173      */
9174     filter : function(property, value, anyMatch){
9175         var fn = this.createFilterFn(property, value, anyMatch);
9176         return fn ? this.filterBy(fn) : this.clearFilter();
9177     },
9178
9179     /**
9180      * Filter by a function. The specified function will be called with each
9181      * record in this data source. If the function returns true the record is included,
9182      * otherwise it is filtered.
9183      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9184      * @param {Object} scope (optional) The scope of the function (defaults to this)
9185      */
9186     filterBy : function(fn, scope){
9187         this.snapshot = this.snapshot || this.data;
9188         this.data = this.queryBy(fn, scope||this);
9189         this.fireEvent("datachanged", this);
9190     },
9191
9192     /**
9193      * Query the records by a specified property.
9194      * @param {String} field A field on your records
9195      * @param {String/RegExp} value Either a string that the field
9196      * should start with or a RegExp to test against the field
9197      * @param {Boolean} anyMatch True to match any part not just the beginning
9198      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9199      */
9200     query : function(property, value, anyMatch){
9201         var fn = this.createFilterFn(property, value, anyMatch);
9202         return fn ? this.queryBy(fn) : this.data.clone();
9203     },
9204
9205     /**
9206      * Query by a function. The specified function will be called with each
9207      * record in this data source. If the function returns true the record is included
9208      * in the results.
9209      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9210      * @param {Object} scope (optional) The scope of the function (defaults to this)
9211       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9212      **/
9213     queryBy : function(fn, scope){
9214         var data = this.snapshot || this.data;
9215         return data.filterBy(fn, scope||this);
9216     },
9217
9218     /**
9219      * Collects unique values for a particular dataIndex from this store.
9220      * @param {String} dataIndex The property to collect
9221      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9222      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9223      * @return {Array} An array of the unique values
9224      **/
9225     collect : function(dataIndex, allowNull, bypassFilter){
9226         var d = (bypassFilter === true && this.snapshot) ?
9227                 this.snapshot.items : this.data.items;
9228         var v, sv, r = [], l = {};
9229         for(var i = 0, len = d.length; i < len; i++){
9230             v = d[i].data[dataIndex];
9231             sv = String(v);
9232             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9233                 l[sv] = true;
9234                 r[r.length] = v;
9235             }
9236         }
9237         return r;
9238     },
9239
9240     /**
9241      * Revert to a view of the Record cache with no filtering applied.
9242      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9243      */
9244     clearFilter : function(suppressEvent){
9245         if(this.snapshot && this.snapshot != this.data){
9246             this.data = this.snapshot;
9247             delete this.snapshot;
9248             if(suppressEvent !== true){
9249                 this.fireEvent("datachanged", this);
9250             }
9251         }
9252     },
9253
9254     // private
9255     afterEdit : function(record){
9256         if(this.modified.indexOf(record) == -1){
9257             this.modified.push(record);
9258         }
9259         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9260     },
9261     
9262     // private
9263     afterReject : function(record){
9264         this.modified.remove(record);
9265         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9266     },
9267
9268     // private
9269     afterCommit : function(record){
9270         this.modified.remove(record);
9271         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9272     },
9273
9274     /**
9275      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9276      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9277      */
9278     commitChanges : function(){
9279         var m = this.modified.slice(0);
9280         this.modified = [];
9281         for(var i = 0, len = m.length; i < len; i++){
9282             m[i].commit();
9283         }
9284     },
9285
9286     /**
9287      * Cancel outstanding changes on all changed records.
9288      */
9289     rejectChanges : function(){
9290         var m = this.modified.slice(0);
9291         this.modified = [];
9292         for(var i = 0, len = m.length; i < len; i++){
9293             m[i].reject();
9294         }
9295     },
9296
9297     onMetaChange : function(meta, rtype, o){
9298         this.recordType = rtype;
9299         this.fields = rtype.prototype.fields;
9300         delete this.snapshot;
9301         this.sortInfo = meta.sortInfo || this.sortInfo;
9302         this.modified = [];
9303         this.fireEvent('metachange', this, this.reader.meta);
9304     },
9305     
9306     moveIndex : function(data, type)
9307     {
9308         var index = this.indexOf(data);
9309         
9310         var newIndex = index + type;
9311         
9312         this.remove(data);
9313         
9314         this.insert(newIndex, data);
9315         
9316     }
9317 });/*
9318  * Based on:
9319  * Ext JS Library 1.1.1
9320  * Copyright(c) 2006-2007, Ext JS, LLC.
9321  *
9322  * Originally Released Under LGPL - original licence link has changed is not relivant.
9323  *
9324  * Fork - LGPL
9325  * <script type="text/javascript">
9326  */
9327
9328 /**
9329  * @class Roo.data.SimpleStore
9330  * @extends Roo.data.Store
9331  * Small helper class to make creating Stores from Array data easier.
9332  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9333  * @cfg {Array} fields An array of field definition objects, or field name strings.
9334  * @cfg {Array} data The multi-dimensional array of data
9335  * @constructor
9336  * @param {Object} config
9337  */
9338 Roo.data.SimpleStore = function(config){
9339     Roo.data.SimpleStore.superclass.constructor.call(this, {
9340         isLocal : true,
9341         reader: new Roo.data.ArrayReader({
9342                 id: config.id
9343             },
9344             Roo.data.Record.create(config.fields)
9345         ),
9346         proxy : new Roo.data.MemoryProxy(config.data)
9347     });
9348     this.load();
9349 };
9350 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9351  * Based on:
9352  * Ext JS Library 1.1.1
9353  * Copyright(c) 2006-2007, Ext JS, LLC.
9354  *
9355  * Originally Released Under LGPL - original licence link has changed is not relivant.
9356  *
9357  * Fork - LGPL
9358  * <script type="text/javascript">
9359  */
9360
9361 /**
9362 /**
9363  * @extends Roo.data.Store
9364  * @class Roo.data.JsonStore
9365  * Small helper class to make creating Stores for JSON data easier. <br/>
9366 <pre><code>
9367 var store = new Roo.data.JsonStore({
9368     url: 'get-images.php',
9369     root: 'images',
9370     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9371 });
9372 </code></pre>
9373  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9374  * JsonReader and HttpProxy (unless inline data is provided).</b>
9375  * @cfg {Array} fields An array of field definition objects, or field name strings.
9376  * @constructor
9377  * @param {Object} config
9378  */
9379 Roo.data.JsonStore = function(c){
9380     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9381         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9382         reader: new Roo.data.JsonReader(c, c.fields)
9383     }));
9384 };
9385 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9386  * Based on:
9387  * Ext JS Library 1.1.1
9388  * Copyright(c) 2006-2007, Ext JS, LLC.
9389  *
9390  * Originally Released Under LGPL - original licence link has changed is not relivant.
9391  *
9392  * Fork - LGPL
9393  * <script type="text/javascript">
9394  */
9395
9396  
9397 Roo.data.Field = function(config){
9398     if(typeof config == "string"){
9399         config = {name: config};
9400     }
9401     Roo.apply(this, config);
9402     
9403     if(!this.type){
9404         this.type = "auto";
9405     }
9406     
9407     var st = Roo.data.SortTypes;
9408     // named sortTypes are supported, here we look them up
9409     if(typeof this.sortType == "string"){
9410         this.sortType = st[this.sortType];
9411     }
9412     
9413     // set default sortType for strings and dates
9414     if(!this.sortType){
9415         switch(this.type){
9416             case "string":
9417                 this.sortType = st.asUCString;
9418                 break;
9419             case "date":
9420                 this.sortType = st.asDate;
9421                 break;
9422             default:
9423                 this.sortType = st.none;
9424         }
9425     }
9426
9427     // define once
9428     var stripRe = /[\$,%]/g;
9429
9430     // prebuilt conversion function for this field, instead of
9431     // switching every time we're reading a value
9432     if(!this.convert){
9433         var cv, dateFormat = this.dateFormat;
9434         switch(this.type){
9435             case "":
9436             case "auto":
9437             case undefined:
9438                 cv = function(v){ return v; };
9439                 break;
9440             case "string":
9441                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9442                 break;
9443             case "int":
9444                 cv = function(v){
9445                     return v !== undefined && v !== null && v !== '' ?
9446                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9447                     };
9448                 break;
9449             case "float":
9450                 cv = function(v){
9451                     return v !== undefined && v !== null && v !== '' ?
9452                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9453                     };
9454                 break;
9455             case "bool":
9456             case "boolean":
9457                 cv = function(v){ return v === true || v === "true" || v == 1; };
9458                 break;
9459             case "date":
9460                 cv = function(v){
9461                     if(!v){
9462                         return '';
9463                     }
9464                     if(v instanceof Date){
9465                         return v;
9466                     }
9467                     if(dateFormat){
9468                         if(dateFormat == "timestamp"){
9469                             return new Date(v*1000);
9470                         }
9471                         return Date.parseDate(v, dateFormat);
9472                     }
9473                     var parsed = Date.parse(v);
9474                     return parsed ? new Date(parsed) : null;
9475                 };
9476              break;
9477             
9478         }
9479         this.convert = cv;
9480     }
9481 };
9482
9483 Roo.data.Field.prototype = {
9484     dateFormat: null,
9485     defaultValue: "",
9486     mapping: null,
9487     sortType : null,
9488     sortDir : "ASC"
9489 };/*
9490  * Based on:
9491  * Ext JS Library 1.1.1
9492  * Copyright(c) 2006-2007, Ext JS, LLC.
9493  *
9494  * Originally Released Under LGPL - original licence link has changed is not relivant.
9495  *
9496  * Fork - LGPL
9497  * <script type="text/javascript">
9498  */
9499  
9500 // Base class for reading structured data from a data source.  This class is intended to be
9501 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9502
9503 /**
9504  * @class Roo.data.DataReader
9505  * Base class for reading structured data from a data source.  This class is intended to be
9506  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9507  */
9508
9509 Roo.data.DataReader = function(meta, recordType){
9510     
9511     this.meta = meta;
9512     
9513     this.recordType = recordType instanceof Array ? 
9514         Roo.data.Record.create(recordType) : recordType;
9515 };
9516
9517 Roo.data.DataReader.prototype = {
9518      /**
9519      * Create an empty record
9520      * @param {Object} data (optional) - overlay some values
9521      * @return {Roo.data.Record} record created.
9522      */
9523     newRow :  function(d) {
9524         var da =  {};
9525         this.recordType.prototype.fields.each(function(c) {
9526             switch( c.type) {
9527                 case 'int' : da[c.name] = 0; break;
9528                 case 'date' : da[c.name] = new Date(); break;
9529                 case 'float' : da[c.name] = 0.0; break;
9530                 case 'boolean' : da[c.name] = false; break;
9531                 default : da[c.name] = ""; break;
9532             }
9533             
9534         });
9535         return new this.recordType(Roo.apply(da, d));
9536     }
9537     
9538 };/*
9539  * Based on:
9540  * Ext JS Library 1.1.1
9541  * Copyright(c) 2006-2007, Ext JS, LLC.
9542  *
9543  * Originally Released Under LGPL - original licence link has changed is not relivant.
9544  *
9545  * Fork - LGPL
9546  * <script type="text/javascript">
9547  */
9548
9549 /**
9550  * @class Roo.data.DataProxy
9551  * @extends Roo.data.Observable
9552  * This class is an abstract base class for implementations which provide retrieval of
9553  * unformatted data objects.<br>
9554  * <p>
9555  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9556  * (of the appropriate type which knows how to parse the data object) to provide a block of
9557  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9558  * <p>
9559  * Custom implementations must implement the load method as described in
9560  * {@link Roo.data.HttpProxy#load}.
9561  */
9562 Roo.data.DataProxy = function(){
9563     this.addEvents({
9564         /**
9565          * @event beforeload
9566          * Fires before a network request is made to retrieve a data object.
9567          * @param {Object} This DataProxy object.
9568          * @param {Object} params The params parameter to the load function.
9569          */
9570         beforeload : true,
9571         /**
9572          * @event load
9573          * Fires before the load method's callback is called.
9574          * @param {Object} This DataProxy object.
9575          * @param {Object} o The data object.
9576          * @param {Object} arg The callback argument object passed to the load function.
9577          */
9578         load : true,
9579         /**
9580          * @event loadexception
9581          * Fires if an Exception occurs during data retrieval.
9582          * @param {Object} This DataProxy object.
9583          * @param {Object} o The data object.
9584          * @param {Object} arg The callback argument object passed to the load function.
9585          * @param {Object} e The Exception.
9586          */
9587         loadexception : true
9588     });
9589     Roo.data.DataProxy.superclass.constructor.call(this);
9590 };
9591
9592 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9593
9594     /**
9595      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9596      */
9597 /*
9598  * Based on:
9599  * Ext JS Library 1.1.1
9600  * Copyright(c) 2006-2007, Ext JS, LLC.
9601  *
9602  * Originally Released Under LGPL - original licence link has changed is not relivant.
9603  *
9604  * Fork - LGPL
9605  * <script type="text/javascript">
9606  */
9607 /**
9608  * @class Roo.data.MemoryProxy
9609  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9610  * to the Reader when its load method is called.
9611  * @constructor
9612  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9613  */
9614 Roo.data.MemoryProxy = function(data){
9615     if (data.data) {
9616         data = data.data;
9617     }
9618     Roo.data.MemoryProxy.superclass.constructor.call(this);
9619     this.data = data;
9620 };
9621
9622 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9623     /**
9624      * Load data from the requested source (in this case an in-memory
9625      * data object passed to the constructor), read the data object into
9626      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9627      * process that block using the passed callback.
9628      * @param {Object} params This parameter is not used by the MemoryProxy class.
9629      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9630      * object into a block of Roo.data.Records.
9631      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9632      * The function must be passed <ul>
9633      * <li>The Record block object</li>
9634      * <li>The "arg" argument from the load function</li>
9635      * <li>A boolean success indicator</li>
9636      * </ul>
9637      * @param {Object} scope The scope in which to call the callback
9638      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9639      */
9640     load : function(params, reader, callback, scope, arg){
9641         params = params || {};
9642         var result;
9643         try {
9644             result = reader.readRecords(this.data);
9645         }catch(e){
9646             this.fireEvent("loadexception", this, arg, null, e);
9647             callback.call(scope, null, arg, false);
9648             return;
9649         }
9650         callback.call(scope, result, arg, true);
9651     },
9652     
9653     // private
9654     update : function(params, records){
9655         
9656     }
9657 });/*
9658  * Based on:
9659  * Ext JS Library 1.1.1
9660  * Copyright(c) 2006-2007, Ext JS, LLC.
9661  *
9662  * Originally Released Under LGPL - original licence link has changed is not relivant.
9663  *
9664  * Fork - LGPL
9665  * <script type="text/javascript">
9666  */
9667 /**
9668  * @class Roo.data.HttpProxy
9669  * @extends Roo.data.DataProxy
9670  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9671  * configured to reference a certain URL.<br><br>
9672  * <p>
9673  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9674  * from which the running page was served.<br><br>
9675  * <p>
9676  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9677  * <p>
9678  * Be aware that to enable the browser to parse an XML document, the server must set
9679  * the Content-Type header in the HTTP response to "text/xml".
9680  * @constructor
9681  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9682  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9683  * will be used to make the request.
9684  */
9685 Roo.data.HttpProxy = function(conn){
9686     Roo.data.HttpProxy.superclass.constructor.call(this);
9687     // is conn a conn config or a real conn?
9688     this.conn = conn;
9689     this.useAjax = !conn || !conn.events;
9690   
9691 };
9692
9693 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9694     // thse are take from connection...
9695     
9696     /**
9697      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9698      */
9699     /**
9700      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9701      * extra parameters to each request made by this object. (defaults to undefined)
9702      */
9703     /**
9704      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9705      *  to each request made by this object. (defaults to undefined)
9706      */
9707     /**
9708      * @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)
9709      */
9710     /**
9711      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9712      */
9713      /**
9714      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9715      * @type Boolean
9716      */
9717   
9718
9719     /**
9720      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9721      * @type Boolean
9722      */
9723     /**
9724      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9725      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9726      * a finer-grained basis than the DataProxy events.
9727      */
9728     getConnection : function(){
9729         return this.useAjax ? Roo.Ajax : this.conn;
9730     },
9731
9732     /**
9733      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9734      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9735      * process that block using the passed callback.
9736      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9737      * for the request to the remote server.
9738      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9739      * object into a block of Roo.data.Records.
9740      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9741      * The function must be passed <ul>
9742      * <li>The Record block object</li>
9743      * <li>The "arg" argument from the load function</li>
9744      * <li>A boolean success indicator</li>
9745      * </ul>
9746      * @param {Object} scope The scope in which to call the callback
9747      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9748      */
9749     load : function(params, reader, callback, scope, arg){
9750         if(this.fireEvent("beforeload", this, params) !== false){
9751             var  o = {
9752                 params : params || {},
9753                 request: {
9754                     callback : callback,
9755                     scope : scope,
9756                     arg : arg
9757                 },
9758                 reader: reader,
9759                 callback : this.loadResponse,
9760                 scope: this
9761             };
9762             if(this.useAjax){
9763                 Roo.applyIf(o, this.conn);
9764                 if(this.activeRequest){
9765                     Roo.Ajax.abort(this.activeRequest);
9766                 }
9767                 this.activeRequest = Roo.Ajax.request(o);
9768             }else{
9769                 this.conn.request(o);
9770             }
9771         }else{
9772             callback.call(scope||this, null, arg, false);
9773         }
9774     },
9775
9776     // private
9777     loadResponse : function(o, success, response){
9778         delete this.activeRequest;
9779         if(!success){
9780             this.fireEvent("loadexception", this, o, response);
9781             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9782             return;
9783         }
9784         var result;
9785         try {
9786             result = o.reader.read(response);
9787         }catch(e){
9788             this.fireEvent("loadexception", this, o, response, e);
9789             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9790             return;
9791         }
9792         
9793         this.fireEvent("load", this, o, o.request.arg);
9794         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9795     },
9796
9797     // private
9798     update : function(dataSet){
9799
9800     },
9801
9802     // private
9803     updateResponse : function(dataSet){
9804
9805     }
9806 });/*
9807  * Based on:
9808  * Ext JS Library 1.1.1
9809  * Copyright(c) 2006-2007, Ext JS, LLC.
9810  *
9811  * Originally Released Under LGPL - original licence link has changed is not relivant.
9812  *
9813  * Fork - LGPL
9814  * <script type="text/javascript">
9815  */
9816
9817 /**
9818  * @class Roo.data.ScriptTagProxy
9819  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9820  * other than the originating domain of the running page.<br><br>
9821  * <p>
9822  * <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
9823  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9824  * <p>
9825  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9826  * source code that is used as the source inside a &lt;script> tag.<br><br>
9827  * <p>
9828  * In order for the browser to process the returned data, the server must wrap the data object
9829  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9830  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9831  * depending on whether the callback name was passed:
9832  * <p>
9833  * <pre><code>
9834 boolean scriptTag = false;
9835 String cb = request.getParameter("callback");
9836 if (cb != null) {
9837     scriptTag = true;
9838     response.setContentType("text/javascript");
9839 } else {
9840     response.setContentType("application/x-json");
9841 }
9842 Writer out = response.getWriter();
9843 if (scriptTag) {
9844     out.write(cb + "(");
9845 }
9846 out.print(dataBlock.toJsonString());
9847 if (scriptTag) {
9848     out.write(");");
9849 }
9850 </pre></code>
9851  *
9852  * @constructor
9853  * @param {Object} config A configuration object.
9854  */
9855 Roo.data.ScriptTagProxy = function(config){
9856     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9857     Roo.apply(this, config);
9858     this.head = document.getElementsByTagName("head")[0];
9859 };
9860
9861 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9862
9863 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9864     /**
9865      * @cfg {String} url The URL from which to request the data object.
9866      */
9867     /**
9868      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9869      */
9870     timeout : 30000,
9871     /**
9872      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9873      * the server the name of the callback function set up by the load call to process the returned data object.
9874      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9875      * javascript output which calls this named function passing the data object as its only parameter.
9876      */
9877     callbackParam : "callback",
9878     /**
9879      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9880      * name to the request.
9881      */
9882     nocache : true,
9883
9884     /**
9885      * Load data from the configured URL, read the data object into
9886      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9887      * process that block using the passed callback.
9888      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9889      * for the request to the remote server.
9890      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9891      * object into a block of Roo.data.Records.
9892      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9893      * The function must be passed <ul>
9894      * <li>The Record block object</li>
9895      * <li>The "arg" argument from the load function</li>
9896      * <li>A boolean success indicator</li>
9897      * </ul>
9898      * @param {Object} scope The scope in which to call the callback
9899      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9900      */
9901     load : function(params, reader, callback, scope, arg){
9902         if(this.fireEvent("beforeload", this, params) !== false){
9903
9904             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9905
9906             var url = this.url;
9907             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9908             if(this.nocache){
9909                 url += "&_dc=" + (new Date().getTime());
9910             }
9911             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9912             var trans = {
9913                 id : transId,
9914                 cb : "stcCallback"+transId,
9915                 scriptId : "stcScript"+transId,
9916                 params : params,
9917                 arg : arg,
9918                 url : url,
9919                 callback : callback,
9920                 scope : scope,
9921                 reader : reader
9922             };
9923             var conn = this;
9924
9925             window[trans.cb] = function(o){
9926                 conn.handleResponse(o, trans);
9927             };
9928
9929             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9930
9931             if(this.autoAbort !== false){
9932                 this.abort();
9933             }
9934
9935             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9936
9937             var script = document.createElement("script");
9938             script.setAttribute("src", url);
9939             script.setAttribute("type", "text/javascript");
9940             script.setAttribute("id", trans.scriptId);
9941             this.head.appendChild(script);
9942
9943             this.trans = trans;
9944         }else{
9945             callback.call(scope||this, null, arg, false);
9946         }
9947     },
9948
9949     // private
9950     isLoading : function(){
9951         return this.trans ? true : false;
9952     },
9953
9954     /**
9955      * Abort the current server request.
9956      */
9957     abort : function(){
9958         if(this.isLoading()){
9959             this.destroyTrans(this.trans);
9960         }
9961     },
9962
9963     // private
9964     destroyTrans : function(trans, isLoaded){
9965         this.head.removeChild(document.getElementById(trans.scriptId));
9966         clearTimeout(trans.timeoutId);
9967         if(isLoaded){
9968             window[trans.cb] = undefined;
9969             try{
9970                 delete window[trans.cb];
9971             }catch(e){}
9972         }else{
9973             // if hasn't been loaded, wait for load to remove it to prevent script error
9974             window[trans.cb] = function(){
9975                 window[trans.cb] = undefined;
9976                 try{
9977                     delete window[trans.cb];
9978                 }catch(e){}
9979             };
9980         }
9981     },
9982
9983     // private
9984     handleResponse : function(o, trans){
9985         this.trans = false;
9986         this.destroyTrans(trans, true);
9987         var result;
9988         try {
9989             result = trans.reader.readRecords(o);
9990         }catch(e){
9991             this.fireEvent("loadexception", this, o, trans.arg, e);
9992             trans.callback.call(trans.scope||window, null, trans.arg, false);
9993             return;
9994         }
9995         this.fireEvent("load", this, o, trans.arg);
9996         trans.callback.call(trans.scope||window, result, trans.arg, true);
9997     },
9998
9999     // private
10000     handleFailure : function(trans){
10001         this.trans = false;
10002         this.destroyTrans(trans, false);
10003         this.fireEvent("loadexception", this, null, trans.arg);
10004         trans.callback.call(trans.scope||window, null, trans.arg, false);
10005     }
10006 });/*
10007  * Based on:
10008  * Ext JS Library 1.1.1
10009  * Copyright(c) 2006-2007, Ext JS, LLC.
10010  *
10011  * Originally Released Under LGPL - original licence link has changed is not relivant.
10012  *
10013  * Fork - LGPL
10014  * <script type="text/javascript">
10015  */
10016
10017 /**
10018  * @class Roo.data.JsonReader
10019  * @extends Roo.data.DataReader
10020  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10021  * based on mappings in a provided Roo.data.Record constructor.
10022  * 
10023  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10024  * in the reply previously. 
10025  * 
10026  * <p>
10027  * Example code:
10028  * <pre><code>
10029 var RecordDef = Roo.data.Record.create([
10030     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10031     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10032 ]);
10033 var myReader = new Roo.data.JsonReader({
10034     totalProperty: "results",    // The property which contains the total dataset size (optional)
10035     root: "rows",                // The property which contains an Array of row objects
10036     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10037 }, RecordDef);
10038 </code></pre>
10039  * <p>
10040  * This would consume a JSON file like this:
10041  * <pre><code>
10042 { 'results': 2, 'rows': [
10043     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10044     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10045 }
10046 </code></pre>
10047  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10048  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10049  * paged from the remote server.
10050  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10051  * @cfg {String} root name of the property which contains the Array of row objects.
10052  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10053  * @constructor
10054  * Create a new JsonReader
10055  * @param {Object} meta Metadata configuration options
10056  * @param {Object} recordType Either an Array of field definition objects,
10057  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10058  */
10059 Roo.data.JsonReader = function(meta, recordType){
10060     
10061     meta = meta || {};
10062     // set some defaults:
10063     Roo.applyIf(meta, {
10064         totalProperty: 'total',
10065         successProperty : 'success',
10066         root : 'data',
10067         id : 'id'
10068     });
10069     
10070     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10071 };
10072 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10073     
10074     /**
10075      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10076      * Used by Store query builder to append _requestMeta to params.
10077      * 
10078      */
10079     metaFromRemote : false,
10080     /**
10081      * This method is only used by a DataProxy which has retrieved data from a remote server.
10082      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10083      * @return {Object} data A data block which is used by an Roo.data.Store object as
10084      * a cache of Roo.data.Records.
10085      */
10086     read : function(response){
10087         var json = response.responseText;
10088        
10089         var o = /* eval:var:o */ eval("("+json+")");
10090         if(!o) {
10091             throw {message: "JsonReader.read: Json object not found"};
10092         }
10093         
10094         if(o.metaData){
10095             
10096             delete this.ef;
10097             this.metaFromRemote = true;
10098             this.meta = o.metaData;
10099             this.recordType = Roo.data.Record.create(o.metaData.fields);
10100             this.onMetaChange(this.meta, this.recordType, o);
10101         }
10102         return this.readRecords(o);
10103     },
10104
10105     // private function a store will implement
10106     onMetaChange : function(meta, recordType, o){
10107
10108     },
10109
10110     /**
10111          * @ignore
10112          */
10113     simpleAccess: function(obj, subsc) {
10114         return obj[subsc];
10115     },
10116
10117         /**
10118          * @ignore
10119          */
10120     getJsonAccessor: function(){
10121         var re = /[\[\.]/;
10122         return function(expr) {
10123             try {
10124                 return(re.test(expr))
10125                     ? new Function("obj", "return obj." + expr)
10126                     : function(obj){
10127                         return obj[expr];
10128                     };
10129             } catch(e){}
10130             return Roo.emptyFn;
10131         };
10132     }(),
10133
10134     /**
10135      * Create a data block containing Roo.data.Records from an XML document.
10136      * @param {Object} o An object which contains an Array of row objects in the property specified
10137      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10138      * which contains the total size of the dataset.
10139      * @return {Object} data A data block which is used by an Roo.data.Store object as
10140      * a cache of Roo.data.Records.
10141      */
10142     readRecords : function(o){
10143         /**
10144          * After any data loads, the raw JSON data is available for further custom processing.
10145          * @type Object
10146          */
10147         this.o = o;
10148         var s = this.meta, Record = this.recordType,
10149             f = Record.prototype.fields, fi = f.items, fl = f.length;
10150
10151 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10152         if (!this.ef) {
10153             if(s.totalProperty) {
10154                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10155                 }
10156                 if(s.successProperty) {
10157                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10158                 }
10159                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10160                 if (s.id) {
10161                         var g = this.getJsonAccessor(s.id);
10162                         this.getId = function(rec) {
10163                                 var r = g(rec);  
10164                                 return (r === undefined || r === "") ? null : r;
10165                         };
10166                 } else {
10167                         this.getId = function(){return null;};
10168                 }
10169             this.ef = [];
10170             for(var jj = 0; jj < fl; jj++){
10171                 f = fi[jj];
10172                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10173                 this.ef[jj] = this.getJsonAccessor(map);
10174             }
10175         }
10176
10177         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10178         if(s.totalProperty){
10179             var vt = parseInt(this.getTotal(o), 10);
10180             if(!isNaN(vt)){
10181                 totalRecords = vt;
10182             }
10183         }
10184         if(s.successProperty){
10185             var vs = this.getSuccess(o);
10186             if(vs === false || vs === 'false'){
10187                 success = false;
10188             }
10189         }
10190         var records = [];
10191             for(var i = 0; i < c; i++){
10192                     var n = root[i];
10193                 var values = {};
10194                 var id = this.getId(n);
10195                 for(var j = 0; j < fl; j++){
10196                     f = fi[j];
10197                 var v = this.ef[j](n);
10198                 if (!f.convert) {
10199                     Roo.log('missing convert for ' + f.name);
10200                     Roo.log(f);
10201                     continue;
10202                 }
10203                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10204                 }
10205                 var record = new Record(values, id);
10206                 record.json = n;
10207                 records[i] = record;
10208             }
10209             return {
10210             raw : o,
10211                 success : success,
10212                 records : records,
10213                 totalRecords : totalRecords
10214             };
10215     }
10216 });/*
10217  * Based on:
10218  * Ext JS Library 1.1.1
10219  * Copyright(c) 2006-2007, Ext JS, LLC.
10220  *
10221  * Originally Released Under LGPL - original licence link has changed is not relivant.
10222  *
10223  * Fork - LGPL
10224  * <script type="text/javascript">
10225  */
10226
10227 /**
10228  * @class Roo.data.ArrayReader
10229  * @extends Roo.data.DataReader
10230  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10231  * Each element of that Array represents a row of data fields. The
10232  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10233  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10234  * <p>
10235  * Example code:.
10236  * <pre><code>
10237 var RecordDef = Roo.data.Record.create([
10238     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10239     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10240 ]);
10241 var myReader = new Roo.data.ArrayReader({
10242     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10243 }, RecordDef);
10244 </code></pre>
10245  * <p>
10246  * This would consume an Array like this:
10247  * <pre><code>
10248 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10249   </code></pre>
10250  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10251  * @constructor
10252  * Create a new JsonReader
10253  * @param {Object} meta Metadata configuration options.
10254  * @param {Object} recordType Either an Array of field definition objects
10255  * as specified to {@link Roo.data.Record#create},
10256  * or an {@link Roo.data.Record} object
10257  * created using {@link Roo.data.Record#create}.
10258  */
10259 Roo.data.ArrayReader = function(meta, recordType){
10260     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10261 };
10262
10263 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10264     /**
10265      * Create a data block containing Roo.data.Records from an XML document.
10266      * @param {Object} o An Array of row objects which represents the dataset.
10267      * @return {Object} data A data block which is used by an Roo.data.Store object as
10268      * a cache of Roo.data.Records.
10269      */
10270     readRecords : function(o){
10271         var sid = this.meta ? this.meta.id : null;
10272         var recordType = this.recordType, fields = recordType.prototype.fields;
10273         var records = [];
10274         var root = o;
10275             for(var i = 0; i < root.length; i++){
10276                     var n = root[i];
10277                 var values = {};
10278                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10279                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10280                 var f = fields.items[j];
10281                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10282                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10283                 v = f.convert(v);
10284                 values[f.name] = v;
10285             }
10286                 var record = new recordType(values, id);
10287                 record.json = n;
10288                 records[records.length] = record;
10289             }
10290             return {
10291                 records : records,
10292                 totalRecords : records.length
10293             };
10294     }
10295 });/*
10296  * - LGPL
10297  * * 
10298  */
10299
10300 /**
10301  * @class Roo.bootstrap.ComboBox
10302  * @extends Roo.bootstrap.TriggerField
10303  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10304  * @cfg {Boolean} append (true|false) default false
10305  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10306  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10307  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10308  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10309  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10310  * @constructor
10311  * Create a new ComboBox.
10312  * @param {Object} config Configuration options
10313  */
10314 Roo.bootstrap.ComboBox = function(config){
10315     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10316     this.addEvents({
10317         /**
10318          * @event expand
10319          * Fires when the dropdown list is expanded
10320              * @param {Roo.bootstrap.ComboBox} combo This combo box
10321              */
10322         'expand' : true,
10323         /**
10324          * @event collapse
10325          * Fires when the dropdown list is collapsed
10326              * @param {Roo.bootstrap.ComboBox} combo This combo box
10327              */
10328         'collapse' : true,
10329         /**
10330          * @event beforeselect
10331          * Fires before a list item is selected. Return false to cancel the selection.
10332              * @param {Roo.bootstrap.ComboBox} combo This combo box
10333              * @param {Roo.data.Record} record The data record returned from the underlying store
10334              * @param {Number} index The index of the selected item in the dropdown list
10335              */
10336         'beforeselect' : true,
10337         /**
10338          * @event select
10339          * Fires when a list item is selected
10340              * @param {Roo.bootstrap.ComboBox} combo This combo box
10341              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10342              * @param {Number} index The index of the selected item in the dropdown list
10343              */
10344         'select' : true,
10345         /**
10346          * @event beforequery
10347          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10348          * The event object passed has these properties:
10349              * @param {Roo.bootstrap.ComboBox} combo This combo box
10350              * @param {String} query The query
10351              * @param {Boolean} forceAll true to force "all" query
10352              * @param {Boolean} cancel true to cancel the query
10353              * @param {Object} e The query event object
10354              */
10355         'beforequery': true,
10356          /**
10357          * @event add
10358          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10359              * @param {Roo.bootstrap.ComboBox} combo This combo box
10360              */
10361         'add' : true,
10362         /**
10363          * @event edit
10364          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10365              * @param {Roo.bootstrap.ComboBox} combo This combo box
10366              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10367              */
10368         'edit' : true,
10369         /**
10370          * @event remove
10371          * Fires when the remove value from the combobox array
10372              * @param {Roo.bootstrap.ComboBox} combo This combo box
10373              */
10374         'remove' : true
10375         
10376     });
10377     
10378     this.item = [];
10379     this.tickItems = [];
10380     
10381     this.selectedIndex = -1;
10382     if(this.mode == 'local'){
10383         if(config.queryDelay === undefined){
10384             this.queryDelay = 10;
10385         }
10386         if(config.minChars === undefined){
10387             this.minChars = 0;
10388         }
10389     }
10390 };
10391
10392 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10393      
10394     /**
10395      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10396      * rendering into an Roo.Editor, defaults to false)
10397      */
10398     /**
10399      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10400      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10401      */
10402     /**
10403      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10404      */
10405     /**
10406      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10407      * the dropdown list (defaults to undefined, with no header element)
10408      */
10409
10410      /**
10411      * @cfg {String/Roo.Template} tpl The template to use to render the output
10412      */
10413      
10414      /**
10415      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10416      */
10417     listWidth: undefined,
10418     /**
10419      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10420      * mode = 'remote' or 'text' if mode = 'local')
10421      */
10422     displayField: undefined,
10423     /**
10424      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10425      * mode = 'remote' or 'value' if mode = 'local'). 
10426      * Note: use of a valueField requires the user make a selection
10427      * in order for a value to be mapped.
10428      */
10429     valueField: undefined,
10430     
10431     
10432     /**
10433      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10434      * field's data value (defaults to the underlying DOM element's name)
10435      */
10436     hiddenName: undefined,
10437     /**
10438      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10439      */
10440     listClass: '',
10441     /**
10442      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10443      */
10444     selectedClass: 'active',
10445     
10446     /**
10447      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10448      */
10449     shadow:'sides',
10450     /**
10451      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10452      * anchor positions (defaults to 'tl-bl')
10453      */
10454     listAlign: 'tl-bl?',
10455     /**
10456      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10457      */
10458     maxHeight: 300,
10459     /**
10460      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10461      * query specified by the allQuery config option (defaults to 'query')
10462      */
10463     triggerAction: 'query',
10464     /**
10465      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10466      * (defaults to 4, does not apply if editable = false)
10467      */
10468     minChars : 4,
10469     /**
10470      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10471      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10472      */
10473     typeAhead: false,
10474     /**
10475      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10476      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10477      */
10478     queryDelay: 500,
10479     /**
10480      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10481      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10482      */
10483     pageSize: 0,
10484     /**
10485      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10486      * when editable = true (defaults to false)
10487      */
10488     selectOnFocus:false,
10489     /**
10490      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10491      */
10492     queryParam: 'query',
10493     /**
10494      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10495      * when mode = 'remote' (defaults to 'Loading...')
10496      */
10497     loadingText: 'Loading...',
10498     /**
10499      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10500      */
10501     resizable: false,
10502     /**
10503      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10504      */
10505     handleHeight : 8,
10506     /**
10507      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10508      * traditional select (defaults to true)
10509      */
10510     editable: true,
10511     /**
10512      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10513      */
10514     allQuery: '',
10515     /**
10516      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10517      */
10518     mode: 'remote',
10519     /**
10520      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10521      * listWidth has a higher value)
10522      */
10523     minListWidth : 70,
10524     /**
10525      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10526      * allow the user to set arbitrary text into the field (defaults to false)
10527      */
10528     forceSelection:false,
10529     /**
10530      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10531      * if typeAhead = true (defaults to 250)
10532      */
10533     typeAheadDelay : 250,
10534     /**
10535      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10536      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10537      */
10538     valueNotFoundText : undefined,
10539     /**
10540      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10541      */
10542     blockFocus : false,
10543     
10544     /**
10545      * @cfg {Boolean} disableClear Disable showing of clear button.
10546      */
10547     disableClear : false,
10548     /**
10549      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10550      */
10551     alwaysQuery : false,
10552     
10553     /**
10554      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10555      */
10556     multiple : false,
10557     
10558     //private
10559     addicon : false,
10560     editicon: false,
10561     
10562     page: 0,
10563     hasQuery: false,
10564     append: false,
10565     loadNext: false,
10566     autoFocus : true,
10567     tickable : false,
10568     btnPosition : 'right',
10569     triggerList : true,
10570     showToggleBtn : true,
10571     // element that contains real text value.. (when hidden is used..)
10572     
10573     getAutoCreate : function()
10574     {
10575         var cfg = false;
10576         
10577         /*
10578          *  Normal ComboBox
10579          */
10580         if(!this.tickable){
10581             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10582             return cfg;
10583         }
10584         
10585         /*
10586          *  ComboBox with tickable selections
10587          */
10588              
10589         var align = this.labelAlign || this.parentLabelAlign();
10590         
10591         cfg = {
10592             cls : 'form-group roo-combobox-tickable' //input-group
10593         };
10594         
10595         
10596         var buttons = {
10597             tag : 'div',
10598             cls : 'tickable-buttons',
10599             cn : [
10600                 {
10601                     tag : 'button',
10602                     type : 'button',
10603                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10604                     html : 'Edit'
10605                 },
10606                 {
10607                     tag : 'button',
10608                     type : 'button',
10609                     name : 'ok',
10610                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10611                     html : 'Done'
10612                 },
10613                 {
10614                     tag : 'button',
10615                     type : 'button',
10616                     name : 'cancel',
10617                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10618                     html : 'Cancel'
10619                 }
10620             ]
10621         };
10622         
10623         var _this = this;
10624         Roo.each(buttons.cn, function(c){
10625             if (_this.size) {
10626                 c.cls += ' btn-' + _this.size;
10627             }
10628
10629             if (_this.disabled) {
10630                 c.disabled = true;
10631             }
10632         });
10633         
10634         var box = {
10635             tag: 'div',
10636             cn: [
10637                 {
10638                     tag: 'input',
10639                     type : 'hidden',
10640                     cls: 'form-hidden-field'
10641                 },
10642                 {
10643                     tag: 'ul',
10644                     cls: 'select2-choices',
10645                     cn:[
10646                         {
10647                             tag: 'li',
10648                             cls: 'select2-search-field',
10649                             cn: [
10650
10651                                 buttons
10652                             ]
10653                         }
10654                     ]
10655                 }
10656             ]
10657         }
10658         
10659         var combobox = {
10660             cls: 'select2-container input-group select2-container-multi',
10661             cn: [
10662                 box
10663 //                {
10664 //                    tag: 'ul',
10665 //                    cls: 'typeahead typeahead-long dropdown-menu',
10666 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
10667 //                }
10668             ]
10669         };
10670         
10671         if (align ==='left' && this.fieldLabel.length) {
10672             
10673                 Roo.log("left and has label");
10674                 cfg.cn = [
10675                     
10676                     {
10677                         tag: 'label',
10678                         'for' :  id,
10679                         cls : 'control-label col-sm-' + this.labelWidth,
10680                         html : this.fieldLabel
10681                         
10682                     },
10683                     {
10684                         cls : "col-sm-" + (12 - this.labelWidth), 
10685                         cn: [
10686                             combobox
10687                         ]
10688                     }
10689                     
10690                 ];
10691         } else if ( this.fieldLabel.length) {
10692                 Roo.log(" label");
10693                  cfg.cn = [
10694                    
10695                     {
10696                         tag: 'label',
10697                         //cls : 'input-group-addon',
10698                         html : this.fieldLabel
10699                         
10700                     },
10701                     
10702                     combobox
10703                     
10704                 ];
10705
10706         } else {
10707             
10708                 Roo.log(" no label && no align");
10709                 cfg = combobox
10710                      
10711                 
10712         }
10713          
10714         var settings=this;
10715         ['xs','sm','md','lg'].map(function(size){
10716             if (settings[size]) {
10717                 cfg.cls += ' col-' + size + '-' + settings[size];
10718             }
10719         });
10720         
10721         return cfg;
10722         
10723     },
10724     
10725     // private
10726     initEvents: function()
10727     {
10728         
10729         if (!this.store) {
10730             throw "can not find store for combo";
10731         }
10732         this.store = Roo.factory(this.store, Roo.data);
10733         
10734         if(this.tickable){
10735             this.initTickableEvents();
10736             return;
10737         }
10738         
10739         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10740         
10741         if(this.hiddenName){
10742             
10743             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10744             
10745             this.hiddenField.dom.value =
10746                 this.hiddenValue !== undefined ? this.hiddenValue :
10747                 this.value !== undefined ? this.value : '';
10748
10749             // prevent input submission
10750             this.el.dom.removeAttribute('name');
10751             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10752              
10753              
10754         }
10755         //if(Roo.isGecko){
10756         //    this.el.dom.setAttribute('autocomplete', 'off');
10757         //}
10758         
10759         var cls = 'x-combo-list';
10760         
10761         //this.list = new Roo.Layer({
10762         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10763         //});
10764         
10765         var _this = this;
10766         
10767         (function(){
10768             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10769             _this.list.setWidth(lw);
10770         }).defer(100);
10771         
10772         this.list.on('mouseover', this.onViewOver, this);
10773         this.list.on('mousemove', this.onViewMove, this);
10774         
10775         this.list.on('scroll', this.onViewScroll, this);
10776         
10777         /*
10778         this.list.swallowEvent('mousewheel');
10779         this.assetHeight = 0;
10780
10781         if(this.title){
10782             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10783             this.assetHeight += this.header.getHeight();
10784         }
10785
10786         this.innerList = this.list.createChild({cls:cls+'-inner'});
10787         this.innerList.on('mouseover', this.onViewOver, this);
10788         this.innerList.on('mousemove', this.onViewMove, this);
10789         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10790         
10791         if(this.allowBlank && !this.pageSize && !this.disableClear){
10792             this.footer = this.list.createChild({cls:cls+'-ft'});
10793             this.pageTb = new Roo.Toolbar(this.footer);
10794            
10795         }
10796         if(this.pageSize){
10797             this.footer = this.list.createChild({cls:cls+'-ft'});
10798             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10799                     {pageSize: this.pageSize});
10800             
10801         }
10802         
10803         if (this.pageTb && this.allowBlank && !this.disableClear) {
10804             var _this = this;
10805             this.pageTb.add(new Roo.Toolbar.Fill(), {
10806                 cls: 'x-btn-icon x-btn-clear',
10807                 text: '&#160;',
10808                 handler: function()
10809                 {
10810                     _this.collapse();
10811                     _this.clearValue();
10812                     _this.onSelect(false, -1);
10813                 }
10814             });
10815         }
10816         if (this.footer) {
10817             this.assetHeight += this.footer.getHeight();
10818         }
10819         */
10820             
10821         if(!this.tpl){
10822             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10823         }
10824
10825         this.view = new Roo.View(this.list, this.tpl, {
10826             singleSelect:true, store: this.store, selectedClass: this.selectedClass
10827         });
10828         //this.view.wrapEl.setDisplayed(false);
10829         this.view.on('click', this.onViewClick, this);
10830         
10831         
10832         
10833         this.store.on('beforeload', this.onBeforeLoad, this);
10834         this.store.on('load', this.onLoad, this);
10835         this.store.on('loadexception', this.onLoadException, this);
10836         /*
10837         if(this.resizable){
10838             this.resizer = new Roo.Resizable(this.list,  {
10839                pinned:true, handles:'se'
10840             });
10841             this.resizer.on('resize', function(r, w, h){
10842                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10843                 this.listWidth = w;
10844                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10845                 this.restrictHeight();
10846             }, this);
10847             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10848         }
10849         */
10850         if(!this.editable){
10851             this.editable = true;
10852             this.setEditable(false);
10853         }
10854         
10855         /*
10856         
10857         if (typeof(this.events.add.listeners) != 'undefined') {
10858             
10859             this.addicon = this.wrap.createChild(
10860                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
10861        
10862             this.addicon.on('click', function(e) {
10863                 this.fireEvent('add', this);
10864             }, this);
10865         }
10866         if (typeof(this.events.edit.listeners) != 'undefined') {
10867             
10868             this.editicon = this.wrap.createChild(
10869                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
10870             if (this.addicon) {
10871                 this.editicon.setStyle('margin-left', '40px');
10872             }
10873             this.editicon.on('click', function(e) {
10874                 
10875                 // we fire even  if inothing is selected..
10876                 this.fireEvent('edit', this, this.lastData );
10877                 
10878             }, this);
10879         }
10880         */
10881         
10882         this.keyNav = new Roo.KeyNav(this.inputEl(), {
10883             "up" : function(e){
10884                 this.inKeyMode = true;
10885                 this.selectPrev();
10886             },
10887
10888             "down" : function(e){
10889                 if(!this.isExpanded()){
10890                     this.onTriggerClick();
10891                 }else{
10892                     this.inKeyMode = true;
10893                     this.selectNext();
10894                 }
10895             },
10896
10897             "enter" : function(e){
10898 //                this.onViewClick();
10899                 //return true;
10900                 this.collapse();
10901                 
10902                 if(this.fireEvent("specialkey", this, e)){
10903                     this.onViewClick(false);
10904                 }
10905                 
10906                 return true;
10907             },
10908
10909             "esc" : function(e){
10910                 this.collapse();
10911             },
10912
10913             "tab" : function(e){
10914                 this.collapse();
10915                 
10916                 if(this.fireEvent("specialkey", this, e)){
10917                     this.onViewClick(false);
10918                 }
10919                 
10920                 return true;
10921             },
10922
10923             scope : this,
10924
10925             doRelay : function(foo, bar, hname){
10926                 if(hname == 'down' || this.scope.isExpanded()){
10927                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10928                 }
10929                 return true;
10930             },
10931
10932             forceKeyDown: true
10933         });
10934         
10935         
10936         this.queryDelay = Math.max(this.queryDelay || 10,
10937                 this.mode == 'local' ? 10 : 250);
10938         
10939         
10940         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10941         
10942         if(this.typeAhead){
10943             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10944         }
10945         if(this.editable !== false){
10946             this.inputEl().on("keyup", this.onKeyUp, this);
10947         }
10948         if(this.forceSelection){
10949             this.inputEl().on('blur', this.doForce, this);
10950         }
10951         
10952         if(this.multiple){
10953             this.choices = this.el.select('ul.select2-choices', true).first();
10954             this.searchField = this.el.select('ul li.select2-search-field', true).first();
10955         }
10956     },
10957     
10958     initTickableEvents: function()
10959     {   
10960         this.createList();
10961         
10962         if(this.hiddenName){
10963             
10964             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10965             
10966             this.hiddenField.dom.value =
10967                 this.hiddenValue !== undefined ? this.hiddenValue :
10968                 this.value !== undefined ? this.value : '';
10969
10970             // prevent input submission
10971             this.el.dom.removeAttribute('name');
10972             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10973              
10974              
10975         }
10976         
10977 //        this.list = this.el.select('ul.dropdown-menu',true).first();
10978         
10979         this.choices = this.el.select('ul.select2-choices', true).first();
10980         this.searchField = this.el.select('ul li.select2-search-field', true).first();
10981         if(this.triggerList){
10982             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
10983         }
10984          
10985         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10986         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
10987         
10988         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10989         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10990         
10991         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10992         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10993         
10994         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10995         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10996         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10997         
10998         this.okBtn.hide();
10999         this.cancelBtn.hide();
11000         
11001         var _this = this;
11002         
11003         (function(){
11004             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11005             _this.list.setWidth(lw);
11006         }).defer(100);
11007         
11008         this.list.on('mouseover', this.onViewOver, this);
11009         this.list.on('mousemove', this.onViewMove, this);
11010         
11011         this.list.on('scroll', this.onViewScroll, this);
11012         
11013         if(!this.tpl){
11014             this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11015         }
11016
11017         this.view = new Roo.View(this.list, this.tpl, {
11018             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11019         });
11020         
11021         //this.view.wrapEl.setDisplayed(false);
11022         this.view.on('click', this.onViewClick, this);
11023         
11024         
11025         
11026         this.store.on('beforeload', this.onBeforeLoad, this);
11027         this.store.on('load', this.onLoad, this);
11028         this.store.on('loadexception', this.onLoadException, this);
11029         
11030 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11031 //            "up" : function(e){
11032 //                this.inKeyMode = true;
11033 //                this.selectPrev();
11034 //            },
11035 //
11036 //            "down" : function(e){
11037 //                if(!this.isExpanded()){
11038 //                    this.onTriggerClick();
11039 //                }else{
11040 //                    this.inKeyMode = true;
11041 //                    this.selectNext();
11042 //                }
11043 //            },
11044 //
11045 //            "enter" : function(e){
11046 ////                this.onViewClick();
11047 //                //return true;
11048 //                this.collapse();
11049 //                
11050 //                if(this.fireEvent("specialkey", this, e)){
11051 //                    this.onViewClick(false);
11052 //                }
11053 //                
11054 //                return true;
11055 //            },
11056 //
11057 //            "esc" : function(e){
11058 //                this.collapse();
11059 //            },
11060 //
11061 //            "tab" : function(e){
11062 //                this.collapse();
11063 //                
11064 //                if(this.fireEvent("specialkey", this, e)){
11065 //                    this.onViewClick(false);
11066 //                }
11067 //                
11068 //                return true;
11069 //            },
11070 //
11071 //            scope : this,
11072 //
11073 //            doRelay : function(foo, bar, hname){
11074 //                if(hname == 'down' || this.scope.isExpanded()){
11075 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11076 //                }
11077 //                return true;
11078 //            },
11079 //
11080 //            forceKeyDown: true
11081 //        });
11082         
11083         
11084         this.queryDelay = Math.max(this.queryDelay || 10,
11085                 this.mode == 'local' ? 10 : 250);
11086         
11087         
11088         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11089         
11090         if(this.typeAhead){
11091             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11092         }
11093     },
11094
11095     onDestroy : function(){
11096         if(this.view){
11097             this.view.setStore(null);
11098             this.view.el.removeAllListeners();
11099             this.view.el.remove();
11100             this.view.purgeListeners();
11101         }
11102         if(this.list){
11103             this.list.dom.innerHTML  = '';
11104         }
11105         
11106         if(this.store){
11107             this.store.un('beforeload', this.onBeforeLoad, this);
11108             this.store.un('load', this.onLoad, this);
11109             this.store.un('loadexception', this.onLoadException, this);
11110         }
11111         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11112     },
11113
11114     // private
11115     fireKey : function(e){
11116         if(e.isNavKeyPress() && !this.list.isVisible()){
11117             this.fireEvent("specialkey", this, e);
11118         }
11119     },
11120
11121     // private
11122     onResize: function(w, h){
11123 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11124 //        
11125 //        if(typeof w != 'number'){
11126 //            // we do not handle it!?!?
11127 //            return;
11128 //        }
11129 //        var tw = this.trigger.getWidth();
11130 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11131 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11132 //        var x = w - tw;
11133 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11134 //            
11135 //        //this.trigger.setStyle('left', x+'px');
11136 //        
11137 //        if(this.list && this.listWidth === undefined){
11138 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11139 //            this.list.setWidth(lw);
11140 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11141 //        }
11142         
11143     
11144         
11145     },
11146
11147     /**
11148      * Allow or prevent the user from directly editing the field text.  If false is passed,
11149      * the user will only be able to select from the items defined in the dropdown list.  This method
11150      * is the runtime equivalent of setting the 'editable' config option at config time.
11151      * @param {Boolean} value True to allow the user to directly edit the field text
11152      */
11153     setEditable : function(value){
11154         if(value == this.editable){
11155             return;
11156         }
11157         this.editable = value;
11158         if(!value){
11159             this.inputEl().dom.setAttribute('readOnly', true);
11160             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11161             this.inputEl().addClass('x-combo-noedit');
11162         }else{
11163             this.inputEl().dom.setAttribute('readOnly', false);
11164             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11165             this.inputEl().removeClass('x-combo-noedit');
11166         }
11167     },
11168
11169     // private
11170     
11171     onBeforeLoad : function(combo,opts){
11172         if(!this.hasFocus){
11173             return;
11174         }
11175          if (!opts.add) {
11176             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11177          }
11178         this.restrictHeight();
11179         this.selectedIndex = -1;
11180     },
11181
11182     // private
11183     onLoad : function(){
11184         
11185         this.hasQuery = false;
11186         
11187         if(!this.hasFocus){
11188             return;
11189         }
11190         
11191         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11192             this.loading.hide();
11193         }
11194         
11195         if(this.store.getCount() > 0){
11196             this.expand();
11197 //            this.restrictHeight();
11198             if(this.lastQuery == this.allQuery){
11199                 if(this.editable && !this.tickable){
11200                     this.inputEl().dom.select();
11201                 }
11202                 
11203                 if(
11204                     !this.selectByValue(this.value, true) &&
11205                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11206                     this.store.lastOptions.add != true)
11207                 ){
11208                     this.select(0, true);
11209                 }
11210             }else{
11211                 if(this.autoFocus){
11212                     this.selectNext();
11213                 }
11214                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11215                     this.taTask.delay(this.typeAheadDelay);
11216                 }
11217             }
11218         }else{
11219             this.onEmptyResults();
11220         }
11221         
11222         //this.el.focus();
11223     },
11224     // private
11225     onLoadException : function()
11226     {
11227         this.hasQuery = false;
11228         
11229         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11230             this.loading.hide();
11231         }
11232         
11233         this.collapse();
11234         Roo.log(this.store.reader.jsonData);
11235         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11236             // fixme
11237             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11238         }
11239         
11240         
11241     },
11242     // private
11243     onTypeAhead : function(){
11244         if(this.store.getCount() > 0){
11245             var r = this.store.getAt(0);
11246             var newValue = r.data[this.displayField];
11247             var len = newValue.length;
11248             var selStart = this.getRawValue().length;
11249             
11250             if(selStart != len){
11251                 this.setRawValue(newValue);
11252                 this.selectText(selStart, newValue.length);
11253             }
11254         }
11255     },
11256
11257     // private
11258     onSelect : function(record, index){
11259         
11260         if(this.fireEvent('beforeselect', this, record, index) !== false){
11261         
11262             this.setFromData(index > -1 ? record.data : false);
11263             
11264             this.collapse();
11265             this.fireEvent('select', this, record, index);
11266         }
11267     },
11268
11269     /**
11270      * Returns the currently selected field value or empty string if no value is set.
11271      * @return {String} value The selected value
11272      */
11273     getValue : function(){
11274         
11275         if(this.multiple){
11276             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11277         }
11278         
11279         if(this.valueField){
11280             return typeof this.value != 'undefined' ? this.value : '';
11281         }else{
11282             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11283         }
11284     },
11285
11286     /**
11287      * Clears any text/value currently set in the field
11288      */
11289     clearValue : function(){
11290         if(this.hiddenField){
11291             this.hiddenField.dom.value = '';
11292         }
11293         this.value = '';
11294         this.setRawValue('');
11295         this.lastSelectionText = '';
11296         
11297     },
11298
11299     /**
11300      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11301      * will be displayed in the field.  If the value does not match the data value of an existing item,
11302      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11303      * Otherwise the field will be blank (although the value will still be set).
11304      * @param {String} value The value to match
11305      */
11306     setValue : function(v){
11307         if(this.multiple){
11308             this.syncValue();
11309             return;
11310         }
11311         
11312         var text = v;
11313         if(this.valueField){
11314             var r = this.findRecord(this.valueField, v);
11315             if(r){
11316                 text = r.data[this.displayField];
11317             }else if(this.valueNotFoundText !== undefined){
11318                 text = this.valueNotFoundText;
11319             }
11320         }
11321         this.lastSelectionText = text;
11322         if(this.hiddenField){
11323             this.hiddenField.dom.value = v;
11324         }
11325         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11326         this.value = v;
11327     },
11328     /**
11329      * @property {Object} the last set data for the element
11330      */
11331     
11332     lastData : false,
11333     /**
11334      * Sets the value of the field based on a object which is related to the record format for the store.
11335      * @param {Object} value the value to set as. or false on reset?
11336      */
11337     setFromData : function(o){
11338         
11339         if(this.multiple){
11340             this.addItem(o);
11341             return;
11342         }
11343             
11344         var dv = ''; // display value
11345         var vv = ''; // value value..
11346         this.lastData = o;
11347         if (this.displayField) {
11348             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11349         } else {
11350             // this is an error condition!!!
11351             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11352         }
11353         
11354         if(this.valueField){
11355             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11356         }
11357         
11358         if(this.hiddenField){
11359             this.hiddenField.dom.value = vv;
11360             
11361             this.lastSelectionText = dv;
11362             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11363             this.value = vv;
11364             return;
11365         }
11366         // no hidden field.. - we store the value in 'value', but still display
11367         // display field!!!!
11368         this.lastSelectionText = dv;
11369         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11370         this.value = vv;
11371         
11372         
11373     },
11374     // private
11375     reset : function(){
11376         // overridden so that last data is reset..
11377         this.setValue(this.originalValue);
11378         this.clearInvalid();
11379         this.lastData = false;
11380         if (this.view) {
11381             this.view.clearSelections();
11382         }
11383     },
11384     // private
11385     findRecord : function(prop, value){
11386         var record;
11387         if(this.store.getCount() > 0){
11388             this.store.each(function(r){
11389                 if(r.data[prop] == value){
11390                     record = r;
11391                     return false;
11392                 }
11393                 return true;
11394             });
11395         }
11396         return record;
11397     },
11398     
11399     getName: function()
11400     {
11401         // returns hidden if it's set..
11402         if (!this.rendered) {return ''};
11403         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11404         
11405     },
11406     // private
11407     onViewMove : function(e, t){
11408         this.inKeyMode = false;
11409     },
11410
11411     // private
11412     onViewOver : function(e, t){
11413         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11414             return;
11415         }
11416         var item = this.view.findItemFromChild(t);
11417         
11418         if(item){
11419             var index = this.view.indexOf(item);
11420             this.select(index, false);
11421         }
11422     },
11423
11424     // private
11425     onViewClick : function(view, doFocus, el, e)
11426     {
11427         var index = this.view.getSelectedIndexes()[0];
11428         
11429         var r = this.store.getAt(index);
11430         
11431         if(this.tickable){
11432             
11433             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11434                 return;
11435             }
11436             
11437             var rm = false;
11438             var _this = this;
11439             
11440             Roo.each(this.tickItems, function(v,k){
11441                 
11442                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11443                     _this.tickItems.splice(k, 1);
11444                     rm = true;
11445                     return;
11446                 }
11447             })
11448             
11449             if(rm){
11450                 return;
11451             }
11452             
11453             this.tickItems.push(r.data);
11454             return;
11455         }
11456         
11457         if(r){
11458             this.onSelect(r, index);
11459         }
11460         if(doFocus !== false && !this.blockFocus){
11461             this.inputEl().focus();
11462         }
11463     },
11464
11465     // private
11466     restrictHeight : function(){
11467         //this.innerList.dom.style.height = '';
11468         //var inner = this.innerList.dom;
11469         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11470         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11471         //this.list.beginUpdate();
11472         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11473         this.list.alignTo(this.inputEl(), this.listAlign);
11474         this.list.alignTo(this.inputEl(), this.listAlign);
11475         //this.list.endUpdate();
11476     },
11477
11478     // private
11479     onEmptyResults : function(){
11480         this.collapse();
11481     },
11482
11483     /**
11484      * Returns true if the dropdown list is expanded, else false.
11485      */
11486     isExpanded : function(){
11487         return this.list.isVisible();
11488     },
11489
11490     /**
11491      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11492      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11493      * @param {String} value The data value of the item to select
11494      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11495      * selected item if it is not currently in view (defaults to true)
11496      * @return {Boolean} True if the value matched an item in the list, else false
11497      */
11498     selectByValue : function(v, scrollIntoView){
11499         if(v !== undefined && v !== null){
11500             var r = this.findRecord(this.valueField || this.displayField, v);
11501             if(r){
11502                 this.select(this.store.indexOf(r), scrollIntoView);
11503                 return true;
11504             }
11505         }
11506         return false;
11507     },
11508
11509     /**
11510      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11511      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11512      * @param {Number} index The zero-based index of the list item to select
11513      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11514      * selected item if it is not currently in view (defaults to true)
11515      */
11516     select : function(index, scrollIntoView){
11517         this.selectedIndex = index;
11518         this.view.select(index);
11519         if(scrollIntoView !== false){
11520             var el = this.view.getNode(index);
11521             if(el && !this.multiple && !this.tickable){
11522                 this.list.scrollChildIntoView(el, false);
11523             }
11524         }
11525     },
11526
11527     // private
11528     selectNext : function(){
11529         var ct = this.store.getCount();
11530         if(ct > 0){
11531             if(this.selectedIndex == -1){
11532                 this.select(0);
11533             }else if(this.selectedIndex < ct-1){
11534                 this.select(this.selectedIndex+1);
11535             }
11536         }
11537     },
11538
11539     // private
11540     selectPrev : function(){
11541         var ct = this.store.getCount();
11542         if(ct > 0){
11543             if(this.selectedIndex == -1){
11544                 this.select(0);
11545             }else if(this.selectedIndex != 0){
11546                 this.select(this.selectedIndex-1);
11547             }
11548         }
11549     },
11550
11551     // private
11552     onKeyUp : function(e){
11553         if(this.editable !== false && !e.isSpecialKey()){
11554             this.lastKey = e.getKey();
11555             this.dqTask.delay(this.queryDelay);
11556         }
11557     },
11558
11559     // private
11560     validateBlur : function(){
11561         return !this.list || !this.list.isVisible();   
11562     },
11563
11564     // private
11565     initQuery : function(){
11566         this.doQuery(this.getRawValue());
11567     },
11568
11569     // private
11570     doForce : function(){
11571         if(this.inputEl().dom.value.length > 0){
11572             this.inputEl().dom.value =
11573                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11574              
11575         }
11576     },
11577
11578     /**
11579      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11580      * query allowing the query action to be canceled if needed.
11581      * @param {String} query The SQL query to execute
11582      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11583      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11584      * saved in the current store (defaults to false)
11585      */
11586     doQuery : function(q, forceAll){
11587         
11588         if(q === undefined || q === null){
11589             q = '';
11590         }
11591         var qe = {
11592             query: q,
11593             forceAll: forceAll,
11594             combo: this,
11595             cancel:false
11596         };
11597         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11598             return false;
11599         }
11600         q = qe.query;
11601         
11602         forceAll = qe.forceAll;
11603         if(forceAll === true || (q.length >= this.minChars)){
11604             
11605             this.hasQuery = true;
11606             
11607             if(this.lastQuery != q || this.alwaysQuery){
11608                 this.lastQuery = q;
11609                 if(this.mode == 'local'){
11610                     this.selectedIndex = -1;
11611                     if(forceAll){
11612                         this.store.clearFilter();
11613                     }else{
11614                         this.store.filter(this.displayField, q);
11615                     }
11616                     this.onLoad();
11617                 }else{
11618                     this.store.baseParams[this.queryParam] = q;
11619                     
11620                     var options = {params : this.getParams(q)};
11621                     
11622                     if(this.loadNext){
11623                         options.add = true;
11624                         options.params.start = this.page * this.pageSize;
11625                     }
11626                     
11627                     this.store.load(options);
11628                     /*
11629                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11630                      *  we should expand the list on onLoad
11631                      *  so command out it
11632                      */
11633 //                    this.expand();
11634                 }
11635             }else{
11636                 this.selectedIndex = -1;
11637                 this.onLoad();   
11638             }
11639         }
11640         
11641         this.loadNext = false;
11642     },
11643
11644     // private
11645     getParams : function(q){
11646         var p = {};
11647         //p[this.queryParam] = q;
11648         
11649         if(this.pageSize){
11650             p.start = 0;
11651             p.limit = this.pageSize;
11652         }
11653         return p;
11654     },
11655
11656     /**
11657      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11658      */
11659     collapse : function(){
11660         if(!this.isExpanded()){
11661             return;
11662         }
11663         
11664         this.list.hide();
11665         
11666         if(this.tickable){
11667             this.okBtn.hide();
11668             this.cancelBtn.hide();
11669             this.trigger.show();
11670         }
11671         
11672         Roo.get(document).un('mousedown', this.collapseIf, this);
11673         Roo.get(document).un('mousewheel', this.collapseIf, this);
11674         if (!this.editable) {
11675             Roo.get(document).un('keydown', this.listKeyPress, this);
11676         }
11677         this.fireEvent('collapse', this);
11678     },
11679
11680     // private
11681     collapseIf : function(e){
11682         var in_combo  = e.within(this.el);
11683         var in_list =  e.within(this.list);
11684         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11685         
11686         if (in_combo || in_list || is_list) {
11687             //e.stopPropagation();
11688             return;
11689         }
11690         
11691         if(this.tickable){
11692             this.onTickableFooterButtonClick(e, false, false);
11693         }
11694
11695         this.collapse();
11696         
11697     },
11698
11699     /**
11700      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11701      */
11702     expand : function(){
11703        
11704         if(this.isExpanded() || !this.hasFocus){
11705             return;
11706         }
11707         
11708         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11709         this.list.setWidth(lw);
11710         
11711         
11712          Roo.log('expand');
11713         
11714         this.list.show();
11715         
11716         this.restrictHeight();
11717         
11718         if(this.tickable){
11719             
11720             this.tickItems = Roo.apply([], this.item);
11721             
11722             this.okBtn.show();
11723             this.cancelBtn.show();
11724             this.trigger.hide();
11725             
11726         }
11727         
11728         Roo.get(document).on('mousedown', this.collapseIf, this);
11729         Roo.get(document).on('mousewheel', this.collapseIf, this);
11730         if (!this.editable) {
11731             Roo.get(document).on('keydown', this.listKeyPress, this);
11732         }
11733         
11734         this.fireEvent('expand', this);
11735     },
11736
11737     // private
11738     // Implements the default empty TriggerField.onTriggerClick function
11739     onTriggerClick : function(e)
11740     {
11741         Roo.log('trigger click');
11742         
11743         if(this.disabled || !this.triggerList){
11744             return;
11745         }
11746         
11747         this.page = 0;
11748         this.loadNext = false;
11749         
11750         if(this.isExpanded()){
11751             this.collapse();
11752             if (!this.blockFocus) {
11753                 this.inputEl().focus();
11754             }
11755             
11756         }else {
11757             this.hasFocus = true;
11758             if(this.triggerAction == 'all') {
11759                 this.doQuery(this.allQuery, true);
11760             } else {
11761                 this.doQuery(this.getRawValue());
11762             }
11763             if (!this.blockFocus) {
11764                 this.inputEl().focus();
11765             }
11766         }
11767     },
11768     
11769     onTickableTriggerClick : function(e)
11770     {
11771         if(this.disabled){
11772             return;
11773         }
11774         
11775         this.page = 0;
11776         this.loadNext = false;
11777         this.hasFocus = true;
11778         
11779         if(this.triggerAction == 'all') {
11780             this.doQuery(this.allQuery, true);
11781         } else {
11782             this.doQuery(this.getRawValue());
11783         }
11784     },
11785     
11786     onSearchFieldClick : function(e)
11787     {
11788         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11789             return;
11790         }
11791         
11792         this.page = 0;
11793         this.loadNext = false;
11794         this.hasFocus = true;
11795         
11796         if(this.triggerAction == 'all') {
11797             this.doQuery(this.allQuery, true);
11798         } else {
11799             this.doQuery(this.getRawValue());
11800         }
11801     },
11802     
11803     listKeyPress : function(e)
11804     {
11805         //Roo.log('listkeypress');
11806         // scroll to first matching element based on key pres..
11807         if (e.isSpecialKey()) {
11808             return false;
11809         }
11810         var k = String.fromCharCode(e.getKey()).toUpperCase();
11811         //Roo.log(k);
11812         var match  = false;
11813         var csel = this.view.getSelectedNodes();
11814         var cselitem = false;
11815         if (csel.length) {
11816             var ix = this.view.indexOf(csel[0]);
11817             cselitem  = this.store.getAt(ix);
11818             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11819                 cselitem = false;
11820             }
11821             
11822         }
11823         
11824         this.store.each(function(v) { 
11825             if (cselitem) {
11826                 // start at existing selection.
11827                 if (cselitem.id == v.id) {
11828                     cselitem = false;
11829                 }
11830                 return true;
11831             }
11832                 
11833             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11834                 match = this.store.indexOf(v);
11835                 return false;
11836             }
11837             return true;
11838         }, this);
11839         
11840         if (match === false) {
11841             return true; // no more action?
11842         }
11843         // scroll to?
11844         this.view.select(match);
11845         var sn = Roo.get(this.view.getSelectedNodes()[0])
11846         //sn.scrollIntoView(sn.dom.parentNode, false);
11847     },
11848     
11849     onViewScroll : function(e, t){
11850         
11851         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){
11852             return;
11853         }
11854         
11855         this.hasQuery = true;
11856         
11857         this.loading = this.list.select('.loading', true).first();
11858         
11859         if(this.loading === null){
11860             this.list.createChild({
11861                 tag: 'div',
11862                 cls: 'loading select2-more-results select2-active',
11863                 html: 'Loading more results...'
11864             })
11865             
11866             this.loading = this.list.select('.loading', true).first();
11867             
11868             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11869             
11870             this.loading.hide();
11871         }
11872         
11873         this.loading.show();
11874         
11875         var _combo = this;
11876         
11877         this.page++;
11878         this.loadNext = true;
11879         
11880         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11881         
11882         return;
11883     },
11884     
11885     addItem : function(o)
11886     {   
11887         var dv = ''; // display value
11888         
11889         if (this.displayField) {
11890             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11891         } else {
11892             // this is an error condition!!!
11893             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11894         }
11895         
11896         if(!dv.length){
11897             return;
11898         }
11899         
11900         var choice = this.choices.createChild({
11901             tag: 'li',
11902             cls: 'select2-search-choice',
11903             cn: [
11904                 {
11905                     tag: 'div',
11906                     html: dv
11907                 },
11908                 {
11909                     tag: 'a',
11910                     href: '#',
11911                     cls: 'select2-search-choice-close',
11912                     tabindex: '-1'
11913                 }
11914             ]
11915             
11916         }, this.searchField);
11917         
11918         var close = choice.select('a.select2-search-choice-close', true).first()
11919         
11920         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11921         
11922         this.item.push(o);
11923         
11924         this.lastData = o;
11925         
11926         this.syncValue();
11927         
11928         this.inputEl().dom.value = '';
11929         
11930     },
11931     
11932     onRemoveItem : function(e, _self, o)
11933     {
11934         e.preventDefault();
11935         var index = this.item.indexOf(o.data) * 1;
11936         
11937         if( index < 0){
11938             Roo.log('not this item?!');
11939             return;
11940         }
11941         
11942         this.item.splice(index, 1);
11943         o.item.remove();
11944         
11945         this.syncValue();
11946         
11947         this.fireEvent('remove', this, e);
11948         
11949     },
11950     
11951     syncValue : function()
11952     {
11953         if(!this.item.length){
11954             this.clearValue();
11955             return;
11956         }
11957             
11958         var value = [];
11959         var _this = this;
11960         Roo.each(this.item, function(i){
11961             if(_this.valueField){
11962                 value.push(i[_this.valueField]);
11963                 return;
11964             }
11965
11966             value.push(i);
11967         });
11968
11969         this.value = value.join(',');
11970
11971         if(this.hiddenField){
11972             this.hiddenField.dom.value = this.value;
11973         }
11974     },
11975     
11976     clearItem : function()
11977     {
11978         if(!this.multiple){
11979             return;
11980         }
11981         
11982         this.item = [];
11983         
11984         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11985            c.remove();
11986         });
11987         
11988         this.syncValue();
11989     },
11990     
11991     inputEl: function ()
11992     {
11993         if(this.tickable){
11994             return this.searchField;
11995         }
11996         return this.el.select('input.form-control',true).first();
11997     },
11998     
11999     
12000     onTickableFooterButtonClick : function(e, btn, el)
12001     {
12002         e.preventDefault();
12003         
12004         if(btn && btn.name == 'cancel'){
12005             this.tickItems = Roo.apply([], this.item);
12006             this.collapse();
12007             return;
12008         }
12009         
12010         this.clearItem();
12011         
12012         var _this = this;
12013         
12014         Roo.each(this.tickItems, function(o){
12015             _this.addItem(o);
12016         });
12017         
12018         this.collapse();
12019         
12020     }
12021     
12022     
12023
12024     /** 
12025     * @cfg {Boolean} grow 
12026     * @hide 
12027     */
12028     /** 
12029     * @cfg {Number} growMin 
12030     * @hide 
12031     */
12032     /** 
12033     * @cfg {Number} growMax 
12034     * @hide 
12035     */
12036     /**
12037      * @hide
12038      * @method autoSize
12039      */
12040 });
12041 /*
12042  * Based on:
12043  * Ext JS Library 1.1.1
12044  * Copyright(c) 2006-2007, Ext JS, LLC.
12045  *
12046  * Originally Released Under LGPL - original licence link has changed is not relivant.
12047  *
12048  * Fork - LGPL
12049  * <script type="text/javascript">
12050  */
12051
12052 /**
12053  * @class Roo.View
12054  * @extends Roo.util.Observable
12055  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12056  * This class also supports single and multi selection modes. <br>
12057  * Create a data model bound view:
12058  <pre><code>
12059  var store = new Roo.data.Store(...);
12060
12061  var view = new Roo.View({
12062     el : "my-element",
12063     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12064  
12065     singleSelect: true,
12066     selectedClass: "ydataview-selected",
12067     store: store
12068  });
12069
12070  // listen for node click?
12071  view.on("click", function(vw, index, node, e){
12072  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12073  });
12074
12075  // load XML data
12076  dataModel.load("foobar.xml");
12077  </code></pre>
12078  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12079  * <br><br>
12080  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12081  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12082  * 
12083  * Note: old style constructor is still suported (container, template, config)
12084  * 
12085  * @constructor
12086  * Create a new View
12087  * @param {Object} config The config object
12088  * 
12089  */
12090 Roo.View = function(config, depreciated_tpl, depreciated_config){
12091     
12092     this.parent = false;
12093     
12094     if (typeof(depreciated_tpl) == 'undefined') {
12095         // new way.. - universal constructor.
12096         Roo.apply(this, config);
12097         this.el  = Roo.get(this.el);
12098     } else {
12099         // old format..
12100         this.el  = Roo.get(config);
12101         this.tpl = depreciated_tpl;
12102         Roo.apply(this, depreciated_config);
12103     }
12104     this.wrapEl  = this.el.wrap().wrap();
12105     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12106     
12107     
12108     if(typeof(this.tpl) == "string"){
12109         this.tpl = new Roo.Template(this.tpl);
12110     } else {
12111         // support xtype ctors..
12112         this.tpl = new Roo.factory(this.tpl, Roo);
12113     }
12114     
12115     
12116     this.tpl.compile();
12117     
12118     /** @private */
12119     this.addEvents({
12120         /**
12121          * @event beforeclick
12122          * Fires before a click is processed. Returns false to cancel the default action.
12123          * @param {Roo.View} this
12124          * @param {Number} index The index of the target node
12125          * @param {HTMLElement} node The target node
12126          * @param {Roo.EventObject} e The raw event object
12127          */
12128             "beforeclick" : true,
12129         /**
12130          * @event click
12131          * Fires when a template node is clicked.
12132          * @param {Roo.View} this
12133          * @param {Number} index The index of the target node
12134          * @param {HTMLElement} node The target node
12135          * @param {Roo.EventObject} e The raw event object
12136          */
12137             "click" : true,
12138         /**
12139          * @event dblclick
12140          * Fires when a template node is double clicked.
12141          * @param {Roo.View} this
12142          * @param {Number} index The index of the target node
12143          * @param {HTMLElement} node The target node
12144          * @param {Roo.EventObject} e The raw event object
12145          */
12146             "dblclick" : true,
12147         /**
12148          * @event contextmenu
12149          * Fires when a template node is right clicked.
12150          * @param {Roo.View} this
12151          * @param {Number} index The index of the target node
12152          * @param {HTMLElement} node The target node
12153          * @param {Roo.EventObject} e The raw event object
12154          */
12155             "contextmenu" : true,
12156         /**
12157          * @event selectionchange
12158          * Fires when the selected nodes change.
12159          * @param {Roo.View} this
12160          * @param {Array} selections Array of the selected nodes
12161          */
12162             "selectionchange" : true,
12163     
12164         /**
12165          * @event beforeselect
12166          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12167          * @param {Roo.View} this
12168          * @param {HTMLElement} node The node to be selected
12169          * @param {Array} selections Array of currently selected nodes
12170          */
12171             "beforeselect" : true,
12172         /**
12173          * @event preparedata
12174          * Fires on every row to render, to allow you to change the data.
12175          * @param {Roo.View} this
12176          * @param {Object} data to be rendered (change this)
12177          */
12178           "preparedata" : true
12179           
12180           
12181         });
12182
12183
12184
12185     this.el.on({
12186         "click": this.onClick,
12187         "dblclick": this.onDblClick,
12188         "contextmenu": this.onContextMenu,
12189         scope:this
12190     });
12191
12192     this.selections = [];
12193     this.nodes = [];
12194     this.cmp = new Roo.CompositeElementLite([]);
12195     if(this.store){
12196         this.store = Roo.factory(this.store, Roo.data);
12197         this.setStore(this.store, true);
12198     }
12199     
12200     if ( this.footer && this.footer.xtype) {
12201            
12202          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12203         
12204         this.footer.dataSource = this.store
12205         this.footer.container = fctr;
12206         this.footer = Roo.factory(this.footer, Roo);
12207         fctr.insertFirst(this.el);
12208         
12209         // this is a bit insane - as the paging toolbar seems to detach the el..
12210 //        dom.parentNode.parentNode.parentNode
12211          // they get detached?
12212     }
12213     
12214     
12215     Roo.View.superclass.constructor.call(this);
12216     
12217     
12218 };
12219
12220 Roo.extend(Roo.View, Roo.util.Observable, {
12221     
12222      /**
12223      * @cfg {Roo.data.Store} store Data store to load data from.
12224      */
12225     store : false,
12226     
12227     /**
12228      * @cfg {String|Roo.Element} el The container element.
12229      */
12230     el : '',
12231     
12232     /**
12233      * @cfg {String|Roo.Template} tpl The template used by this View 
12234      */
12235     tpl : false,
12236     /**
12237      * @cfg {String} dataName the named area of the template to use as the data area
12238      *                          Works with domtemplates roo-name="name"
12239      */
12240     dataName: false,
12241     /**
12242      * @cfg {String} selectedClass The css class to add to selected nodes
12243      */
12244     selectedClass : "x-view-selected",
12245      /**
12246      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12247      */
12248     emptyText : "",
12249     
12250     /**
12251      * @cfg {String} text to display on mask (default Loading)
12252      */
12253     mask : false,
12254     /**
12255      * @cfg {Boolean} multiSelect Allow multiple selection
12256      */
12257     multiSelect : false,
12258     /**
12259      * @cfg {Boolean} singleSelect Allow single selection
12260      */
12261     singleSelect:  false,
12262     
12263     /**
12264      * @cfg {Boolean} toggleSelect - selecting 
12265      */
12266     toggleSelect : false,
12267     
12268     /**
12269      * @cfg {Boolean} tickable - selecting 
12270      */
12271     tickable : false,
12272     
12273     /**
12274      * Returns the element this view is bound to.
12275      * @return {Roo.Element}
12276      */
12277     getEl : function(){
12278         return this.wrapEl;
12279     },
12280     
12281     
12282
12283     /**
12284      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12285      */
12286     refresh : function(){
12287         Roo.log('refresh');
12288         var t = this.tpl;
12289         
12290         // if we are using something like 'domtemplate', then
12291         // the what gets used is:
12292         // t.applySubtemplate(NAME, data, wrapping data..)
12293         // the outer template then get' applied with
12294         //     the store 'extra data'
12295         // and the body get's added to the
12296         //      roo-name="data" node?
12297         //      <span class='roo-tpl-{name}'></span> ?????
12298         
12299         
12300         
12301         this.clearSelections();
12302         this.el.update("");
12303         var html = [];
12304         var records = this.store.getRange();
12305         if(records.length < 1) {
12306             
12307             // is this valid??  = should it render a template??
12308             
12309             this.el.update(this.emptyText);
12310             return;
12311         }
12312         var el = this.el;
12313         if (this.dataName) {
12314             this.el.update(t.apply(this.store.meta)); //????
12315             el = this.el.child('.roo-tpl-' + this.dataName);
12316         }
12317         
12318         for(var i = 0, len = records.length; i < len; i++){
12319             var data = this.prepareData(records[i].data, i, records[i]);
12320             this.fireEvent("preparedata", this, data, i, records[i]);
12321             
12322             var d = Roo.apply({}, data);
12323             
12324             if(this.tickable){
12325                 Roo.apply(d, {'roo-id' : Roo.id()});
12326                 
12327                 var _this = this;
12328             
12329                 Roo.each(this.parent.item, function(item){
12330                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12331                         return;
12332                     }
12333                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12334                 });
12335             }
12336             
12337             html[html.length] = Roo.util.Format.trim(
12338                 this.dataName ?
12339                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12340                     t.apply(d)
12341             );
12342         }
12343         
12344         
12345         
12346         el.update(html.join(""));
12347         this.nodes = el.dom.childNodes;
12348         this.updateIndexes(0);
12349     },
12350     
12351
12352     /**
12353      * Function to override to reformat the data that is sent to
12354      * the template for each node.
12355      * DEPRICATED - use the preparedata event handler.
12356      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12357      * a JSON object for an UpdateManager bound view).
12358      */
12359     prepareData : function(data, index, record)
12360     {
12361         this.fireEvent("preparedata", this, data, index, record);
12362         return data;
12363     },
12364
12365     onUpdate : function(ds, record){
12366          Roo.log('on update');   
12367         this.clearSelections();
12368         var index = this.store.indexOf(record);
12369         var n = this.nodes[index];
12370         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12371         n.parentNode.removeChild(n);
12372         this.updateIndexes(index, index);
12373     },
12374
12375     
12376     
12377 // --------- FIXME     
12378     onAdd : function(ds, records, index)
12379     {
12380         Roo.log(['on Add', ds, records, index] );        
12381         this.clearSelections();
12382         if(this.nodes.length == 0){
12383             this.refresh();
12384             return;
12385         }
12386         var n = this.nodes[index];
12387         for(var i = 0, len = records.length; i < len; i++){
12388             var d = this.prepareData(records[i].data, i, records[i]);
12389             if(n){
12390                 this.tpl.insertBefore(n, d);
12391             }else{
12392                 
12393                 this.tpl.append(this.el, d);
12394             }
12395         }
12396         this.updateIndexes(index);
12397     },
12398
12399     onRemove : function(ds, record, index){
12400         Roo.log('onRemove');
12401         this.clearSelections();
12402         var el = this.dataName  ?
12403             this.el.child('.roo-tpl-' + this.dataName) :
12404             this.el; 
12405         
12406         el.dom.removeChild(this.nodes[index]);
12407         this.updateIndexes(index);
12408     },
12409
12410     /**
12411      * Refresh an individual node.
12412      * @param {Number} index
12413      */
12414     refreshNode : function(index){
12415         this.onUpdate(this.store, this.store.getAt(index));
12416     },
12417
12418     updateIndexes : function(startIndex, endIndex){
12419         var ns = this.nodes;
12420         startIndex = startIndex || 0;
12421         endIndex = endIndex || ns.length - 1;
12422         for(var i = startIndex; i <= endIndex; i++){
12423             ns[i].nodeIndex = i;
12424         }
12425     },
12426
12427     /**
12428      * Changes the data store this view uses and refresh the view.
12429      * @param {Store} store
12430      */
12431     setStore : function(store, initial){
12432         if(!initial && this.store){
12433             this.store.un("datachanged", this.refresh);
12434             this.store.un("add", this.onAdd);
12435             this.store.un("remove", this.onRemove);
12436             this.store.un("update", this.onUpdate);
12437             this.store.un("clear", this.refresh);
12438             this.store.un("beforeload", this.onBeforeLoad);
12439             this.store.un("load", this.onLoad);
12440             this.store.un("loadexception", this.onLoad);
12441         }
12442         if(store){
12443           
12444             store.on("datachanged", this.refresh, this);
12445             store.on("add", this.onAdd, this);
12446             store.on("remove", this.onRemove, this);
12447             store.on("update", this.onUpdate, this);
12448             store.on("clear", this.refresh, this);
12449             store.on("beforeload", this.onBeforeLoad, this);
12450             store.on("load", this.onLoad, this);
12451             store.on("loadexception", this.onLoad, this);
12452         }
12453         
12454         if(store){
12455             this.refresh();
12456         }
12457     },
12458     /**
12459      * onbeforeLoad - masks the loading area.
12460      *
12461      */
12462     onBeforeLoad : function(store,opts)
12463     {
12464          Roo.log('onBeforeLoad');   
12465         if (!opts.add) {
12466             this.el.update("");
12467         }
12468         this.el.mask(this.mask ? this.mask : "Loading" ); 
12469     },
12470     onLoad : function ()
12471     {
12472         this.el.unmask();
12473     },
12474     
12475
12476     /**
12477      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12478      * @param {HTMLElement} node
12479      * @return {HTMLElement} The template node
12480      */
12481     findItemFromChild : function(node){
12482         var el = this.dataName  ?
12483             this.el.child('.roo-tpl-' + this.dataName,true) :
12484             this.el.dom; 
12485         
12486         if(!node || node.parentNode == el){
12487                     return node;
12488             }
12489             var p = node.parentNode;
12490             while(p && p != el){
12491             if(p.parentNode == el){
12492                 return p;
12493             }
12494             p = p.parentNode;
12495         }
12496             return null;
12497     },
12498
12499     /** @ignore */
12500     onClick : function(e){
12501         var item = this.findItemFromChild(e.getTarget());
12502         if(item){
12503             var index = this.indexOf(item);
12504             if(this.onItemClick(item, index, e) !== false){
12505                 this.fireEvent("click", this, index, item, e);
12506             }
12507         }else{
12508             this.clearSelections();
12509         }
12510     },
12511
12512     /** @ignore */
12513     onContextMenu : function(e){
12514         var item = this.findItemFromChild(e.getTarget());
12515         if(item){
12516             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12517         }
12518     },
12519
12520     /** @ignore */
12521     onDblClick : function(e){
12522         var item = this.findItemFromChild(e.getTarget());
12523         if(item){
12524             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12525         }
12526     },
12527
12528     onItemClick : function(item, index, e)
12529     {
12530         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12531             return false;
12532         }
12533         if (this.toggleSelect) {
12534             var m = this.isSelected(item) ? 'unselect' : 'select';
12535             Roo.log(m);
12536             var _t = this;
12537             _t[m](item, true, false);
12538             return true;
12539         }
12540         if(this.multiSelect || this.singleSelect){
12541             if(this.multiSelect && e.shiftKey && this.lastSelection){
12542                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12543             }else{
12544                 this.select(item, this.multiSelect && e.ctrlKey);
12545                 this.lastSelection = item;
12546             }
12547             
12548             if(!this.tickable){
12549                 e.preventDefault();
12550             }
12551             
12552         }
12553         return true;
12554     },
12555
12556     /**
12557      * Get the number of selected nodes.
12558      * @return {Number}
12559      */
12560     getSelectionCount : function(){
12561         return this.selections.length;
12562     },
12563
12564     /**
12565      * Get the currently selected nodes.
12566      * @return {Array} An array of HTMLElements
12567      */
12568     getSelectedNodes : function(){
12569         return this.selections;
12570     },
12571
12572     /**
12573      * Get the indexes of the selected nodes.
12574      * @return {Array}
12575      */
12576     getSelectedIndexes : function(){
12577         var indexes = [], s = this.selections;
12578         for(var i = 0, len = s.length; i < len; i++){
12579             indexes.push(s[i].nodeIndex);
12580         }
12581         return indexes;
12582     },
12583
12584     /**
12585      * Clear all selections
12586      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12587      */
12588     clearSelections : function(suppressEvent){
12589         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12590             this.cmp.elements = this.selections;
12591             this.cmp.removeClass(this.selectedClass);
12592             this.selections = [];
12593             if(!suppressEvent){
12594                 this.fireEvent("selectionchange", this, this.selections);
12595             }
12596         }
12597     },
12598
12599     /**
12600      * Returns true if the passed node is selected
12601      * @param {HTMLElement/Number} node The node or node index
12602      * @return {Boolean}
12603      */
12604     isSelected : function(node){
12605         var s = this.selections;
12606         if(s.length < 1){
12607             return false;
12608         }
12609         node = this.getNode(node);
12610         return s.indexOf(node) !== -1;
12611     },
12612
12613     /**
12614      * Selects nodes.
12615      * @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
12616      * @param {Boolean} keepExisting (optional) true to keep existing selections
12617      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12618      */
12619     select : function(nodeInfo, keepExisting, suppressEvent){
12620         Roo.log('running Roo.View select!!!!!!!!!!!!!!!!!!!!!!1');
12621         if(nodeInfo instanceof Array){
12622             if(!keepExisting){
12623                 this.clearSelections(true);
12624             }
12625             for(var i = 0, len = nodeInfo.length; i < len; i++){
12626                 this.select(nodeInfo[i], true, true);
12627             }
12628             return;
12629         } 
12630         var node = this.getNode(nodeInfo);
12631         if(!node || this.isSelected(node)){
12632             return; // already selected.
12633         }
12634         if(!keepExisting){
12635             this.clearSelections(true);
12636         }
12637         
12638         Roo.log(this.parent);
12639 //        var el = this.view.getNode(index);
12640 //        if(el && !this.multiple && !this.tickable){
12641 //            this.list.scrollChildIntoView(el, false);
12642 //        }
12643         
12644         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12645             Roo.fly(node).addClass(this.selectedClass);
12646             this.selections.push(node);
12647             if(!suppressEvent){
12648                 this.fireEvent("selectionchange", this, this.selections);
12649             }
12650         }
12651         
12652         
12653     },
12654       /**
12655      * Unselects nodes.
12656      * @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
12657      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12658      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12659      */
12660     unselect : function(nodeInfo, keepExisting, suppressEvent)
12661     {
12662         if(nodeInfo instanceof Array){
12663             Roo.each(this.selections, function(s) {
12664                 this.unselect(s, nodeInfo);
12665             }, this);
12666             return;
12667         }
12668         var node = this.getNode(nodeInfo);
12669         if(!node || !this.isSelected(node)){
12670             Roo.log("not selected");
12671             return; // not selected.
12672         }
12673         // fireevent???
12674         var ns = [];
12675         Roo.each(this.selections, function(s) {
12676             if (s == node ) {
12677                 Roo.fly(node).removeClass(this.selectedClass);
12678
12679                 return;
12680             }
12681             ns.push(s);
12682         },this);
12683         
12684         this.selections= ns;
12685         this.fireEvent("selectionchange", this, this.selections);
12686     },
12687
12688     /**
12689      * Gets a template node.
12690      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12691      * @return {HTMLElement} The node or null if it wasn't found
12692      */
12693     getNode : function(nodeInfo){
12694         if(typeof nodeInfo == "string"){
12695             return document.getElementById(nodeInfo);
12696         }else if(typeof nodeInfo == "number"){
12697             return this.nodes[nodeInfo];
12698         }
12699         return nodeInfo;
12700     },
12701
12702     /**
12703      * Gets a range template nodes.
12704      * @param {Number} startIndex
12705      * @param {Number} endIndex
12706      * @return {Array} An array of nodes
12707      */
12708     getNodes : function(start, end){
12709         var ns = this.nodes;
12710         start = start || 0;
12711         end = typeof end == "undefined" ? ns.length - 1 : end;
12712         var nodes = [];
12713         if(start <= end){
12714             for(var i = start; i <= end; i++){
12715                 nodes.push(ns[i]);
12716             }
12717         } else{
12718             for(var i = start; i >= end; i--){
12719                 nodes.push(ns[i]);
12720             }
12721         }
12722         return nodes;
12723     },
12724
12725     /**
12726      * Finds the index of the passed node
12727      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12728      * @return {Number} The index of the node or -1
12729      */
12730     indexOf : function(node){
12731         node = this.getNode(node);
12732         if(typeof node.nodeIndex == "number"){
12733             return node.nodeIndex;
12734         }
12735         var ns = this.nodes;
12736         for(var i = 0, len = ns.length; i < len; i++){
12737             if(ns[i] == node){
12738                 return i;
12739             }
12740         }
12741         return -1;
12742     }
12743 });
12744 /*
12745  * - LGPL
12746  *
12747  * based on jquery fullcalendar
12748  * 
12749  */
12750
12751 Roo.bootstrap = Roo.bootstrap || {};
12752 /**
12753  * @class Roo.bootstrap.Calendar
12754  * @extends Roo.bootstrap.Component
12755  * Bootstrap Calendar class
12756  * @cfg {Boolean} loadMask (true|false) default false
12757  * @cfg {Object} header generate the user specific header of the calendar, default false
12758
12759  * @constructor
12760  * Create a new Container
12761  * @param {Object} config The config object
12762  */
12763
12764
12765
12766 Roo.bootstrap.Calendar = function(config){
12767     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12768      this.addEvents({
12769         /**
12770              * @event select
12771              * Fires when a date is selected
12772              * @param {DatePicker} this
12773              * @param {Date} date The selected date
12774              */
12775         'select': true,
12776         /**
12777              * @event monthchange
12778              * Fires when the displayed month changes 
12779              * @param {DatePicker} this
12780              * @param {Date} date The selected month
12781              */
12782         'monthchange': true,
12783         /**
12784              * @event evententer
12785              * Fires when mouse over an event
12786              * @param {Calendar} this
12787              * @param {event} Event
12788              */
12789         'evententer': true,
12790         /**
12791              * @event eventleave
12792              * Fires when the mouse leaves an
12793              * @param {Calendar} this
12794              * @param {event}
12795              */
12796         'eventleave': true,
12797         /**
12798              * @event eventclick
12799              * Fires when the mouse click an
12800              * @param {Calendar} this
12801              * @param {event}
12802              */
12803         'eventclick': true
12804         
12805     });
12806
12807 };
12808
12809 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
12810     
12811      /**
12812      * @cfg {Number} startDay
12813      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12814      */
12815     startDay : 0,
12816     
12817     loadMask : false,
12818     
12819     header : false,
12820       
12821     getAutoCreate : function(){
12822         
12823         
12824         var fc_button = function(name, corner, style, content ) {
12825             return Roo.apply({},{
12826                 tag : 'span',
12827                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
12828                          (corner.length ?
12829                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12830                             ''
12831                         ),
12832                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12833                 unselectable: 'on'
12834             });
12835         };
12836         
12837         var header = {};
12838         
12839         if(!this.header){
12840             header = {
12841                 tag : 'table',
12842                 cls : 'fc-header',
12843                 style : 'width:100%',
12844                 cn : [
12845                     {
12846                         tag: 'tr',
12847                         cn : [
12848                             {
12849                                 tag : 'td',
12850                                 cls : 'fc-header-left',
12851                                 cn : [
12852                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
12853                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
12854                                     { tag: 'span', cls: 'fc-header-space' },
12855                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
12856
12857
12858                                 ]
12859                             },
12860
12861                             {
12862                                 tag : 'td',
12863                                 cls : 'fc-header-center',
12864                                 cn : [
12865                                     {
12866                                         tag: 'span',
12867                                         cls: 'fc-header-title',
12868                                         cn : {
12869                                             tag: 'H2',
12870                                             html : 'month / year'
12871                                         }
12872                                     }
12873
12874                                 ]
12875                             },
12876                             {
12877                                 tag : 'td',
12878                                 cls : 'fc-header-right',
12879                                 cn : [
12880                               /*      fc_button('month', 'left', '', 'month' ),
12881                                     fc_button('week', '', '', 'week' ),
12882                                     fc_button('day', 'right', '', 'day' )
12883                                 */    
12884
12885                                 ]
12886                             }
12887
12888                         ]
12889                     }
12890                 ]
12891             };
12892         }
12893         
12894         header = this.header;
12895         
12896        
12897         var cal_heads = function() {
12898             var ret = [];
12899             // fixme - handle this.
12900             
12901             for (var i =0; i < Date.dayNames.length; i++) {
12902                 var d = Date.dayNames[i];
12903                 ret.push({
12904                     tag: 'th',
12905                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12906                     html : d.substring(0,3)
12907                 });
12908                 
12909             }
12910             ret[0].cls += ' fc-first';
12911             ret[6].cls += ' fc-last';
12912             return ret;
12913         };
12914         var cal_cell = function(n) {
12915             return  {
12916                 tag: 'td',
12917                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12918                 cn : [
12919                     {
12920                         cn : [
12921                             {
12922                                 cls: 'fc-day-number',
12923                                 html: 'D'
12924                             },
12925                             {
12926                                 cls: 'fc-day-content',
12927                              
12928                                 cn : [
12929                                      {
12930                                         style: 'position: relative;' // height: 17px;
12931                                     }
12932                                 ]
12933                             }
12934                             
12935                             
12936                         ]
12937                     }
12938                 ]
12939                 
12940             }
12941         };
12942         var cal_rows = function() {
12943             
12944             var ret = []
12945             for (var r = 0; r < 6; r++) {
12946                 var row= {
12947                     tag : 'tr',
12948                     cls : 'fc-week',
12949                     cn : []
12950                 };
12951                 
12952                 for (var i =0; i < Date.dayNames.length; i++) {
12953                     var d = Date.dayNames[i];
12954                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12955
12956                 }
12957                 row.cn[0].cls+=' fc-first';
12958                 row.cn[0].cn[0].style = 'min-height:90px';
12959                 row.cn[6].cls+=' fc-last';
12960                 ret.push(row);
12961                 
12962             }
12963             ret[0].cls += ' fc-first';
12964             ret[4].cls += ' fc-prev-last';
12965             ret[5].cls += ' fc-last';
12966             return ret;
12967             
12968         };
12969         
12970         var cal_table = {
12971             tag: 'table',
12972             cls: 'fc-border-separate',
12973             style : 'width:100%',
12974             cellspacing  : 0,
12975             cn : [
12976                 { 
12977                     tag: 'thead',
12978                     cn : [
12979                         { 
12980                             tag: 'tr',
12981                             cls : 'fc-first fc-last',
12982                             cn : cal_heads()
12983                         }
12984                     ]
12985                 },
12986                 { 
12987                     tag: 'tbody',
12988                     cn : cal_rows()
12989                 }
12990                   
12991             ]
12992         };
12993          
12994          var cfg = {
12995             cls : 'fc fc-ltr',
12996             cn : [
12997                 header,
12998                 {
12999                     cls : 'fc-content',
13000                     style : "position: relative;",
13001                     cn : [
13002                         {
13003                             cls : 'fc-view fc-view-month fc-grid',
13004                             style : 'position: relative',
13005                             unselectable : 'on',
13006                             cn : [
13007                                 {
13008                                     cls : 'fc-event-container',
13009                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13010                                 },
13011                                 cal_table
13012                             ]
13013                         }
13014                     ]
13015     
13016                 }
13017            ] 
13018             
13019         };
13020         
13021          
13022         
13023         return cfg;
13024     },
13025     
13026     
13027     initEvents : function()
13028     {
13029         if(!this.store){
13030             throw "can not find store for calendar";
13031         }
13032         
13033         var mark = {
13034             tag: "div",
13035             cls:"x-dlg-mask",
13036             style: "text-align:center",
13037             cn: [
13038                 {
13039                     tag: "div",
13040                     style: "background-color:white;width:50%;margin:250 auto",
13041                     cn: [
13042                         {
13043                             tag: "img",
13044                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13045                         },
13046                         {
13047                             tag: "span",
13048                             html: "Loading"
13049                         }
13050                         
13051                     ]
13052                 }
13053             ]
13054         }
13055         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13056         
13057         var size = this.el.select('.fc-content', true).first().getSize();
13058         this.maskEl.setSize(size.width, size.height);
13059         this.maskEl.enableDisplayMode("block");
13060         if(!this.loadMask){
13061             this.maskEl.hide();
13062         }
13063         
13064         this.store = Roo.factory(this.store, Roo.data);
13065         this.store.on('load', this.onLoad, this);
13066         this.store.on('beforeload', this.onBeforeLoad, this);
13067         
13068         this.resize();
13069         
13070         this.cells = this.el.select('.fc-day',true);
13071         //Roo.log(this.cells);
13072         this.textNodes = this.el.query('.fc-day-number');
13073         this.cells.addClassOnOver('fc-state-hover');
13074         
13075         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13076         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13077         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13078         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13079         
13080         this.on('monthchange', this.onMonthChange, this);
13081         
13082         this.update(new Date().clearTime());
13083     },
13084     
13085     resize : function() {
13086         var sz  = this.el.getSize();
13087         
13088         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13089         this.el.select('.fc-day-content div',true).setHeight(34);
13090     },
13091     
13092     
13093     // private
13094     showPrevMonth : function(e){
13095         this.update(this.activeDate.add("mo", -1));
13096     },
13097     showToday : function(e){
13098         this.update(new Date().clearTime());
13099     },
13100     // private
13101     showNextMonth : function(e){
13102         this.update(this.activeDate.add("mo", 1));
13103     },
13104
13105     // private
13106     showPrevYear : function(){
13107         this.update(this.activeDate.add("y", -1));
13108     },
13109
13110     // private
13111     showNextYear : function(){
13112         this.update(this.activeDate.add("y", 1));
13113     },
13114
13115     
13116    // private
13117     update : function(date)
13118     {
13119         var vd = this.activeDate;
13120         this.activeDate = date;
13121 //        if(vd && this.el){
13122 //            var t = date.getTime();
13123 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13124 //                Roo.log('using add remove');
13125 //                
13126 //                this.fireEvent('monthchange', this, date);
13127 //                
13128 //                this.cells.removeClass("fc-state-highlight");
13129 //                this.cells.each(function(c){
13130 //                   if(c.dateValue == t){
13131 //                       c.addClass("fc-state-highlight");
13132 //                       setTimeout(function(){
13133 //                            try{c.dom.firstChild.focus();}catch(e){}
13134 //                       }, 50);
13135 //                       return false;
13136 //                   }
13137 //                   return true;
13138 //                });
13139 //                return;
13140 //            }
13141 //        }
13142         
13143         var days = date.getDaysInMonth();
13144         
13145         var firstOfMonth = date.getFirstDateOfMonth();
13146         var startingPos = firstOfMonth.getDay()-this.startDay;
13147         
13148         if(startingPos < this.startDay){
13149             startingPos += 7;
13150         }
13151         
13152         var pm = date.add(Date.MONTH, -1);
13153         var prevStart = pm.getDaysInMonth()-startingPos;
13154 //        
13155         this.cells = this.el.select('.fc-day',true);
13156         this.textNodes = this.el.query('.fc-day-number');
13157         this.cells.addClassOnOver('fc-state-hover');
13158         
13159         var cells = this.cells.elements;
13160         var textEls = this.textNodes;
13161         
13162         Roo.each(cells, function(cell){
13163             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13164         });
13165         
13166         days += startingPos;
13167
13168         // convert everything to numbers so it's fast
13169         var day = 86400000;
13170         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13171         //Roo.log(d);
13172         //Roo.log(pm);
13173         //Roo.log(prevStart);
13174         
13175         var today = new Date().clearTime().getTime();
13176         var sel = date.clearTime().getTime();
13177         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13178         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13179         var ddMatch = this.disabledDatesRE;
13180         var ddText = this.disabledDatesText;
13181         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13182         var ddaysText = this.disabledDaysText;
13183         var format = this.format;
13184         
13185         var setCellClass = function(cal, cell){
13186             cell.row = 0;
13187             cell.events = [];
13188             cell.more = [];
13189             //Roo.log('set Cell Class');
13190             cell.title = "";
13191             var t = d.getTime();
13192             
13193             //Roo.log(d);
13194             
13195             cell.dateValue = t;
13196             if(t == today){
13197                 cell.className += " fc-today";
13198                 cell.className += " fc-state-highlight";
13199                 cell.title = cal.todayText;
13200             }
13201             if(t == sel){
13202                 // disable highlight in other month..
13203                 //cell.className += " fc-state-highlight";
13204                 
13205             }
13206             // disabling
13207             if(t < min) {
13208                 cell.className = " fc-state-disabled";
13209                 cell.title = cal.minText;
13210                 return;
13211             }
13212             if(t > max) {
13213                 cell.className = " fc-state-disabled";
13214                 cell.title = cal.maxText;
13215                 return;
13216             }
13217             if(ddays){
13218                 if(ddays.indexOf(d.getDay()) != -1){
13219                     cell.title = ddaysText;
13220                     cell.className = " fc-state-disabled";
13221                 }
13222             }
13223             if(ddMatch && format){
13224                 var fvalue = d.dateFormat(format);
13225                 if(ddMatch.test(fvalue)){
13226                     cell.title = ddText.replace("%0", fvalue);
13227                     cell.className = " fc-state-disabled";
13228                 }
13229             }
13230             
13231             if (!cell.initialClassName) {
13232                 cell.initialClassName = cell.dom.className;
13233             }
13234             
13235             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13236         };
13237
13238         var i = 0;
13239         
13240         for(; i < startingPos; i++) {
13241             textEls[i].innerHTML = (++prevStart);
13242             d.setDate(d.getDate()+1);
13243             
13244             cells[i].className = "fc-past fc-other-month";
13245             setCellClass(this, cells[i]);
13246         }
13247         
13248         var intDay = 0;
13249         
13250         for(; i < days; i++){
13251             intDay = i - startingPos + 1;
13252             textEls[i].innerHTML = (intDay);
13253             d.setDate(d.getDate()+1);
13254             
13255             cells[i].className = ''; // "x-date-active";
13256             setCellClass(this, cells[i]);
13257         }
13258         var extraDays = 0;
13259         
13260         for(; i < 42; i++) {
13261             textEls[i].innerHTML = (++extraDays);
13262             d.setDate(d.getDate()+1);
13263             
13264             cells[i].className = "fc-future fc-other-month";
13265             setCellClass(this, cells[i]);
13266         }
13267         
13268         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13269         
13270         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13271         
13272         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13273         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13274         
13275         if(totalRows != 6){
13276             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13277             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13278         }
13279         
13280         this.fireEvent('monthchange', this, date);
13281         
13282         
13283         /*
13284         if(!this.internalRender){
13285             var main = this.el.dom.firstChild;
13286             var w = main.offsetWidth;
13287             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13288             Roo.fly(main).setWidth(w);
13289             this.internalRender = true;
13290             // opera does not respect the auto grow header center column
13291             // then, after it gets a width opera refuses to recalculate
13292             // without a second pass
13293             if(Roo.isOpera && !this.secondPass){
13294                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13295                 this.secondPass = true;
13296                 this.update.defer(10, this, [date]);
13297             }
13298         }
13299         */
13300         
13301     },
13302     
13303     findCell : function(dt) {
13304         dt = dt.clearTime().getTime();
13305         var ret = false;
13306         this.cells.each(function(c){
13307             //Roo.log("check " +c.dateValue + '?=' + dt);
13308             if(c.dateValue == dt){
13309                 ret = c;
13310                 return false;
13311             }
13312             return true;
13313         });
13314         
13315         return ret;
13316     },
13317     
13318     findCells : function(ev) {
13319         var s = ev.start.clone().clearTime().getTime();
13320        // Roo.log(s);
13321         var e= ev.end.clone().clearTime().getTime();
13322        // Roo.log(e);
13323         var ret = [];
13324         this.cells.each(function(c){
13325              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13326             
13327             if(c.dateValue > e){
13328                 return ;
13329             }
13330             if(c.dateValue < s){
13331                 return ;
13332             }
13333             ret.push(c);
13334         });
13335         
13336         return ret;    
13337     },
13338     
13339 //    findBestRow: function(cells)
13340 //    {
13341 //        var ret = 0;
13342 //        
13343 //        for (var i =0 ; i < cells.length;i++) {
13344 //            ret  = Math.max(cells[i].rows || 0,ret);
13345 //        }
13346 //        return ret;
13347 //        
13348 //    },
13349     
13350     
13351     addItem : function(ev)
13352     {
13353         // look for vertical location slot in
13354         var cells = this.findCells(ev);
13355         
13356 //        ev.row = this.findBestRow(cells);
13357         
13358         // work out the location.
13359         
13360         var crow = false;
13361         var rows = [];
13362         for(var i =0; i < cells.length; i++) {
13363             
13364             cells[i].row = cells[0].row;
13365             
13366             if(i == 0){
13367                 cells[i].row = cells[i].row + 1;
13368             }
13369             
13370             if (!crow) {
13371                 crow = {
13372                     start : cells[i],
13373                     end :  cells[i]
13374                 };
13375                 continue;
13376             }
13377             if (crow.start.getY() == cells[i].getY()) {
13378                 // on same row.
13379                 crow.end = cells[i];
13380                 continue;
13381             }
13382             // different row.
13383             rows.push(crow);
13384             crow = {
13385                 start: cells[i],
13386                 end : cells[i]
13387             };
13388             
13389         }
13390         
13391         rows.push(crow);
13392         ev.els = [];
13393         ev.rows = rows;
13394         ev.cells = cells;
13395         
13396         cells[0].events.push(ev);
13397         
13398         this.calevents.push(ev);
13399     },
13400     
13401     clearEvents: function() {
13402         
13403         if(!this.calevents){
13404             return;
13405         }
13406         
13407         Roo.each(this.cells.elements, function(c){
13408             c.row = 0;
13409             c.events = [];
13410             c.more = [];
13411         });
13412         
13413         Roo.each(this.calevents, function(e) {
13414             Roo.each(e.els, function(el) {
13415                 el.un('mouseenter' ,this.onEventEnter, this);
13416                 el.un('mouseleave' ,this.onEventLeave, this);
13417                 el.remove();
13418             },this);
13419         },this);
13420         
13421         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13422             e.remove();
13423         });
13424         
13425     },
13426     
13427     renderEvents: function()
13428     {   
13429         var _this = this;
13430         
13431         this.cells.each(function(c) {
13432             
13433             if(c.row < 5){
13434                 return;
13435             }
13436             
13437             var ev = c.events;
13438             
13439             var r = 4;
13440             if(c.row != c.events.length){
13441                 r = 4 - (4 - (c.row - c.events.length));
13442             }
13443             
13444             c.events = ev.slice(0, r);
13445             c.more = ev.slice(r);
13446             
13447             if(c.more.length && c.more.length == 1){
13448                 c.events.push(c.more.pop());
13449             }
13450             
13451             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13452             
13453         });
13454             
13455         this.cells.each(function(c) {
13456             
13457             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13458             
13459             
13460             for (var e = 0; e < c.events.length; e++){
13461                 var ev = c.events[e];
13462                 var rows = ev.rows;
13463                 
13464                 for(var i = 0; i < rows.length; i++) {
13465                 
13466                     // how many rows should it span..
13467
13468                     var  cfg = {
13469                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13470                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13471
13472                         unselectable : "on",
13473                         cn : [
13474                             {
13475                                 cls: 'fc-event-inner',
13476                                 cn : [
13477     //                                {
13478     //                                  tag:'span',
13479     //                                  cls: 'fc-event-time',
13480     //                                  html : cells.length > 1 ? '' : ev.time
13481     //                                },
13482                                     {
13483                                       tag:'span',
13484                                       cls: 'fc-event-title',
13485                                       html : String.format('{0}', ev.title)
13486                                     }
13487
13488
13489                                 ]
13490                             },
13491                             {
13492                                 cls: 'ui-resizable-handle ui-resizable-e',
13493                                 html : '&nbsp;&nbsp;&nbsp'
13494                             }
13495
13496                         ]
13497                     };
13498
13499                     if (i == 0) {
13500                         cfg.cls += ' fc-event-start';
13501                     }
13502                     if ((i+1) == rows.length) {
13503                         cfg.cls += ' fc-event-end';
13504                     }
13505
13506                     var ctr = _this.el.select('.fc-event-container',true).first();
13507                     var cg = ctr.createChild(cfg);
13508
13509                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13510                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13511
13512                     var r = (c.more.length) ? 1 : 0;
13513                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13514                     cg.setWidth(ebox.right - sbox.x -2);
13515
13516                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13517                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13518                     cg.on('click', _this.onEventClick, _this, ev);
13519
13520                     ev.els.push(cg);
13521                     
13522                 }
13523                 
13524             }
13525             
13526             
13527             if(c.more.length){
13528                 var  cfg = {
13529                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13530                     style : 'position: absolute',
13531                     unselectable : "on",
13532                     cn : [
13533                         {
13534                             cls: 'fc-event-inner',
13535                             cn : [
13536                                 {
13537                                   tag:'span',
13538                                   cls: 'fc-event-title',
13539                                   html : 'More'
13540                                 }
13541
13542
13543                             ]
13544                         },
13545                         {
13546                             cls: 'ui-resizable-handle ui-resizable-e',
13547                             html : '&nbsp;&nbsp;&nbsp'
13548                         }
13549
13550                     ]
13551                 };
13552
13553                 var ctr = _this.el.select('.fc-event-container',true).first();
13554                 var cg = ctr.createChild(cfg);
13555
13556                 var sbox = c.select('.fc-day-content',true).first().getBox();
13557                 var ebox = c.select('.fc-day-content',true).first().getBox();
13558                 //Roo.log(cg);
13559                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13560                 cg.setWidth(ebox.right - sbox.x -2);
13561
13562                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13563                 
13564             }
13565             
13566         });
13567         
13568         
13569         
13570     },
13571     
13572     onEventEnter: function (e, el,event,d) {
13573         this.fireEvent('evententer', this, el, event);
13574     },
13575     
13576     onEventLeave: function (e, el,event,d) {
13577         this.fireEvent('eventleave', this, el, event);
13578     },
13579     
13580     onEventClick: function (e, el,event,d) {
13581         this.fireEvent('eventclick', this, el, event);
13582     },
13583     
13584     onMonthChange: function () {
13585         this.store.load();
13586     },
13587     
13588     onMoreEventClick: function(e, el, more)
13589     {
13590         var _this = this;
13591         
13592         this.calpopover.placement = 'right';
13593         this.calpopover.setTitle('More');
13594         
13595         this.calpopover.setContent('');
13596         
13597         var ctr = this.calpopover.el.select('.popover-content', true).first();
13598         
13599         Roo.each(more, function(m){
13600             var cfg = {
13601                 cls : 'fc-event-hori fc-event-draggable',
13602                 html : m.title
13603             }
13604             var cg = ctr.createChild(cfg);
13605             
13606             cg.on('click', _this.onEventClick, _this, m);
13607         });
13608         
13609         this.calpopover.show(el);
13610         
13611         
13612     },
13613     
13614     onLoad: function () 
13615     {   
13616         this.calevents = [];
13617         var cal = this;
13618         
13619         if(this.store.getCount() > 0){
13620             this.store.data.each(function(d){
13621                cal.addItem({
13622                     id : d.data.id,
13623                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13624                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13625                     time : d.data.start_time,
13626                     title : d.data.title,
13627                     description : d.data.description,
13628                     venue : d.data.venue
13629                 });
13630             });
13631         }
13632         
13633         this.renderEvents();
13634         
13635         if(this.calevents.length && this.loadMask){
13636             this.maskEl.hide();
13637         }
13638     },
13639     
13640     onBeforeLoad: function()
13641     {
13642         this.clearEvents();
13643         if(this.loadMask){
13644             this.maskEl.show();
13645         }
13646     }
13647 });
13648
13649  
13650  /*
13651  * - LGPL
13652  *
13653  * element
13654  * 
13655  */
13656
13657 /**
13658  * @class Roo.bootstrap.Popover
13659  * @extends Roo.bootstrap.Component
13660  * Bootstrap Popover class
13661  * @cfg {String} html contents of the popover   (or false to use children..)
13662  * @cfg {String} title of popover (or false to hide)
13663  * @cfg {String} placement how it is placed
13664  * @cfg {String} trigger click || hover (or false to trigger manually)
13665  * @cfg {String} over what (parent or false to trigger manually.)
13666  * @cfg {Number} delay - delay before showing
13667  
13668  * @constructor
13669  * Create a new Popover
13670  * @param {Object} config The config object
13671  */
13672
13673 Roo.bootstrap.Popover = function(config){
13674     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13675 };
13676
13677 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13678     
13679     title: 'Fill in a title',
13680     html: false,
13681     
13682     placement : 'right',
13683     trigger : 'hover', // hover
13684     
13685     delay : 0,
13686     
13687     over: 'parent',
13688     
13689     can_build_overlaid : false,
13690     
13691     getChildContainer : function()
13692     {
13693         return this.el.select('.popover-content',true).first();
13694     },
13695     
13696     getAutoCreate : function(){
13697          Roo.log('make popover?');
13698         var cfg = {
13699            cls : 'popover roo-dynamic',
13700            style: 'display:block',
13701            cn : [
13702                 {
13703                     cls : 'arrow'
13704                 },
13705                 {
13706                     cls : 'popover-inner',
13707                     cn : [
13708                         {
13709                             tag: 'h3',
13710                             cls: 'popover-title',
13711                             html : this.title
13712                         },
13713                         {
13714                             cls : 'popover-content',
13715                             html : this.html
13716                         }
13717                     ]
13718                     
13719                 }
13720            ]
13721         };
13722         
13723         return cfg;
13724     },
13725     setTitle: function(str)
13726     {
13727         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13728     },
13729     setContent: function(str)
13730     {
13731         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13732     },
13733     // as it get's added to the bottom of the page.
13734     onRender : function(ct, position)
13735     {
13736         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13737         if(!this.el){
13738             var cfg = Roo.apply({},  this.getAutoCreate());
13739             cfg.id = Roo.id();
13740             
13741             if (this.cls) {
13742                 cfg.cls += ' ' + this.cls;
13743             }
13744             if (this.style) {
13745                 cfg.style = this.style;
13746             }
13747             Roo.log("adding to ")
13748             this.el = Roo.get(document.body).createChild(cfg, position);
13749             Roo.log(this.el);
13750         }
13751         this.initEvents();
13752     },
13753     
13754     initEvents : function()
13755     {
13756         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13757         this.el.enableDisplayMode('block');
13758         this.el.hide();
13759         if (this.over === false) {
13760             return; 
13761         }
13762         if (this.triggers === false) {
13763             return;
13764         }
13765         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13766         var triggers = this.trigger ? this.trigger.split(' ') : [];
13767         Roo.each(triggers, function(trigger) {
13768         
13769             if (trigger == 'click') {
13770                 on_el.on('click', this.toggle, this);
13771             } else if (trigger != 'manual') {
13772                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
13773                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13774       
13775                 on_el.on(eventIn  ,this.enter, this);
13776                 on_el.on(eventOut, this.leave, this);
13777             }
13778         }, this);
13779         
13780     },
13781     
13782     
13783     // private
13784     timeout : null,
13785     hoverState : null,
13786     
13787     toggle : function () {
13788         this.hoverState == 'in' ? this.leave() : this.enter();
13789     },
13790     
13791     enter : function () {
13792        
13793     
13794         clearTimeout(this.timeout);
13795     
13796         this.hoverState = 'in'
13797     
13798         if (!this.delay || !this.delay.show) {
13799             this.show();
13800             return 
13801         }
13802         var _t = this;
13803         this.timeout = setTimeout(function () {
13804             if (_t.hoverState == 'in') {
13805                 _t.show();
13806             }
13807         }, this.delay.show)
13808     },
13809     leave : function() {
13810         clearTimeout(this.timeout);
13811     
13812         this.hoverState = 'out'
13813     
13814         if (!this.delay || !this.delay.hide) {
13815             this.hide();
13816             return 
13817         }
13818         var _t = this;
13819         this.timeout = setTimeout(function () {
13820             if (_t.hoverState == 'out') {
13821                 _t.hide();
13822             }
13823         }, this.delay.hide)
13824     },
13825     
13826     show : function (on_el)
13827     {
13828         if (!on_el) {
13829             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13830         }
13831         // set content.
13832         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13833         if (this.html !== false) {
13834             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13835         }
13836         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13837         if (!this.title.length) {
13838             this.el.select('.popover-title',true).hide();
13839         }
13840         
13841         var placement = typeof this.placement == 'function' ?
13842             this.placement.call(this, this.el, on_el) :
13843             this.placement;
13844             
13845         var autoToken = /\s?auto?\s?/i;
13846         var autoPlace = autoToken.test(placement);
13847         if (autoPlace) {
13848             placement = placement.replace(autoToken, '') || 'top';
13849         }
13850         
13851         //this.el.detach()
13852         //this.el.setXY([0,0]);
13853         this.el.show();
13854         this.el.dom.style.display='block';
13855         this.el.addClass(placement);
13856         
13857         //this.el.appendTo(on_el);
13858         
13859         var p = this.getPosition();
13860         var box = this.el.getBox();
13861         
13862         if (autoPlace) {
13863             // fixme..
13864         }
13865         var align = Roo.bootstrap.Popover.alignment[placement]
13866         this.el.alignTo(on_el, align[0],align[1]);
13867         //var arrow = this.el.select('.arrow',true).first();
13868         //arrow.set(align[2], 
13869         
13870         this.el.addClass('in');
13871         this.hoverState = null;
13872         
13873         if (this.el.hasClass('fade')) {
13874             // fade it?
13875         }
13876         
13877     },
13878     hide : function()
13879     {
13880         this.el.setXY([0,0]);
13881         this.el.removeClass('in');
13882         this.el.hide();
13883         
13884     }
13885     
13886 });
13887
13888 Roo.bootstrap.Popover.alignment = {
13889     'left' : ['r-l', [-10,0], 'right'],
13890     'right' : ['l-r', [10,0], 'left'],
13891     'bottom' : ['t-b', [0,10], 'top'],
13892     'top' : [ 'b-t', [0,-10], 'bottom']
13893 };
13894
13895  /*
13896  * - LGPL
13897  *
13898  * Progress
13899  * 
13900  */
13901
13902 /**
13903  * @class Roo.bootstrap.Progress
13904  * @extends Roo.bootstrap.Component
13905  * Bootstrap Progress class
13906  * @cfg {Boolean} striped striped of the progress bar
13907  * @cfg {Boolean} active animated of the progress bar
13908  * 
13909  * 
13910  * @constructor
13911  * Create a new Progress
13912  * @param {Object} config The config object
13913  */
13914
13915 Roo.bootstrap.Progress = function(config){
13916     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13917 };
13918
13919 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
13920     
13921     striped : false,
13922     active: false,
13923     
13924     getAutoCreate : function(){
13925         var cfg = {
13926             tag: 'div',
13927             cls: 'progress'
13928         };
13929         
13930         
13931         if(this.striped){
13932             cfg.cls += ' progress-striped';
13933         }
13934       
13935         if(this.active){
13936             cfg.cls += ' active';
13937         }
13938         
13939         
13940         return cfg;
13941     }
13942    
13943 });
13944
13945  
13946
13947  /*
13948  * - LGPL
13949  *
13950  * ProgressBar
13951  * 
13952  */
13953
13954 /**
13955  * @class Roo.bootstrap.ProgressBar
13956  * @extends Roo.bootstrap.Component
13957  * Bootstrap ProgressBar class
13958  * @cfg {Number} aria_valuenow aria-value now
13959  * @cfg {Number} aria_valuemin aria-value min
13960  * @cfg {Number} aria_valuemax aria-value max
13961  * @cfg {String} label label for the progress bar
13962  * @cfg {String} panel (success | info | warning | danger )
13963  * @cfg {String} role role of the progress bar
13964  * @cfg {String} sr_only text
13965  * 
13966  * 
13967  * @constructor
13968  * Create a new ProgressBar
13969  * @param {Object} config The config object
13970  */
13971
13972 Roo.bootstrap.ProgressBar = function(config){
13973     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13974 };
13975
13976 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
13977     
13978     aria_valuenow : 0,
13979     aria_valuemin : 0,
13980     aria_valuemax : 100,
13981     label : false,
13982     panel : false,
13983     role : false,
13984     sr_only: false,
13985     
13986     getAutoCreate : function()
13987     {
13988         
13989         var cfg = {
13990             tag: 'div',
13991             cls: 'progress-bar',
13992             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13993         };
13994         
13995         if(this.sr_only){
13996             cfg.cn = {
13997                 tag: 'span',
13998                 cls: 'sr-only',
13999                 html: this.sr_only
14000             }
14001         }
14002         
14003         if(this.role){
14004             cfg.role = this.role;
14005         }
14006         
14007         if(this.aria_valuenow){
14008             cfg['aria-valuenow'] = this.aria_valuenow;
14009         }
14010         
14011         if(this.aria_valuemin){
14012             cfg['aria-valuemin'] = this.aria_valuemin;
14013         }
14014         
14015         if(this.aria_valuemax){
14016             cfg['aria-valuemax'] = this.aria_valuemax;
14017         }
14018         
14019         if(this.label && !this.sr_only){
14020             cfg.html = this.label;
14021         }
14022         
14023         if(this.panel){
14024             cfg.cls += ' progress-bar-' + this.panel;
14025         }
14026         
14027         return cfg;
14028     },
14029     
14030     update : function(aria_valuenow)
14031     {
14032         this.aria_valuenow = aria_valuenow;
14033         
14034         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14035     }
14036    
14037 });
14038
14039  
14040
14041  /*
14042  * - LGPL
14043  *
14044  * column
14045  * 
14046  */
14047
14048 /**
14049  * @class Roo.bootstrap.TabGroup
14050  * @extends Roo.bootstrap.Column
14051  * Bootstrap Column class
14052  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14053  * @cfg {Boolean} carousel true to make the group behave like a carousel
14054  * 
14055  * @constructor
14056  * Create a new TabGroup
14057  * @param {Object} config The config object
14058  */
14059
14060 Roo.bootstrap.TabGroup = function(config){
14061     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14062     if (!this.navId) {
14063         this.navId = Roo.id();
14064     }
14065     this.tabs = [];
14066     Roo.bootstrap.TabGroup.register(this);
14067     
14068 };
14069
14070 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14071     
14072     carousel : false,
14073     transition : false,
14074      
14075     getAutoCreate : function()
14076     {
14077         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14078         
14079         cfg.cls += ' tab-content';
14080         
14081         if (this.carousel) {
14082             cfg.cls += ' carousel slide';
14083             cfg.cn = [{
14084                cls : 'carousel-inner'
14085             }]
14086         }
14087         
14088         
14089         return cfg;
14090     },
14091     getChildContainer : function()
14092     {
14093         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14094     },
14095     
14096     /**
14097     * register a Navigation item
14098     * @param {Roo.bootstrap.NavItem} the navitem to add
14099     */
14100     register : function(item)
14101     {
14102         this.tabs.push( item);
14103         item.navId = this.navId; // not really needed..
14104     
14105     },
14106     
14107     getActivePanel : function()
14108     {
14109         var r = false;
14110         Roo.each(this.tabs, function(t) {
14111             if (t.active) {
14112                 r = t;
14113                 return false;
14114             }
14115             return null;
14116         });
14117         return r;
14118         
14119     },
14120     getPanelByName : function(n)
14121     {
14122         var r = false;
14123         Roo.each(this.tabs, function(t) {
14124             if (t.tabId == n) {
14125                 r = t;
14126                 return false;
14127             }
14128             return null;
14129         });
14130         return r;
14131     },
14132     indexOfPanel : function(p)
14133     {
14134         var r = false;
14135         Roo.each(this.tabs, function(t,i) {
14136             if (t.tabId == p.tabId) {
14137                 r = i;
14138                 return false;
14139             }
14140             return null;
14141         });
14142         return r;
14143     },
14144     /**
14145      * show a specific panel
14146      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14147      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14148      */
14149     showPanel : function (pan)
14150     {
14151         
14152         if (typeof(pan) == 'number') {
14153             pan = this.tabs[pan];
14154         }
14155         if (typeof(pan) == 'string') {
14156             pan = this.getPanelByName(pan);
14157         }
14158         if (pan.tabId == this.getActivePanel().tabId) {
14159             return true;
14160         }
14161         var cur = this.getActivePanel();
14162         
14163         if (false === cur.fireEvent('beforedeactivate')) {
14164             return false;
14165         }
14166         
14167         if (this.carousel) {
14168             this.transition = true;
14169             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14170             var lr = dir == 'next' ? 'left' : 'right';
14171             pan.el.addClass(dir); // or prev
14172             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14173             cur.el.addClass(lr); // or right
14174             pan.el.addClass(lr);
14175             
14176             var _this = this;
14177             cur.el.on('transitionend', function() {
14178                 Roo.log("trans end?");
14179                 
14180                 pan.el.removeClass([lr,dir]);
14181                 pan.setActive(true);
14182                 
14183                 cur.el.removeClass([lr]);
14184                 cur.setActive(false);
14185                 
14186                 _this.transition = false;
14187                 
14188             }, this, { single:  true } );
14189             return true;
14190         }
14191         
14192         cur.setActive(false);
14193         pan.setActive(true);
14194         return true;
14195         
14196     },
14197     showPanelNext : function()
14198     {
14199         var i = this.indexOfPanel(this.getActivePanel());
14200         if (i > this.tabs.length) {
14201             return;
14202         }
14203         this.showPanel(this.tabs[i+1]);
14204     },
14205     showPanelPrev : function()
14206     {
14207         var i = this.indexOfPanel(this.getActivePanel());
14208         if (i  < 1) {
14209             return;
14210         }
14211         this.showPanel(this.tabs[i-1]);
14212     }
14213     
14214     
14215   
14216 });
14217
14218  
14219
14220  
14221  
14222 Roo.apply(Roo.bootstrap.TabGroup, {
14223     
14224     groups: {},
14225      /**
14226     * register a Navigation Group
14227     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14228     */
14229     register : function(navgrp)
14230     {
14231         this.groups[navgrp.navId] = navgrp;
14232         
14233     },
14234     /**
14235     * fetch a Navigation Group based on the navigation ID
14236     * if one does not exist , it will get created.
14237     * @param {string} the navgroup to add
14238     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14239     */
14240     get: function(navId) {
14241         if (typeof(this.groups[navId]) == 'undefined') {
14242             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14243         }
14244         return this.groups[navId] ;
14245     }
14246     
14247     
14248     
14249 });
14250
14251  /*
14252  * - LGPL
14253  *
14254  * TabPanel
14255  * 
14256  */
14257
14258 /**
14259  * @class Roo.bootstrap.TabPanel
14260  * @extends Roo.bootstrap.Component
14261  * Bootstrap TabPanel class
14262  * @cfg {Boolean} active panel active
14263  * @cfg {String} html panel content
14264  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14265  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14266  * 
14267  * 
14268  * @constructor
14269  * Create a new TabPanel
14270  * @param {Object} config The config object
14271  */
14272
14273 Roo.bootstrap.TabPanel = function(config){
14274     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14275     this.addEvents({
14276         /**
14277              * @event changed
14278              * Fires when the active status changes
14279              * @param {Roo.bootstrap.TabPanel} this
14280              * @param {Boolean} state the new state
14281             
14282          */
14283         'changed': true,
14284         /**
14285              * @event beforedeactivate
14286              * Fires before a tab is de-activated - can be used to do validation on a form.
14287              * @param {Roo.bootstrap.TabPanel} this
14288              * @return {Boolean} false if there is an error
14289             
14290          */
14291         'beforedeactivate': true
14292      });
14293     
14294     this.tabId = this.tabId || Roo.id();
14295   
14296 };
14297
14298 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14299     
14300     active: false,
14301     html: false,
14302     tabId: false,
14303     navId : false,
14304     
14305     getAutoCreate : function(){
14306         var cfg = {
14307             tag: 'div',
14308             // item is needed for carousel - not sure if it has any effect otherwise
14309             cls: 'tab-pane item',
14310             html: this.html || ''
14311         };
14312         
14313         if(this.active){
14314             cfg.cls += ' active';
14315         }
14316         
14317         if(this.tabId){
14318             cfg.tabId = this.tabId;
14319         }
14320         
14321         
14322         return cfg;
14323     },
14324     
14325     initEvents:  function()
14326     {
14327         Roo.log('-------- init events on tab panel ---------');
14328         
14329         var p = this.parent();
14330         this.navId = this.navId || p.navId;
14331         
14332         if (typeof(this.navId) != 'undefined') {
14333             // not really needed.. but just in case.. parent should be a NavGroup.
14334             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14335             Roo.log(['register', tg, this]);
14336             tg.register(this);
14337         }
14338     },
14339     
14340     
14341     onRender : function(ct, position)
14342     {
14343        // Roo.log("Call onRender: " + this.xtype);
14344         
14345         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14346         
14347         
14348         
14349         
14350         
14351     },
14352     
14353     setActive: function(state)
14354     {
14355         Roo.log("panel - set active " + this.tabId + "=" + state);
14356         
14357         this.active = state;
14358         if (!state) {
14359             this.el.removeClass('active');
14360             
14361         } else  if (!this.el.hasClass('active')) {
14362             this.el.addClass('active');
14363         }
14364         this.fireEvent('changed', this, state);
14365     }
14366     
14367     
14368 });
14369  
14370
14371  
14372
14373  /*
14374  * - LGPL
14375  *
14376  * DateField
14377  * 
14378  */
14379
14380 /**
14381  * @class Roo.bootstrap.DateField
14382  * @extends Roo.bootstrap.Input
14383  * Bootstrap DateField class
14384  * @cfg {Number} weekStart default 0
14385  * @cfg {Number} weekStart default 0
14386  * @cfg {Number} viewMode default empty, (months|years)
14387  * @cfg {Number} minViewMode default empty, (months|years)
14388  * @cfg {Number} startDate default -Infinity
14389  * @cfg {Number} endDate default Infinity
14390  * @cfg {Boolean} todayHighlight default false
14391  * @cfg {Boolean} todayBtn default false
14392  * @cfg {Boolean} calendarWeeks default false
14393  * @cfg {Object} daysOfWeekDisabled default empty
14394  * 
14395  * @cfg {Boolean} keyboardNavigation default true
14396  * @cfg {String} language default en
14397  * 
14398  * @constructor
14399  * Create a new DateField
14400  * @param {Object} config The config object
14401  */
14402
14403 Roo.bootstrap.DateField = function(config){
14404     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14405      this.addEvents({
14406             /**
14407              * @event show
14408              * Fires when this field show.
14409              * @param {Roo.bootstrap.DateField} this
14410              * @param {Mixed} date The date value
14411              */
14412             show : true,
14413             /**
14414              * @event show
14415              * Fires when this field hide.
14416              * @param {Roo.bootstrap.DateField} this
14417              * @param {Mixed} date The date value
14418              */
14419             hide : true,
14420             /**
14421              * @event select
14422              * Fires when select a date.
14423              * @param {Roo.bootstrap.DateField} this
14424              * @param {Mixed} date The date value
14425              */
14426             select : true
14427         });
14428 };
14429
14430 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14431     
14432     /**
14433      * @cfg {String} format
14434      * The default date format string which can be overriden for localization support.  The format must be
14435      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14436      */
14437     format : "m/d/y",
14438     /**
14439      * @cfg {String} altFormats
14440      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14441      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14442      */
14443     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14444     
14445     weekStart : 0,
14446     
14447     viewMode : '',
14448     
14449     minViewMode : '',
14450     
14451     todayHighlight : false,
14452     
14453     todayBtn: false,
14454     
14455     language: 'en',
14456     
14457     keyboardNavigation: true,
14458     
14459     calendarWeeks: false,
14460     
14461     startDate: -Infinity,
14462     
14463     endDate: Infinity,
14464     
14465     daysOfWeekDisabled: [],
14466     
14467     _events: [],
14468     
14469     UTCDate: function()
14470     {
14471         return new Date(Date.UTC.apply(Date, arguments));
14472     },
14473     
14474     UTCToday: function()
14475     {
14476         var today = new Date();
14477         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14478     },
14479     
14480     getDate: function() {
14481             var d = this.getUTCDate();
14482             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14483     },
14484     
14485     getUTCDate: function() {
14486             return this.date;
14487     },
14488     
14489     setDate: function(d) {
14490             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14491     },
14492     
14493     setUTCDate: function(d) {
14494             this.date = d;
14495             this.setValue(this.formatDate(this.date));
14496     },
14497         
14498     onRender: function(ct, position)
14499     {
14500         
14501         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14502         
14503         this.language = this.language || 'en';
14504         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14505         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14506         
14507         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14508         this.format = this.format || 'm/d/y';
14509         this.isInline = false;
14510         this.isInput = true;
14511         this.component = this.el.select('.add-on', true).first() || false;
14512         this.component = (this.component && this.component.length === 0) ? false : this.component;
14513         this.hasInput = this.component && this.inputEL().length;
14514         
14515         if (typeof(this.minViewMode === 'string')) {
14516             switch (this.minViewMode) {
14517                 case 'months':
14518                     this.minViewMode = 1;
14519                     break;
14520                 case 'years':
14521                     this.minViewMode = 2;
14522                     break;
14523                 default:
14524                     this.minViewMode = 0;
14525                     break;
14526             }
14527         }
14528         
14529         if (typeof(this.viewMode === 'string')) {
14530             switch (this.viewMode) {
14531                 case 'months':
14532                     this.viewMode = 1;
14533                     break;
14534                 case 'years':
14535                     this.viewMode = 2;
14536                     break;
14537                 default:
14538                     this.viewMode = 0;
14539                     break;
14540             }
14541         }
14542                 
14543         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14544         
14545 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14546         
14547         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14548         
14549         this.picker().on('mousedown', this.onMousedown, this);
14550         this.picker().on('click', this.onClick, this);
14551         
14552         this.picker().addClass('datepicker-dropdown');
14553         
14554         this.startViewMode = this.viewMode;
14555         
14556         
14557         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14558             if(!this.calendarWeeks){
14559                 v.remove();
14560                 return;
14561             };
14562             
14563             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14564             v.attr('colspan', function(i, val){
14565                 return parseInt(val) + 1;
14566             });
14567         })
14568                         
14569         
14570         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14571         
14572         this.setStartDate(this.startDate);
14573         this.setEndDate(this.endDate);
14574         
14575         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14576         
14577         this.fillDow();
14578         this.fillMonths();
14579         this.update();
14580         this.showMode();
14581         
14582         if(this.isInline) {
14583             this.show();
14584         }
14585     },
14586     
14587     picker : function()
14588     {
14589         return this.pickerEl;
14590 //        return this.el.select('.datepicker', true).first();
14591     },
14592     
14593     fillDow: function()
14594     {
14595         var dowCnt = this.weekStart;
14596         
14597         var dow = {
14598             tag: 'tr',
14599             cn: [
14600                 
14601             ]
14602         };
14603         
14604         if(this.calendarWeeks){
14605             dow.cn.push({
14606                 tag: 'th',
14607                 cls: 'cw',
14608                 html: '&nbsp;'
14609             })
14610         }
14611         
14612         while (dowCnt < this.weekStart + 7) {
14613             dow.cn.push({
14614                 tag: 'th',
14615                 cls: 'dow',
14616                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14617             });
14618         }
14619         
14620         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14621     },
14622     
14623     fillMonths: function()
14624     {    
14625         var i = 0
14626         var months = this.picker().select('>.datepicker-months td', true).first();
14627         
14628         months.dom.innerHTML = '';
14629         
14630         while (i < 12) {
14631             var month = {
14632                 tag: 'span',
14633                 cls: 'month',
14634                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14635             }
14636             
14637             months.createChild(month);
14638         }
14639         
14640     },
14641     
14642     update: function()
14643     {
14644         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;
14645         
14646         if (this.date < this.startDate) {
14647             this.viewDate = new Date(this.startDate);
14648         } else if (this.date > this.endDate) {
14649             this.viewDate = new Date(this.endDate);
14650         } else {
14651             this.viewDate = new Date(this.date);
14652         }
14653         
14654         this.fill();
14655     },
14656     
14657     fill: function() 
14658     {
14659         var d = new Date(this.viewDate),
14660                 year = d.getUTCFullYear(),
14661                 month = d.getUTCMonth(),
14662                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14663                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14664                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14665                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14666                 currentDate = this.date && this.date.valueOf(),
14667                 today = this.UTCToday();
14668         
14669         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14670         
14671 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14672         
14673 //        this.picker.select('>tfoot th.today').
14674 //                                              .text(dates[this.language].today)
14675 //                                              .toggle(this.todayBtn !== false);
14676     
14677         this.updateNavArrows();
14678         this.fillMonths();
14679                                                 
14680         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14681         
14682         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14683          
14684         prevMonth.setUTCDate(day);
14685         
14686         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14687         
14688         var nextMonth = new Date(prevMonth);
14689         
14690         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14691         
14692         nextMonth = nextMonth.valueOf();
14693         
14694         var fillMonths = false;
14695         
14696         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14697         
14698         while(prevMonth.valueOf() < nextMonth) {
14699             var clsName = '';
14700             
14701             if (prevMonth.getUTCDay() === this.weekStart) {
14702                 if(fillMonths){
14703                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14704                 }
14705                     
14706                 fillMonths = {
14707                     tag: 'tr',
14708                     cn: []
14709                 };
14710                 
14711                 if(this.calendarWeeks){
14712                     // ISO 8601: First week contains first thursday.
14713                     // ISO also states week starts on Monday, but we can be more abstract here.
14714                     var
14715                     // Start of current week: based on weekstart/current date
14716                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14717                     // Thursday of this week
14718                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14719                     // First Thursday of year, year from thursday
14720                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14721                     // Calendar week: ms between thursdays, div ms per day, div 7 days
14722                     calWeek =  (th - yth) / 864e5 / 7 + 1;
14723                     
14724                     fillMonths.cn.push({
14725                         tag: 'td',
14726                         cls: 'cw',
14727                         html: calWeek
14728                     });
14729                 }
14730             }
14731             
14732             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14733                 clsName += ' old';
14734             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14735                 clsName += ' new';
14736             }
14737             if (this.todayHighlight &&
14738                 prevMonth.getUTCFullYear() == today.getFullYear() &&
14739                 prevMonth.getUTCMonth() == today.getMonth() &&
14740                 prevMonth.getUTCDate() == today.getDate()) {
14741                 clsName += ' today';
14742             }
14743             
14744             if (currentDate && prevMonth.valueOf() === currentDate) {
14745                 clsName += ' active';
14746             }
14747             
14748             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14749                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14750                     clsName += ' disabled';
14751             }
14752             
14753             fillMonths.cn.push({
14754                 tag: 'td',
14755                 cls: 'day ' + clsName,
14756                 html: prevMonth.getDate()
14757             })
14758             
14759             prevMonth.setDate(prevMonth.getDate()+1);
14760         }
14761           
14762         var currentYear = this.date && this.date.getUTCFullYear();
14763         var currentMonth = this.date && this.date.getUTCMonth();
14764         
14765         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14766         
14767         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14768             v.removeClass('active');
14769             
14770             if(currentYear === year && k === currentMonth){
14771                 v.addClass('active');
14772             }
14773             
14774             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14775                 v.addClass('disabled');
14776             }
14777             
14778         });
14779         
14780         
14781         year = parseInt(year/10, 10) * 10;
14782         
14783         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14784         
14785         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14786         
14787         year -= 1;
14788         for (var i = -1; i < 11; i++) {
14789             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14790                 tag: 'span',
14791                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14792                 html: year
14793             })
14794             
14795             year += 1;
14796         }
14797     },
14798     
14799     showMode: function(dir) 
14800     {
14801         if (dir) {
14802             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14803         }
14804         Roo.each(this.picker().select('>div',true).elements, function(v){
14805             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14806             v.hide();
14807         });
14808         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14809     },
14810     
14811     place: function()
14812     {
14813         if(this.isInline) return;
14814         
14815         this.picker().removeClass(['bottom', 'top']);
14816         
14817         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14818             /*
14819              * place to the top of element!
14820              *
14821              */
14822             
14823             this.picker().addClass('top');
14824             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
14825             
14826             return;
14827         }
14828         
14829         this.picker().addClass('bottom');
14830         
14831         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
14832     },
14833     
14834     parseDate : function(value)
14835     {
14836         if(!value || value instanceof Date){
14837             return value;
14838         }
14839         var v = Date.parseDate(value, this.format);
14840         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
14841             v = Date.parseDate(value, 'Y-m-d');
14842         }
14843         if(!v && this.altFormats){
14844             if(!this.altFormatsArray){
14845                 this.altFormatsArray = this.altFormats.split("|");
14846             }
14847             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14848                 v = Date.parseDate(value, this.altFormatsArray[i]);
14849             }
14850         }
14851         return v;
14852     },
14853     
14854     formatDate : function(date, fmt)
14855     {
14856         return (!date || !(date instanceof Date)) ?
14857         date : date.dateFormat(fmt || this.format);
14858     },
14859     
14860     onFocus : function()
14861     {
14862         Roo.bootstrap.DateField.superclass.onFocus.call(this);
14863         this.show();
14864     },
14865     
14866     onBlur : function()
14867     {
14868         Roo.bootstrap.DateField.superclass.onBlur.call(this);
14869         
14870         var d = this.inputEl().getValue();
14871         
14872         this.setValue(d);
14873                 
14874         this.hide();
14875     },
14876     
14877     show : function()
14878     {
14879         this.picker().show();
14880         this.update();
14881         this.place();
14882         
14883         this.fireEvent('show', this, this.date);
14884     },
14885     
14886     hide : function()
14887     {
14888         if(this.isInline) return;
14889         this.picker().hide();
14890         this.viewMode = this.startViewMode;
14891         this.showMode();
14892         
14893         this.fireEvent('hide', this, this.date);
14894         
14895     },
14896     
14897     onMousedown: function(e)
14898     {
14899         e.stopPropagation();
14900         e.preventDefault();
14901     },
14902     
14903     keyup: function(e)
14904     {
14905         Roo.bootstrap.DateField.superclass.keyup.call(this);
14906         this.update();
14907     },
14908
14909     setValue: function(v)
14910     {
14911         
14912         // v can be a string or a date..
14913         
14914         
14915         var d = new Date(this.parseDate(v) ).clearTime();
14916         
14917         Roo.log(d);
14918         Roo.log(d);
14919         if(isNaN(d.getTime())){
14920             this.date = this.viewDate = '';
14921             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
14922             return;
14923         }
14924         
14925         v = this.formatDate(d);
14926         
14927         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14928         
14929         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14930      
14931         this.update();
14932
14933         this.fireEvent('select', this, this.date);
14934         
14935     },
14936     
14937     getValue: function()
14938     {
14939         return this.formatDate(this.date);
14940     },
14941     
14942     fireKey: function(e)
14943     {
14944         if (!this.picker().isVisible()){
14945             if (e.keyCode == 27) // allow escape to hide and re-show picker
14946                 this.show();
14947             return;
14948         }
14949         
14950         var dateChanged = false,
14951         dir, day, month,
14952         newDate, newViewDate;
14953         
14954         switch(e.keyCode){
14955             case 27: // escape
14956                 this.hide();
14957                 e.preventDefault();
14958                 break;
14959             case 37: // left
14960             case 39: // right
14961                 if (!this.keyboardNavigation) break;
14962                 dir = e.keyCode == 37 ? -1 : 1;
14963                 
14964                 if (e.ctrlKey){
14965                     newDate = this.moveYear(this.date, dir);
14966                     newViewDate = this.moveYear(this.viewDate, dir);
14967                 } else if (e.shiftKey){
14968                     newDate = this.moveMonth(this.date, dir);
14969                     newViewDate = this.moveMonth(this.viewDate, dir);
14970                 } else {
14971                     newDate = new Date(this.date);
14972                     newDate.setUTCDate(this.date.getUTCDate() + dir);
14973                     newViewDate = new Date(this.viewDate);
14974                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14975                 }
14976                 if (this.dateWithinRange(newDate)){
14977                     this.date = newDate;
14978                     this.viewDate = newViewDate;
14979                     this.setValue(this.formatDate(this.date));
14980 //                    this.update();
14981                     e.preventDefault();
14982                     dateChanged = true;
14983                 }
14984                 break;
14985             case 38: // up
14986             case 40: // down
14987                 if (!this.keyboardNavigation) break;
14988                 dir = e.keyCode == 38 ? -1 : 1;
14989                 if (e.ctrlKey){
14990                     newDate = this.moveYear(this.date, dir);
14991                     newViewDate = this.moveYear(this.viewDate, dir);
14992                 } else if (e.shiftKey){
14993                     newDate = this.moveMonth(this.date, dir);
14994                     newViewDate = this.moveMonth(this.viewDate, dir);
14995                 } else {
14996                     newDate = new Date(this.date);
14997                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14998                     newViewDate = new Date(this.viewDate);
14999                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15000                 }
15001                 if (this.dateWithinRange(newDate)){
15002                     this.date = newDate;
15003                     this.viewDate = newViewDate;
15004                     this.setValue(this.formatDate(this.date));
15005 //                    this.update();
15006                     e.preventDefault();
15007                     dateChanged = true;
15008                 }
15009                 break;
15010             case 13: // enter
15011                 this.setValue(this.formatDate(this.date));
15012                 this.hide();
15013                 e.preventDefault();
15014                 break;
15015             case 9: // tab
15016                 this.setValue(this.formatDate(this.date));
15017                 this.hide();
15018                 break;
15019             case 16: // shift
15020             case 17: // ctrl
15021             case 18: // alt
15022                 break;
15023             default :
15024                 this.hide();
15025                 
15026         }
15027     },
15028     
15029     
15030     onClick: function(e) 
15031     {
15032         e.stopPropagation();
15033         e.preventDefault();
15034         
15035         var target = e.getTarget();
15036         
15037         if(target.nodeName.toLowerCase() === 'i'){
15038             target = Roo.get(target).dom.parentNode;
15039         }
15040         
15041         var nodeName = target.nodeName;
15042         var className = target.className;
15043         var html = target.innerHTML;
15044         //Roo.log(nodeName);
15045         
15046         switch(nodeName.toLowerCase()) {
15047             case 'th':
15048                 switch(className) {
15049                     case 'switch':
15050                         this.showMode(1);
15051                         break;
15052                     case 'prev':
15053                     case 'next':
15054                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15055                         switch(this.viewMode){
15056                                 case 0:
15057                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15058                                         break;
15059                                 case 1:
15060                                 case 2:
15061                                         this.viewDate = this.moveYear(this.viewDate, dir);
15062                                         break;
15063                         }
15064                         this.fill();
15065                         break;
15066                     case 'today':
15067                         var date = new Date();
15068                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15069 //                        this.fill()
15070                         this.setValue(this.formatDate(this.date));
15071                         
15072                         this.hide();
15073                         break;
15074                 }
15075                 break;
15076             case 'span':
15077                 if (className.indexOf('disabled') < 0) {
15078                     this.viewDate.setUTCDate(1);
15079                     if (className.indexOf('month') > -1) {
15080                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15081                     } else {
15082                         var year = parseInt(html, 10) || 0;
15083                         this.viewDate.setUTCFullYear(year);
15084                         
15085                     }
15086                     this.showMode(-1);
15087                     this.fill();
15088                 }
15089                 break;
15090                 
15091             case 'td':
15092                 //Roo.log(className);
15093                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15094                     var day = parseInt(html, 10) || 1;
15095                     var year = this.viewDate.getUTCFullYear(),
15096                         month = this.viewDate.getUTCMonth();
15097
15098                     if (className.indexOf('old') > -1) {
15099                         if(month === 0 ){
15100                             month = 11;
15101                             year -= 1;
15102                         }else{
15103                             month -= 1;
15104                         }
15105                     } else if (className.indexOf('new') > -1) {
15106                         if (month == 11) {
15107                             month = 0;
15108                             year += 1;
15109                         } else {
15110                             month += 1;
15111                         }
15112                     }
15113                     //Roo.log([year,month,day]);
15114                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15115                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15116 //                    this.fill();
15117                     //Roo.log(this.formatDate(this.date));
15118                     this.setValue(this.formatDate(this.date));
15119                     this.hide();
15120                 }
15121                 break;
15122         }
15123     },
15124     
15125     setStartDate: function(startDate)
15126     {
15127         this.startDate = startDate || -Infinity;
15128         if (this.startDate !== -Infinity) {
15129             this.startDate = this.parseDate(this.startDate);
15130         }
15131         this.update();
15132         this.updateNavArrows();
15133     },
15134
15135     setEndDate: function(endDate)
15136     {
15137         this.endDate = endDate || Infinity;
15138         if (this.endDate !== Infinity) {
15139             this.endDate = this.parseDate(this.endDate);
15140         }
15141         this.update();
15142         this.updateNavArrows();
15143     },
15144     
15145     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15146     {
15147         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15148         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15149             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15150         }
15151         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15152             return parseInt(d, 10);
15153         });
15154         this.update();
15155         this.updateNavArrows();
15156     },
15157     
15158     updateNavArrows: function() 
15159     {
15160         var d = new Date(this.viewDate),
15161         year = d.getUTCFullYear(),
15162         month = d.getUTCMonth();
15163         
15164         Roo.each(this.picker().select('.prev', true).elements, function(v){
15165             v.show();
15166             switch (this.viewMode) {
15167                 case 0:
15168
15169                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15170                         v.hide();
15171                     }
15172                     break;
15173                 case 1:
15174                 case 2:
15175                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15176                         v.hide();
15177                     }
15178                     break;
15179             }
15180         });
15181         
15182         Roo.each(this.picker().select('.next', true).elements, function(v){
15183             v.show();
15184             switch (this.viewMode) {
15185                 case 0:
15186
15187                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15188                         v.hide();
15189                     }
15190                     break;
15191                 case 1:
15192                 case 2:
15193                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15194                         v.hide();
15195                     }
15196                     break;
15197             }
15198         })
15199     },
15200     
15201     moveMonth: function(date, dir)
15202     {
15203         if (!dir) return date;
15204         var new_date = new Date(date.valueOf()),
15205         day = new_date.getUTCDate(),
15206         month = new_date.getUTCMonth(),
15207         mag = Math.abs(dir),
15208         new_month, test;
15209         dir = dir > 0 ? 1 : -1;
15210         if (mag == 1){
15211             test = dir == -1
15212             // If going back one month, make sure month is not current month
15213             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15214             ? function(){
15215                 return new_date.getUTCMonth() == month;
15216             }
15217             // If going forward one month, make sure month is as expected
15218             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15219             : function(){
15220                 return new_date.getUTCMonth() != new_month;
15221             };
15222             new_month = month + dir;
15223             new_date.setUTCMonth(new_month);
15224             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15225             if (new_month < 0 || new_month > 11)
15226                 new_month = (new_month + 12) % 12;
15227         } else {
15228             // For magnitudes >1, move one month at a time...
15229             for (var i=0; i<mag; i++)
15230                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15231                 new_date = this.moveMonth(new_date, dir);
15232             // ...then reset the day, keeping it in the new month
15233             new_month = new_date.getUTCMonth();
15234             new_date.setUTCDate(day);
15235             test = function(){
15236                 return new_month != new_date.getUTCMonth();
15237             };
15238         }
15239         // Common date-resetting loop -- if date is beyond end of month, make it
15240         // end of month
15241         while (test()){
15242             new_date.setUTCDate(--day);
15243             new_date.setUTCMonth(new_month);
15244         }
15245         return new_date;
15246     },
15247
15248     moveYear: function(date, dir)
15249     {
15250         return this.moveMonth(date, dir*12);
15251     },
15252
15253     dateWithinRange: function(date)
15254     {
15255         return date >= this.startDate && date <= this.endDate;
15256     },
15257
15258     
15259     remove: function() 
15260     {
15261         this.picker().remove();
15262     }
15263    
15264 });
15265
15266 Roo.apply(Roo.bootstrap.DateField,  {
15267     
15268     head : {
15269         tag: 'thead',
15270         cn: [
15271         {
15272             tag: 'tr',
15273             cn: [
15274             {
15275                 tag: 'th',
15276                 cls: 'prev',
15277                 html: '<i class="fa fa-arrow-left"/>'
15278             },
15279             {
15280                 tag: 'th',
15281                 cls: 'switch',
15282                 colspan: '5'
15283             },
15284             {
15285                 tag: 'th',
15286                 cls: 'next',
15287                 html: '<i class="fa fa-arrow-right"/>'
15288             }
15289
15290             ]
15291         }
15292         ]
15293     },
15294     
15295     content : {
15296         tag: 'tbody',
15297         cn: [
15298         {
15299             tag: 'tr',
15300             cn: [
15301             {
15302                 tag: 'td',
15303                 colspan: '7'
15304             }
15305             ]
15306         }
15307         ]
15308     },
15309     
15310     footer : {
15311         tag: 'tfoot',
15312         cn: [
15313         {
15314             tag: 'tr',
15315             cn: [
15316             {
15317                 tag: 'th',
15318                 colspan: '7',
15319                 cls: 'today'
15320             }
15321                     
15322             ]
15323         }
15324         ]
15325     },
15326     
15327     dates:{
15328         en: {
15329             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15330             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15331             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15332             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15333             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15334             today: "Today"
15335         }
15336     },
15337     
15338     modes: [
15339     {
15340         clsName: 'days',
15341         navFnc: 'Month',
15342         navStep: 1
15343     },
15344     {
15345         clsName: 'months',
15346         navFnc: 'FullYear',
15347         navStep: 1
15348     },
15349     {
15350         clsName: 'years',
15351         navFnc: 'FullYear',
15352         navStep: 10
15353     }]
15354 });
15355
15356 Roo.apply(Roo.bootstrap.DateField,  {
15357   
15358     template : {
15359         tag: 'div',
15360         cls: 'datepicker dropdown-menu',
15361         cn: [
15362         {
15363             tag: 'div',
15364             cls: 'datepicker-days',
15365             cn: [
15366             {
15367                 tag: 'table',
15368                 cls: 'table-condensed',
15369                 cn:[
15370                 Roo.bootstrap.DateField.head,
15371                 {
15372                     tag: 'tbody'
15373                 },
15374                 Roo.bootstrap.DateField.footer
15375                 ]
15376             }
15377             ]
15378         },
15379         {
15380             tag: 'div',
15381             cls: 'datepicker-months',
15382             cn: [
15383             {
15384                 tag: 'table',
15385                 cls: 'table-condensed',
15386                 cn:[
15387                 Roo.bootstrap.DateField.head,
15388                 Roo.bootstrap.DateField.content,
15389                 Roo.bootstrap.DateField.footer
15390                 ]
15391             }
15392             ]
15393         },
15394         {
15395             tag: 'div',
15396             cls: 'datepicker-years',
15397             cn: [
15398             {
15399                 tag: 'table',
15400                 cls: 'table-condensed',
15401                 cn:[
15402                 Roo.bootstrap.DateField.head,
15403                 Roo.bootstrap.DateField.content,
15404                 Roo.bootstrap.DateField.footer
15405                 ]
15406             }
15407             ]
15408         }
15409         ]
15410     }
15411 });
15412
15413  
15414
15415  /*
15416  * - LGPL
15417  *
15418  * TimeField
15419  * 
15420  */
15421
15422 /**
15423  * @class Roo.bootstrap.TimeField
15424  * @extends Roo.bootstrap.Input
15425  * Bootstrap DateField class
15426  * 
15427  * 
15428  * @constructor
15429  * Create a new TimeField
15430  * @param {Object} config The config object
15431  */
15432
15433 Roo.bootstrap.TimeField = function(config){
15434     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15435     this.addEvents({
15436             /**
15437              * @event show
15438              * Fires when this field show.
15439              * @param {Roo.bootstrap.DateField} this
15440              * @param {Mixed} date The date value
15441              */
15442             show : true,
15443             /**
15444              * @event show
15445              * Fires when this field hide.
15446              * @param {Roo.bootstrap.DateField} this
15447              * @param {Mixed} date The date value
15448              */
15449             hide : true,
15450             /**
15451              * @event select
15452              * Fires when select a date.
15453              * @param {Roo.bootstrap.DateField} this
15454              * @param {Mixed} date The date value
15455              */
15456             select : true
15457         });
15458 };
15459
15460 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15461     
15462     /**
15463      * @cfg {String} format
15464      * The default time format string which can be overriden for localization support.  The format must be
15465      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15466      */
15467     format : "H:i",
15468        
15469     onRender: function(ct, position)
15470     {
15471         
15472         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15473                 
15474         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15475         
15476         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15477         
15478         this.pop = this.picker().select('>.datepicker-time',true).first();
15479         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block' 
15480         
15481         this.picker().on('mousedown', this.onMousedown, this);
15482         this.picker().on('click', this.onClick, this);
15483         
15484         this.picker().addClass('datepicker-dropdown');
15485     
15486         this.fillTime();
15487         this.update();
15488             
15489         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15490         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15491         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15492         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15493         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15494         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15495
15496     },
15497     
15498     fireKey: function(e){
15499         if (!this.picker().isVisible()){
15500             if (e.keyCode == 27) // allow escape to hide and re-show picker
15501                 this.show();
15502             return;
15503         }
15504
15505         e.preventDefault();
15506         
15507         switch(e.keyCode){
15508             case 27: // escape
15509                 this.hide();
15510                 break;
15511             case 37: // left
15512             case 39: // right
15513                 this.onTogglePeriod();
15514                 break;
15515             case 38: // up
15516                 this.onIncrementMinutes();
15517                 break;
15518             case 40: // down
15519                 this.onDecrementMinutes();
15520                 break;
15521             case 13: // enter
15522             case 9: // tab
15523                 this.setTime();
15524                 break;
15525         }
15526     },
15527     
15528     onClick: function(e) {
15529         e.stopPropagation();
15530         e.preventDefault();
15531     },
15532     
15533     picker : function()
15534     {
15535         return this.el.select('.datepicker', true).first();
15536     },
15537     
15538     fillTime: function()
15539     {    
15540         var time = this.pop.select('tbody', true).first();
15541         
15542         time.dom.innerHTML = '';
15543         
15544         time.createChild({
15545             tag: 'tr',
15546             cn: [
15547                 {
15548                     tag: 'td',
15549                     cn: [
15550                         {
15551                             tag: 'a',
15552                             href: '#',
15553                             cls: 'btn',
15554                             cn: [
15555                                 {
15556                                     tag: 'span',
15557                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15558                                 }
15559                             ]
15560                         } 
15561                     ]
15562                 },
15563                 {
15564                     tag: 'td',
15565                     cls: 'separator'
15566                 },
15567                 {
15568                     tag: 'td',
15569                     cn: [
15570                         {
15571                             tag: 'a',
15572                             href: '#',
15573                             cls: 'btn',
15574                             cn: [
15575                                 {
15576                                     tag: 'span',
15577                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15578                                 }
15579                             ]
15580                         }
15581                     ]
15582                 },
15583                 {
15584                     tag: 'td',
15585                     cls: 'separator'
15586                 }
15587             ]
15588         });
15589         
15590         time.createChild({
15591             tag: 'tr',
15592             cn: [
15593                 {
15594                     tag: 'td',
15595                     cn: [
15596                         {
15597                             tag: 'span',
15598                             cls: 'timepicker-hour',
15599                             html: '00'
15600                         }  
15601                     ]
15602                 },
15603                 {
15604                     tag: 'td',
15605                     cls: 'separator',
15606                     html: ':'
15607                 },
15608                 {
15609                     tag: 'td',
15610                     cn: [
15611                         {
15612                             tag: 'span',
15613                             cls: 'timepicker-minute',
15614                             html: '00'
15615                         }  
15616                     ]
15617                 },
15618                 {
15619                     tag: 'td',
15620                     cls: 'separator'
15621                 },
15622                 {
15623                     tag: 'td',
15624                     cn: [
15625                         {
15626                             tag: 'button',
15627                             type: 'button',
15628                             cls: 'btn btn-primary period',
15629                             html: 'AM'
15630                             
15631                         }
15632                     ]
15633                 }
15634             ]
15635         });
15636         
15637         time.createChild({
15638             tag: 'tr',
15639             cn: [
15640                 {
15641                     tag: 'td',
15642                     cn: [
15643                         {
15644                             tag: 'a',
15645                             href: '#',
15646                             cls: 'btn',
15647                             cn: [
15648                                 {
15649                                     tag: 'span',
15650                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
15651                                 }
15652                             ]
15653                         }
15654                     ]
15655                 },
15656                 {
15657                     tag: 'td',
15658                     cls: 'separator'
15659                 },
15660                 {
15661                     tag: 'td',
15662                     cn: [
15663                         {
15664                             tag: 'a',
15665                             href: '#',
15666                             cls: 'btn',
15667                             cn: [
15668                                 {
15669                                     tag: 'span',
15670                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
15671                                 }
15672                             ]
15673                         }
15674                     ]
15675                 },
15676                 {
15677                     tag: 'td',
15678                     cls: 'separator'
15679                 }
15680             ]
15681         });
15682         
15683     },
15684     
15685     update: function()
15686     {
15687         
15688         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15689         
15690         this.fill();
15691     },
15692     
15693     fill: function() 
15694     {
15695         var hours = this.time.getHours();
15696         var minutes = this.time.getMinutes();
15697         var period = 'AM';
15698         
15699         if(hours > 11){
15700             period = 'PM';
15701         }
15702         
15703         if(hours == 0){
15704             hours = 12;
15705         }
15706         
15707         
15708         if(hours > 12){
15709             hours = hours - 12;
15710         }
15711         
15712         if(hours < 10){
15713             hours = '0' + hours;
15714         }
15715         
15716         if(minutes < 10){
15717             minutes = '0' + minutes;
15718         }
15719         
15720         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15721         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15722         this.pop.select('button', true).first().dom.innerHTML = period;
15723         
15724     },
15725     
15726     place: function()
15727     {   
15728         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15729         
15730         var cls = ['bottom'];
15731         
15732         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15733             cls.pop();
15734             cls.push('top');
15735         }
15736         
15737         cls.push('right');
15738         
15739         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15740             cls.pop();
15741             cls.push('left');
15742         }
15743         
15744         this.picker().addClass(cls.join('-'));
15745         
15746         var _this = this;
15747         
15748         Roo.each(cls, function(c){
15749             if(c == 'bottom'){
15750                 _this.picker().setTop(_this.inputEl().getHeight());
15751                 return;
15752             }
15753             if(c == 'top'){
15754                 _this.picker().setTop(0 - _this.picker().getHeight());
15755                 return;
15756             }
15757             
15758             if(c == 'left'){
15759                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15760                 return;
15761             }
15762             if(c == 'right'){
15763                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15764                 return;
15765             }
15766         });
15767         
15768     },
15769   
15770     onFocus : function()
15771     {
15772         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15773         this.show();
15774     },
15775     
15776     onBlur : function()
15777     {
15778         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15779         this.hide();
15780     },
15781     
15782     show : function()
15783     {
15784         this.picker().show();
15785         this.pop.show();
15786         this.update();
15787         this.place();
15788         
15789         this.fireEvent('show', this, this.date);
15790     },
15791     
15792     hide : function()
15793     {
15794         this.picker().hide();
15795         this.pop.hide();
15796         
15797         this.fireEvent('hide', this, this.date);
15798     },
15799     
15800     setTime : function()
15801     {
15802         this.hide();
15803         this.setValue(this.time.format(this.format));
15804         
15805         this.fireEvent('select', this, this.date);
15806         
15807         
15808     },
15809     
15810     onMousedown: function(e){
15811         e.stopPropagation();
15812         e.preventDefault();
15813     },
15814     
15815     onIncrementHours: function()
15816     {
15817         Roo.log('onIncrementHours');
15818         this.time = this.time.add(Date.HOUR, 1);
15819         this.update();
15820         
15821     },
15822     
15823     onDecrementHours: function()
15824     {
15825         Roo.log('onDecrementHours');
15826         this.time = this.time.add(Date.HOUR, -1);
15827         this.update();
15828     },
15829     
15830     onIncrementMinutes: function()
15831     {
15832         Roo.log('onIncrementMinutes');
15833         this.time = this.time.add(Date.MINUTE, 1);
15834         this.update();
15835     },
15836     
15837     onDecrementMinutes: function()
15838     {
15839         Roo.log('onDecrementMinutes');
15840         this.time = this.time.add(Date.MINUTE, -1);
15841         this.update();
15842     },
15843     
15844     onTogglePeriod: function()
15845     {
15846         Roo.log('onTogglePeriod');
15847         this.time = this.time.add(Date.HOUR, 12);
15848         this.update();
15849     }
15850     
15851    
15852 });
15853
15854 Roo.apply(Roo.bootstrap.TimeField,  {
15855     
15856     content : {
15857         tag: 'tbody',
15858         cn: [
15859             {
15860                 tag: 'tr',
15861                 cn: [
15862                 {
15863                     tag: 'td',
15864                     colspan: '7'
15865                 }
15866                 ]
15867             }
15868         ]
15869     },
15870     
15871     footer : {
15872         tag: 'tfoot',
15873         cn: [
15874             {
15875                 tag: 'tr',
15876                 cn: [
15877                 {
15878                     tag: 'th',
15879                     colspan: '7',
15880                     cls: '',
15881                     cn: [
15882                         {
15883                             tag: 'button',
15884                             cls: 'btn btn-info ok',
15885                             html: 'OK'
15886                         }
15887                     ]
15888                 }
15889
15890                 ]
15891             }
15892         ]
15893     }
15894 });
15895
15896 Roo.apply(Roo.bootstrap.TimeField,  {
15897   
15898     template : {
15899         tag: 'div',
15900         cls: 'datepicker dropdown-menu',
15901         cn: [
15902             {
15903                 tag: 'div',
15904                 cls: 'datepicker-time',
15905                 cn: [
15906                 {
15907                     tag: 'table',
15908                     cls: 'table-condensed',
15909                     cn:[
15910                     Roo.bootstrap.TimeField.content,
15911                     Roo.bootstrap.TimeField.footer
15912                     ]
15913                 }
15914                 ]
15915             }
15916         ]
15917     }
15918 });
15919
15920  
15921
15922  /*
15923  * - LGPL
15924  *
15925  * CheckBox
15926  * 
15927  */
15928
15929 /**
15930  * @class Roo.bootstrap.CheckBox
15931  * @extends Roo.bootstrap.Input
15932  * Bootstrap CheckBox class
15933  * 
15934  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15935  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15936  * @cfg {String} boxLabel The text that appears beside the checkbox
15937  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15938  * @cfg {Boolean} checked initnal the element
15939  * 
15940  * 
15941  * @constructor
15942  * Create a new CheckBox
15943  * @param {Object} config The config object
15944  */
15945
15946 Roo.bootstrap.CheckBox = function(config){
15947     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15948    
15949         this.addEvents({
15950             /**
15951             * @event check
15952             * Fires when the element is checked or unchecked.
15953             * @param {Roo.bootstrap.CheckBox} this This input
15954             * @param {Boolean} checked The new checked value
15955             */
15956            check : true
15957         });
15958 };
15959
15960 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
15961     
15962     inputType: 'checkbox',
15963     inputValue: 1,
15964     valueOff: 0,
15965     boxLabel: false,
15966     checked: false,
15967     weight : false,
15968     
15969     getAutoCreate : function()
15970     {
15971         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15972         
15973         var id = Roo.id();
15974         
15975         var cfg = {};
15976         
15977         cfg.cls = 'form-group checkbox' //input-group
15978         
15979         
15980         
15981         
15982         var input =  {
15983             tag: 'input',
15984             id : id,
15985             type : this.inputType,
15986             value : (!this.checked) ? this.valueOff : this.inputValue,
15987             cls : 'roo-checkbox', //'form-box',
15988             placeholder : this.placeholder || ''
15989             
15990         };
15991         
15992         if (this.weight) { // Validity check?
15993             cfg.cls += " checkbox-" + this.weight;
15994         }
15995         
15996         if (this.disabled) {
15997             input.disabled=true;
15998         }
15999         
16000         if(this.checked){
16001             input.checked = this.checked;
16002         }
16003         
16004         if (this.name) {
16005             input.name = this.name;
16006         }
16007         
16008         if (this.size) {
16009             input.cls += ' input-' + this.size;
16010         }
16011         
16012         var settings=this;
16013         ['xs','sm','md','lg'].map(function(size){
16014             if (settings[size]) {
16015                 cfg.cls += ' col-' + size + '-' + settings[size];
16016             }
16017         });
16018         
16019        
16020         
16021         var inputblock = input;
16022         
16023         
16024         
16025         
16026         if (this.before || this.after) {
16027             
16028             inputblock = {
16029                 cls : 'input-group',
16030                 cn :  [] 
16031             };
16032             if (this.before) {
16033                 inputblock.cn.push({
16034                     tag :'span',
16035                     cls : 'input-group-addon',
16036                     html : this.before
16037                 });
16038             }
16039             inputblock.cn.push(input);
16040             if (this.after) {
16041                 inputblock.cn.push({
16042                     tag :'span',
16043                     cls : 'input-group-addon',
16044                     html : this.after
16045                 });
16046             }
16047             
16048         };
16049         
16050         if (align ==='left' && this.fieldLabel.length) {
16051                 Roo.log("left and has label");
16052                 cfg.cn = [
16053                     
16054                     {
16055                         tag: 'label',
16056                         'for' :  id,
16057                         cls : 'control-label col-md-' + this.labelWidth,
16058                         html : this.fieldLabel
16059                         
16060                     },
16061                     {
16062                         cls : "col-md-" + (12 - this.labelWidth), 
16063                         cn: [
16064                             inputblock
16065                         ]
16066                     }
16067                     
16068                 ];
16069         } else if ( this.fieldLabel.length) {
16070                 Roo.log(" label");
16071                 cfg.cn = [
16072                    
16073                     {
16074                         tag: this.boxLabel ? 'span' : 'label',
16075                         'for': id,
16076                         cls: 'control-label box-input-label',
16077                         //cls : 'input-group-addon',
16078                         html : this.fieldLabel
16079                         
16080                     },
16081                     
16082                     inputblock
16083                     
16084                 ];
16085
16086         } else {
16087             
16088                 Roo.log(" no label && no align");
16089                 cfg.cn = [  inputblock ] ;
16090                 
16091                 
16092         };
16093          if(this.boxLabel){
16094             cfg.cn.push( {
16095                 tag: 'label',
16096                 'for': id,
16097                 cls: 'box-label',
16098                 html: this.boxLabel
16099                 
16100             });
16101         }
16102         
16103         
16104        
16105         return cfg;
16106         
16107     },
16108     
16109     /**
16110      * return the real input element.
16111      */
16112     inputEl: function ()
16113     {
16114         return this.el.select('input.roo-checkbox',true).first();
16115     },
16116     
16117     label: function()
16118     {
16119         return this.el.select('label.control-label',true).first();
16120     },
16121     
16122     initEvents : function()
16123     {
16124 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16125         
16126         this.inputEl().on('click', this.onClick,  this);
16127         
16128     },
16129     
16130     onClick : function()
16131     {   
16132         this.setChecked(!this.checked);
16133     },
16134     
16135     setChecked : function(state,suppressEvent)
16136     {
16137         this.checked = state;
16138         
16139         this.inputEl().dom.checked = state;
16140         
16141         if(suppressEvent !== true){
16142             this.fireEvent('check', this, state);
16143         }
16144         
16145         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16146         
16147     },
16148     
16149     setValue : function(v,suppressEvent)
16150     {
16151         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16152     }
16153     
16154 });
16155
16156  
16157 /*
16158  * - LGPL
16159  *
16160  * Radio
16161  * 
16162  */
16163
16164 /**
16165  * @class Roo.bootstrap.Radio
16166  * @extends Roo.bootstrap.CheckBox
16167  * Bootstrap Radio class
16168
16169  * @constructor
16170  * Create a new Radio
16171  * @param {Object} config The config object
16172  */
16173
16174 Roo.bootstrap.Radio = function(config){
16175     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16176    
16177 };
16178
16179 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
16180     
16181     inputType: 'radio',
16182     inputValue: '',
16183     valueOff: '',
16184     
16185     getAutoCreate : function()
16186     {
16187         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16188         
16189         var id = Roo.id();
16190         
16191         var cfg = {};
16192         
16193         cfg.cls = 'form-group radio' //input-group
16194         
16195         var input =  {
16196             tag: 'input',
16197             id : id,
16198             type : this.inputType,
16199             value : (!this.checked) ? this.valueOff : this.inputValue,
16200             cls : 'roo-radio',
16201             placeholder : this.placeholder || ''
16202             
16203         };
16204           if (this.weight) { // Validity check?
16205             cfg.cls += " radio-" + this.weight;
16206         }
16207         if (this.disabled) {
16208             input.disabled=true;
16209         }
16210         
16211         if(this.checked){
16212             input.checked = this.checked;
16213         }
16214         
16215         if (this.name) {
16216             input.name = this.name;
16217         }
16218         
16219         if (this.size) {
16220             input.cls += ' input-' + this.size;
16221         }
16222         
16223         var settings=this;
16224         ['xs','sm','md','lg'].map(function(size){
16225             if (settings[size]) {
16226                 cfg.cls += ' col-' + size + '-' + settings[size];
16227             }
16228         });
16229         
16230         var inputblock = input;
16231         
16232         if (this.before || this.after) {
16233             
16234             inputblock = {
16235                 cls : 'input-group',
16236                 cn :  [] 
16237             };
16238             if (this.before) {
16239                 inputblock.cn.push({
16240                     tag :'span',
16241                     cls : 'input-group-addon',
16242                     html : this.before
16243                 });
16244             }
16245             inputblock.cn.push(input);
16246             if (this.after) {
16247                 inputblock.cn.push({
16248                     tag :'span',
16249                     cls : 'input-group-addon',
16250                     html : this.after
16251                 });
16252             }
16253             
16254         };
16255         
16256         if (align ==='left' && this.fieldLabel.length) {
16257                 Roo.log("left and has label");
16258                 cfg.cn = [
16259                     
16260                     {
16261                         tag: 'label',
16262                         'for' :  id,
16263                         cls : 'control-label col-md-' + this.labelWidth,
16264                         html : this.fieldLabel
16265                         
16266                     },
16267                     {
16268                         cls : "col-md-" + (12 - this.labelWidth), 
16269                         cn: [
16270                             inputblock
16271                         ]
16272                     }
16273                     
16274                 ];
16275         } else if ( this.fieldLabel.length) {
16276                 Roo.log(" label");
16277                  cfg.cn = [
16278                    
16279                     {
16280                         tag: 'label',
16281                         'for': id,
16282                         cls: 'control-label box-input-label',
16283                         //cls : 'input-group-addon',
16284                         html : this.fieldLabel
16285                         
16286                     },
16287                     
16288                     inputblock
16289                     
16290                 ];
16291
16292         } else {
16293             
16294                    Roo.log(" no label && no align");
16295                 cfg.cn = [
16296                     
16297                         inputblock
16298                     
16299                 ];
16300                 
16301                 
16302         };
16303         
16304         if(this.boxLabel){
16305             cfg.cn.push({
16306                 tag: 'label',
16307                 'for': id,
16308                 cls: 'box-label',
16309                 html: this.boxLabel
16310             })
16311         }
16312         
16313         return cfg;
16314         
16315     },
16316     inputEl: function ()
16317     {
16318         return this.el.select('input.roo-radio',true).first();
16319     },
16320     onClick : function()
16321     {   
16322         this.setChecked(true);
16323     },
16324     
16325     setChecked : function(state,suppressEvent)
16326     {
16327         if(state){
16328             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16329                 v.dom.checked = false;
16330             });
16331         }
16332         
16333         this.checked = state;
16334         this.inputEl().dom.checked = state;
16335         
16336         if(suppressEvent !== true){
16337             this.fireEvent('check', this, state);
16338         }
16339         
16340         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16341         
16342     },
16343     
16344     getGroupValue : function()
16345     {
16346         var value = ''
16347         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16348             if(v.dom.checked == true){
16349                 value = v.dom.value;
16350             }
16351         });
16352         
16353         return value;
16354     },
16355     
16356     /**
16357      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
16358      * @return {Mixed} value The field value
16359      */
16360     getValue : function(){
16361         return this.getGroupValue();
16362     }
16363     
16364 });
16365
16366  
16367 //<script type="text/javascript">
16368
16369 /*
16370  * Based  Ext JS Library 1.1.1
16371  * Copyright(c) 2006-2007, Ext JS, LLC.
16372  * LGPL
16373  *
16374  */
16375  
16376 /**
16377  * @class Roo.HtmlEditorCore
16378  * @extends Roo.Component
16379  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16380  *
16381  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16382  */
16383
16384 Roo.HtmlEditorCore = function(config){
16385     
16386     
16387     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16388     
16389     
16390     this.addEvents({
16391         /**
16392          * @event initialize
16393          * Fires when the editor is fully initialized (including the iframe)
16394          * @param {Roo.HtmlEditorCore} this
16395          */
16396         initialize: true,
16397         /**
16398          * @event activate
16399          * Fires when the editor is first receives the focus. Any insertion must wait
16400          * until after this event.
16401          * @param {Roo.HtmlEditorCore} this
16402          */
16403         activate: true,
16404          /**
16405          * @event beforesync
16406          * Fires before the textarea is updated with content from the editor iframe. Return false
16407          * to cancel the sync.
16408          * @param {Roo.HtmlEditorCore} this
16409          * @param {String} html
16410          */
16411         beforesync: true,
16412          /**
16413          * @event beforepush
16414          * Fires before the iframe editor is updated with content from the textarea. Return false
16415          * to cancel the push.
16416          * @param {Roo.HtmlEditorCore} this
16417          * @param {String} html
16418          */
16419         beforepush: true,
16420          /**
16421          * @event sync
16422          * Fires when the textarea is updated with content from the editor iframe.
16423          * @param {Roo.HtmlEditorCore} this
16424          * @param {String} html
16425          */
16426         sync: true,
16427          /**
16428          * @event push
16429          * Fires when the iframe editor is updated with content from the textarea.
16430          * @param {Roo.HtmlEditorCore} this
16431          * @param {String} html
16432          */
16433         push: true,
16434         
16435         /**
16436          * @event editorevent
16437          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16438          * @param {Roo.HtmlEditorCore} this
16439          */
16440         editorevent: true
16441     });
16442     
16443     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16444     
16445     // defaults : white / black...
16446     this.applyBlacklists();
16447     
16448     
16449     
16450 };
16451
16452
16453 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
16454
16455
16456      /**
16457      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
16458      */
16459     
16460     owner : false,
16461     
16462      /**
16463      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
16464      *                        Roo.resizable.
16465      */
16466     resizable : false,
16467      /**
16468      * @cfg {Number} height (in pixels)
16469      */   
16470     height: 300,
16471    /**
16472      * @cfg {Number} width (in pixels)
16473      */   
16474     width: 500,
16475     
16476     /**
16477      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16478      * 
16479      */
16480     stylesheets: false,
16481     
16482     // id of frame..
16483     frameId: false,
16484     
16485     // private properties
16486     validationEvent : false,
16487     deferHeight: true,
16488     initialized : false,
16489     activated : false,
16490     sourceEditMode : false,
16491     onFocus : Roo.emptyFn,
16492     iframePad:3,
16493     hideMode:'offsets',
16494     
16495     clearUp: true,
16496     
16497     // blacklist + whitelisted elements..
16498     black: false,
16499     white: false,
16500      
16501     
16502
16503     /**
16504      * Protected method that will not generally be called directly. It
16505      * is called when the editor initializes the iframe with HTML contents. Override this method if you
16506      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16507      */
16508     getDocMarkup : function(){
16509         // body styles..
16510         var st = '';
16511         Roo.log(this.stylesheets);
16512         
16513         // inherit styels from page...?? 
16514         if (this.stylesheets === false) {
16515             
16516             Roo.get(document.head).select('style').each(function(node) {
16517                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16518             });
16519             
16520             Roo.get(document.head).select('link').each(function(node) { 
16521                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16522             });
16523             
16524         } else if (!this.stylesheets.length) {
16525                 // simple..
16526                 st = '<style type="text/css">' +
16527                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16528                    '</style>';
16529         } else {
16530             Roo.each(this.stylesheets, function(s) {
16531                 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
16532             });
16533             
16534         }
16535         
16536         st +=  '<style type="text/css">' +
16537             'IMG { cursor: pointer } ' +
16538         '</style>';
16539
16540         
16541         return '<html><head>' + st  +
16542             //<style type="text/css">' +
16543             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16544             //'</style>' +
16545             ' </head><body class="roo-htmleditor-body"></body></html>';
16546     },
16547
16548     // private
16549     onRender : function(ct, position)
16550     {
16551         var _t = this;
16552         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16553         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16554         
16555         
16556         this.el.dom.style.border = '0 none';
16557         this.el.dom.setAttribute('tabIndex', -1);
16558         this.el.addClass('x-hidden hide');
16559         
16560         
16561         
16562         if(Roo.isIE){ // fix IE 1px bogus margin
16563             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16564         }
16565        
16566         
16567         this.frameId = Roo.id();
16568         
16569          
16570         
16571         var iframe = this.owner.wrap.createChild({
16572             tag: 'iframe',
16573             cls: 'form-control', // bootstrap..
16574             id: this.frameId,
16575             name: this.frameId,
16576             frameBorder : 'no',
16577             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
16578         }, this.el
16579         );
16580         
16581         
16582         this.iframe = iframe.dom;
16583
16584          this.assignDocWin();
16585         
16586         this.doc.designMode = 'on';
16587        
16588         this.doc.open();
16589         this.doc.write(this.getDocMarkup());
16590         this.doc.close();
16591
16592         
16593         var task = { // must defer to wait for browser to be ready
16594             run : function(){
16595                 //console.log("run task?" + this.doc.readyState);
16596                 this.assignDocWin();
16597                 if(this.doc.body || this.doc.readyState == 'complete'){
16598                     try {
16599                         this.doc.designMode="on";
16600                     } catch (e) {
16601                         return;
16602                     }
16603                     Roo.TaskMgr.stop(task);
16604                     this.initEditor.defer(10, this);
16605                 }
16606             },
16607             interval : 10,
16608             duration: 10000,
16609             scope: this
16610         };
16611         Roo.TaskMgr.start(task);
16612
16613         
16614          
16615     },
16616
16617     // private
16618     onResize : function(w, h)
16619     {
16620          Roo.log('resize: ' +w + ',' + h );
16621         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16622         if(!this.iframe){
16623             return;
16624         }
16625         if(typeof w == 'number'){
16626             
16627             this.iframe.style.width = w + 'px';
16628         }
16629         if(typeof h == 'number'){
16630             
16631             this.iframe.style.height = h + 'px';
16632             if(this.doc){
16633                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16634             }
16635         }
16636         
16637     },
16638
16639     /**
16640      * Toggles the editor between standard and source edit mode.
16641      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16642      */
16643     toggleSourceEdit : function(sourceEditMode){
16644         
16645         this.sourceEditMode = sourceEditMode === true;
16646         
16647         if(this.sourceEditMode){
16648  
16649             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
16650             
16651         }else{
16652             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16653             //this.iframe.className = '';
16654             this.deferFocus();
16655         }
16656         //this.setSize(this.owner.wrap.getSize());
16657         //this.fireEvent('editmodechange', this, this.sourceEditMode);
16658     },
16659
16660     
16661   
16662
16663     /**
16664      * Protected method that will not generally be called directly. If you need/want
16665      * custom HTML cleanup, this is the method you should override.
16666      * @param {String} html The HTML to be cleaned
16667      * return {String} The cleaned HTML
16668      */
16669     cleanHtml : function(html){
16670         html = String(html);
16671         if(html.length > 5){
16672             if(Roo.isSafari){ // strip safari nonsense
16673                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16674             }
16675         }
16676         if(html == '&nbsp;'){
16677             html = '';
16678         }
16679         return html;
16680     },
16681
16682     /**
16683      * HTML Editor -> Textarea
16684      * Protected method that will not generally be called directly. Syncs the contents
16685      * of the editor iframe with the textarea.
16686      */
16687     syncValue : function(){
16688         if(this.initialized){
16689             var bd = (this.doc.body || this.doc.documentElement);
16690             //this.cleanUpPaste(); -- this is done else where and causes havoc..
16691             var html = bd.innerHTML;
16692             if(Roo.isSafari){
16693                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
16694                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
16695                 if(m && m[1]){
16696                     html = '<div style="'+m[0]+'">' + html + '</div>';
16697                 }
16698             }
16699             html = this.cleanHtml(html);
16700             // fix up the special chars.. normaly like back quotes in word...
16701             // however we do not want to do this with chinese..
16702             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
16703                 var cc = b.charCodeAt();
16704                 if (
16705                     (cc >= 0x4E00 && cc < 0xA000 ) ||
16706                     (cc >= 0x3400 && cc < 0x4E00 ) ||
16707                     (cc >= 0xf900 && cc < 0xfb00 )
16708                 ) {
16709                         return b;
16710                 }
16711                 return "&#"+cc+";" 
16712             });
16713             if(this.owner.fireEvent('beforesync', this, html) !== false){
16714                 this.el.dom.value = html;
16715                 this.owner.fireEvent('sync', this, html);
16716             }
16717         }
16718     },
16719
16720     /**
16721      * Protected method that will not generally be called directly. Pushes the value of the textarea
16722      * into the iframe editor.
16723      */
16724     pushValue : function(){
16725         if(this.initialized){
16726             var v = this.el.dom.value.trim();
16727             
16728 //            if(v.length < 1){
16729 //                v = '&#160;';
16730 //            }
16731             
16732             if(this.owner.fireEvent('beforepush', this, v) !== false){
16733                 var d = (this.doc.body || this.doc.documentElement);
16734                 d.innerHTML = v;
16735                 this.cleanUpPaste();
16736                 this.el.dom.value = d.innerHTML;
16737                 this.owner.fireEvent('push', this, v);
16738             }
16739         }
16740     },
16741
16742     // private
16743     deferFocus : function(){
16744         this.focus.defer(10, this);
16745     },
16746
16747     // doc'ed in Field
16748     focus : function(){
16749         if(this.win && !this.sourceEditMode){
16750             this.win.focus();
16751         }else{
16752             this.el.focus();
16753         }
16754     },
16755     
16756     assignDocWin: function()
16757     {
16758         var iframe = this.iframe;
16759         
16760          if(Roo.isIE){
16761             this.doc = iframe.contentWindow.document;
16762             this.win = iframe.contentWindow;
16763         } else {
16764 //            if (!Roo.get(this.frameId)) {
16765 //                return;
16766 //            }
16767 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16768 //            this.win = Roo.get(this.frameId).dom.contentWindow;
16769             
16770             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
16771                 return;
16772             }
16773             
16774             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
16775             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
16776         }
16777     },
16778     
16779     // private
16780     initEditor : function(){
16781         //console.log("INIT EDITOR");
16782         this.assignDocWin();
16783         
16784         
16785         
16786         this.doc.designMode="on";
16787         this.doc.open();
16788         this.doc.write(this.getDocMarkup());
16789         this.doc.close();
16790         
16791         var dbody = (this.doc.body || this.doc.documentElement);
16792         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16793         // this copies styles from the containing element into thsi one..
16794         // not sure why we need all of this..
16795         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16796         
16797         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16798         //ss['background-attachment'] = 'fixed'; // w3c
16799         dbody.bgProperties = 'fixed'; // ie
16800         //Roo.DomHelper.applyStyles(dbody, ss);
16801         Roo.EventManager.on(this.doc, {
16802             //'mousedown': this.onEditorEvent,
16803             'mouseup': this.onEditorEvent,
16804             'dblclick': this.onEditorEvent,
16805             'click': this.onEditorEvent,
16806             'keyup': this.onEditorEvent,
16807             buffer:100,
16808             scope: this
16809         });
16810         if(Roo.isGecko){
16811             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16812         }
16813         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16814             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16815         }
16816         this.initialized = true;
16817
16818         this.owner.fireEvent('initialize', this);
16819         this.pushValue();
16820     },
16821
16822     // private
16823     onDestroy : function(){
16824         
16825         
16826         
16827         if(this.rendered){
16828             
16829             //for (var i =0; i < this.toolbars.length;i++) {
16830             //    // fixme - ask toolbars for heights?
16831             //    this.toolbars[i].onDestroy();
16832            // }
16833             
16834             //this.wrap.dom.innerHTML = '';
16835             //this.wrap.remove();
16836         }
16837     },
16838
16839     // private
16840     onFirstFocus : function(){
16841         
16842         this.assignDocWin();
16843         
16844         
16845         this.activated = true;
16846          
16847     
16848         if(Roo.isGecko){ // prevent silly gecko errors
16849             this.win.focus();
16850             var s = this.win.getSelection();
16851             if(!s.focusNode || s.focusNode.nodeType != 3){
16852                 var r = s.getRangeAt(0);
16853                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16854                 r.collapse(true);
16855                 this.deferFocus();
16856             }
16857             try{
16858                 this.execCmd('useCSS', true);
16859                 this.execCmd('styleWithCSS', false);
16860             }catch(e){}
16861         }
16862         this.owner.fireEvent('activate', this);
16863     },
16864
16865     // private
16866     adjustFont: function(btn){
16867         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16868         //if(Roo.isSafari){ // safari
16869         //    adjust *= 2;
16870        // }
16871         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16872         if(Roo.isSafari){ // safari
16873             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16874             v =  (v < 10) ? 10 : v;
16875             v =  (v > 48) ? 48 : v;
16876             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16877             
16878         }
16879         
16880         
16881         v = Math.max(1, v+adjust);
16882         
16883         this.execCmd('FontSize', v  );
16884     },
16885
16886     onEditorEvent : function(e){
16887         this.owner.fireEvent('editorevent', this, e);
16888       //  this.updateToolbar();
16889         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16890     },
16891
16892     insertTag : function(tg)
16893     {
16894         // could be a bit smarter... -> wrap the current selected tRoo..
16895         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16896             
16897             range = this.createRange(this.getSelection());
16898             var wrappingNode = this.doc.createElement(tg.toLowerCase());
16899             wrappingNode.appendChild(range.extractContents());
16900             range.insertNode(wrappingNode);
16901
16902             return;
16903             
16904             
16905             
16906         }
16907         this.execCmd("formatblock",   tg);
16908         
16909     },
16910     
16911     insertText : function(txt)
16912     {
16913         
16914         
16915         var range = this.createRange();
16916         range.deleteContents();
16917                //alert(Sender.getAttribute('label'));
16918                
16919         range.insertNode(this.doc.createTextNode(txt));
16920     } ,
16921     
16922      
16923
16924     /**
16925      * Executes a Midas editor command on the editor document and performs necessary focus and
16926      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16927      * @param {String} cmd The Midas command
16928      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16929      */
16930     relayCmd : function(cmd, value){
16931         this.win.focus();
16932         this.execCmd(cmd, value);
16933         this.owner.fireEvent('editorevent', this);
16934         //this.updateToolbar();
16935         this.owner.deferFocus();
16936     },
16937
16938     /**
16939      * Executes a Midas editor command directly on the editor document.
16940      * For visual commands, you should use {@link #relayCmd} instead.
16941      * <b>This should only be called after the editor is initialized.</b>
16942      * @param {String} cmd The Midas command
16943      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16944      */
16945     execCmd : function(cmd, value){
16946         this.doc.execCommand(cmd, false, value === undefined ? null : value);
16947         this.syncValue();
16948     },
16949  
16950  
16951    
16952     /**
16953      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16954      * to insert tRoo.
16955      * @param {String} text | dom node.. 
16956      */
16957     insertAtCursor : function(text)
16958     {
16959         
16960         
16961         
16962         if(!this.activated){
16963             return;
16964         }
16965         /*
16966         if(Roo.isIE){
16967             this.win.focus();
16968             var r = this.doc.selection.createRange();
16969             if(r){
16970                 r.collapse(true);
16971                 r.pasteHTML(text);
16972                 this.syncValue();
16973                 this.deferFocus();
16974             
16975             }
16976             return;
16977         }
16978         */
16979         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16980             this.win.focus();
16981             
16982             
16983             // from jquery ui (MIT licenced)
16984             var range, node;
16985             var win = this.win;
16986             
16987             if (win.getSelection && win.getSelection().getRangeAt) {
16988                 range = win.getSelection().getRangeAt(0);
16989                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16990                 range.insertNode(node);
16991             } else if (win.document.selection && win.document.selection.createRange) {
16992                 // no firefox support
16993                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16994                 win.document.selection.createRange().pasteHTML(txt);
16995             } else {
16996                 // no firefox support
16997                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16998                 this.execCmd('InsertHTML', txt);
16999             } 
17000             
17001             this.syncValue();
17002             
17003             this.deferFocus();
17004         }
17005     },
17006  // private
17007     mozKeyPress : function(e){
17008         if(e.ctrlKey){
17009             var c = e.getCharCode(), cmd;
17010           
17011             if(c > 0){
17012                 c = String.fromCharCode(c).toLowerCase();
17013                 switch(c){
17014                     case 'b':
17015                         cmd = 'bold';
17016                         break;
17017                     case 'i':
17018                         cmd = 'italic';
17019                         break;
17020                     
17021                     case 'u':
17022                         cmd = 'underline';
17023                         break;
17024                     
17025                     case 'v':
17026                         this.cleanUpPaste.defer(100, this);
17027                         return;
17028                         
17029                 }
17030                 if(cmd){
17031                     this.win.focus();
17032                     this.execCmd(cmd);
17033                     this.deferFocus();
17034                     e.preventDefault();
17035                 }
17036                 
17037             }
17038         }
17039     },
17040
17041     // private
17042     fixKeys : function(){ // load time branching for fastest keydown performance
17043         if(Roo.isIE){
17044             return function(e){
17045                 var k = e.getKey(), r;
17046                 if(k == e.TAB){
17047                     e.stopEvent();
17048                     r = this.doc.selection.createRange();
17049                     if(r){
17050                         r.collapse(true);
17051                         r.pasteHTML('&#160;&#160;&#160;&#160;');
17052                         this.deferFocus();
17053                     }
17054                     return;
17055                 }
17056                 
17057                 if(k == e.ENTER){
17058                     r = this.doc.selection.createRange();
17059                     if(r){
17060                         var target = r.parentElement();
17061                         if(!target || target.tagName.toLowerCase() != 'li'){
17062                             e.stopEvent();
17063                             r.pasteHTML('<br />');
17064                             r.collapse(false);
17065                             r.select();
17066                         }
17067                     }
17068                 }
17069                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17070                     this.cleanUpPaste.defer(100, this);
17071                     return;
17072                 }
17073                 
17074                 
17075             };
17076         }else if(Roo.isOpera){
17077             return function(e){
17078                 var k = e.getKey();
17079                 if(k == e.TAB){
17080                     e.stopEvent();
17081                     this.win.focus();
17082                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
17083                     this.deferFocus();
17084                 }
17085                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17086                     this.cleanUpPaste.defer(100, this);
17087                     return;
17088                 }
17089                 
17090             };
17091         }else if(Roo.isSafari){
17092             return function(e){
17093                 var k = e.getKey();
17094                 
17095                 if(k == e.TAB){
17096                     e.stopEvent();
17097                     this.execCmd('InsertText','\t');
17098                     this.deferFocus();
17099                     return;
17100                 }
17101                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17102                     this.cleanUpPaste.defer(100, this);
17103                     return;
17104                 }
17105                 
17106              };
17107         }
17108     }(),
17109     
17110     getAllAncestors: function()
17111     {
17112         var p = this.getSelectedNode();
17113         var a = [];
17114         if (!p) {
17115             a.push(p); // push blank onto stack..
17116             p = this.getParentElement();
17117         }
17118         
17119         
17120         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17121             a.push(p);
17122             p = p.parentNode;
17123         }
17124         a.push(this.doc.body);
17125         return a;
17126     },
17127     lastSel : false,
17128     lastSelNode : false,
17129     
17130     
17131     getSelection : function() 
17132     {
17133         this.assignDocWin();
17134         return Roo.isIE ? this.doc.selection : this.win.getSelection();
17135     },
17136     
17137     getSelectedNode: function() 
17138     {
17139         // this may only work on Gecko!!!
17140         
17141         // should we cache this!!!!
17142         
17143         
17144         
17145          
17146         var range = this.createRange(this.getSelection()).cloneRange();
17147         
17148         if (Roo.isIE) {
17149             var parent = range.parentElement();
17150             while (true) {
17151                 var testRange = range.duplicate();
17152                 testRange.moveToElementText(parent);
17153                 if (testRange.inRange(range)) {
17154                     break;
17155                 }
17156                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17157                     break;
17158                 }
17159                 parent = parent.parentElement;
17160             }
17161             return parent;
17162         }
17163         
17164         // is ancestor a text element.
17165         var ac =  range.commonAncestorContainer;
17166         if (ac.nodeType == 3) {
17167             ac = ac.parentNode;
17168         }
17169         
17170         var ar = ac.childNodes;
17171          
17172         var nodes = [];
17173         var other_nodes = [];
17174         var has_other_nodes = false;
17175         for (var i=0;i<ar.length;i++) {
17176             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
17177                 continue;
17178             }
17179             // fullly contained node.
17180             
17181             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17182                 nodes.push(ar[i]);
17183                 continue;
17184             }
17185             
17186             // probably selected..
17187             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17188                 other_nodes.push(ar[i]);
17189                 continue;
17190             }
17191             // outer..
17192             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
17193                 continue;
17194             }
17195             
17196             
17197             has_other_nodes = true;
17198         }
17199         if (!nodes.length && other_nodes.length) {
17200             nodes= other_nodes;
17201         }
17202         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17203             return false;
17204         }
17205         
17206         return nodes[0];
17207     },
17208     createRange: function(sel)
17209     {
17210         // this has strange effects when using with 
17211         // top toolbar - not sure if it's a great idea.
17212         //this.editor.contentWindow.focus();
17213         if (typeof sel != "undefined") {
17214             try {
17215                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17216             } catch(e) {
17217                 return this.doc.createRange();
17218             }
17219         } else {
17220             return this.doc.createRange();
17221         }
17222     },
17223     getParentElement: function()
17224     {
17225         
17226         this.assignDocWin();
17227         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17228         
17229         var range = this.createRange(sel);
17230          
17231         try {
17232             var p = range.commonAncestorContainer;
17233             while (p.nodeType == 3) { // text node
17234                 p = p.parentNode;
17235             }
17236             return p;
17237         } catch (e) {
17238             return null;
17239         }
17240     
17241     },
17242     /***
17243      *
17244      * Range intersection.. the hard stuff...
17245      *  '-1' = before
17246      *  '0' = hits..
17247      *  '1' = after.
17248      *         [ -- selected range --- ]
17249      *   [fail]                        [fail]
17250      *
17251      *    basically..
17252      *      if end is before start or  hits it. fail.
17253      *      if start is after end or hits it fail.
17254      *
17255      *   if either hits (but other is outside. - then it's not 
17256      *   
17257      *    
17258      **/
17259     
17260     
17261     // @see http://www.thismuchiknow.co.uk/?p=64.
17262     rangeIntersectsNode : function(range, node)
17263     {
17264         var nodeRange = node.ownerDocument.createRange();
17265         try {
17266             nodeRange.selectNode(node);
17267         } catch (e) {
17268             nodeRange.selectNodeContents(node);
17269         }
17270     
17271         var rangeStartRange = range.cloneRange();
17272         rangeStartRange.collapse(true);
17273     
17274         var rangeEndRange = range.cloneRange();
17275         rangeEndRange.collapse(false);
17276     
17277         var nodeStartRange = nodeRange.cloneRange();
17278         nodeStartRange.collapse(true);
17279     
17280         var nodeEndRange = nodeRange.cloneRange();
17281         nodeEndRange.collapse(false);
17282     
17283         return rangeStartRange.compareBoundaryPoints(
17284                  Range.START_TO_START, nodeEndRange) == -1 &&
17285                rangeEndRange.compareBoundaryPoints(
17286                  Range.START_TO_START, nodeStartRange) == 1;
17287         
17288          
17289     },
17290     rangeCompareNode : function(range, node)
17291     {
17292         var nodeRange = node.ownerDocument.createRange();
17293         try {
17294             nodeRange.selectNode(node);
17295         } catch (e) {
17296             nodeRange.selectNodeContents(node);
17297         }
17298         
17299         
17300         range.collapse(true);
17301     
17302         nodeRange.collapse(true);
17303      
17304         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17305         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
17306          
17307         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17308         
17309         var nodeIsBefore   =  ss == 1;
17310         var nodeIsAfter    = ee == -1;
17311         
17312         if (nodeIsBefore && nodeIsAfter)
17313             return 0; // outer
17314         if (!nodeIsBefore && nodeIsAfter)
17315             return 1; //right trailed.
17316         
17317         if (nodeIsBefore && !nodeIsAfter)
17318             return 2;  // left trailed.
17319         // fully contined.
17320         return 3;
17321     },
17322
17323     // private? - in a new class?
17324     cleanUpPaste :  function()
17325     {
17326         // cleans up the whole document..
17327         Roo.log('cleanuppaste');
17328         
17329         this.cleanUpChildren(this.doc.body);
17330         var clean = this.cleanWordChars(this.doc.body.innerHTML);
17331         if (clean != this.doc.body.innerHTML) {
17332             this.doc.body.innerHTML = clean;
17333         }
17334         
17335     },
17336     
17337     cleanWordChars : function(input) {// change the chars to hex code
17338         var he = Roo.HtmlEditorCore;
17339         
17340         var output = input;
17341         Roo.each(he.swapCodes, function(sw) { 
17342             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17343             
17344             output = output.replace(swapper, sw[1]);
17345         });
17346         
17347         return output;
17348     },
17349     
17350     
17351     cleanUpChildren : function (n)
17352     {
17353         if (!n.childNodes.length) {
17354             return;
17355         }
17356         for (var i = n.childNodes.length-1; i > -1 ; i--) {
17357            this.cleanUpChild(n.childNodes[i]);
17358         }
17359     },
17360     
17361     
17362         
17363     
17364     cleanUpChild : function (node)
17365     {
17366         var ed = this;
17367         //console.log(node);
17368         if (node.nodeName == "#text") {
17369             // clean up silly Windows -- stuff?
17370             return; 
17371         }
17372         if (node.nodeName == "#comment") {
17373             node.parentNode.removeChild(node);
17374             // clean up silly Windows -- stuff?
17375             return; 
17376         }
17377         var lcname = node.tagName.toLowerCase();
17378         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17379         // whitelist of tags..
17380         
17381         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17382             // remove node.
17383             node.parentNode.removeChild(node);
17384             return;
17385             
17386         }
17387         
17388         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17389         
17390         // remove <a name=....> as rendering on yahoo mailer is borked with this.
17391         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17392         
17393         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17394         //    remove_keep_children = true;
17395         //}
17396         
17397         if (remove_keep_children) {
17398             this.cleanUpChildren(node);
17399             // inserts everything just before this node...
17400             while (node.childNodes.length) {
17401                 var cn = node.childNodes[0];
17402                 node.removeChild(cn);
17403                 node.parentNode.insertBefore(cn, node);
17404             }
17405             node.parentNode.removeChild(node);
17406             return;
17407         }
17408         
17409         if (!node.attributes || !node.attributes.length) {
17410             this.cleanUpChildren(node);
17411             return;
17412         }
17413         
17414         function cleanAttr(n,v)
17415         {
17416             
17417             if (v.match(/^\./) || v.match(/^\//)) {
17418                 return;
17419             }
17420             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17421                 return;
17422             }
17423             if (v.match(/^#/)) {
17424                 return;
17425             }
17426 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17427             node.removeAttribute(n);
17428             
17429         }
17430         
17431         var cwhite = this.cwhite;
17432         var cblack = this.cblack;
17433             
17434         function cleanStyle(n,v)
17435         {
17436             if (v.match(/expression/)) { //XSS?? should we even bother..
17437                 node.removeAttribute(n);
17438                 return;
17439             }
17440             
17441             var parts = v.split(/;/);
17442             var clean = [];
17443             
17444             Roo.each(parts, function(p) {
17445                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17446                 if (!p.length) {
17447                     return true;
17448                 }
17449                 var l = p.split(':').shift().replace(/\s+/g,'');
17450                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17451                 
17452                 if ( cwhite.length && cblack.indexOf(l) > -1) {
17453 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17454                     //node.removeAttribute(n);
17455                     return true;
17456                 }
17457                 //Roo.log()
17458                 // only allow 'c whitelisted system attributes'
17459                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
17460 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17461                     //node.removeAttribute(n);
17462                     return true;
17463                 }
17464                 
17465                 
17466                  
17467                 
17468                 clean.push(p);
17469                 return true;
17470             });
17471             if (clean.length) { 
17472                 node.setAttribute(n, clean.join(';'));
17473             } else {
17474                 node.removeAttribute(n);
17475             }
17476             
17477         }
17478         
17479         
17480         for (var i = node.attributes.length-1; i > -1 ; i--) {
17481             var a = node.attributes[i];
17482             //console.log(a);
17483             
17484             if (a.name.toLowerCase().substr(0,2)=='on')  {
17485                 node.removeAttribute(a.name);
17486                 continue;
17487             }
17488             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17489                 node.removeAttribute(a.name);
17490                 continue;
17491             }
17492             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17493                 cleanAttr(a.name,a.value); // fixme..
17494                 continue;
17495             }
17496             if (a.name == 'style') {
17497                 cleanStyle(a.name,a.value);
17498                 continue;
17499             }
17500             /// clean up MS crap..
17501             // tecnically this should be a list of valid class'es..
17502             
17503             
17504             if (a.name == 'class') {
17505                 if (a.value.match(/^Mso/)) {
17506                     node.className = '';
17507                 }
17508                 
17509                 if (a.value.match(/body/)) {
17510                     node.className = '';
17511                 }
17512                 continue;
17513             }
17514             
17515             // style cleanup!?
17516             // class cleanup?
17517             
17518         }
17519         
17520         
17521         this.cleanUpChildren(node);
17522         
17523         
17524     },
17525     /**
17526      * Clean up MS wordisms...
17527      */
17528     cleanWord : function(node)
17529     {
17530         var _t = this;
17531         var cleanWordChildren = function()
17532         {
17533             if (!node.childNodes.length) {
17534                 return;
17535             }
17536             for (var i = node.childNodes.length-1; i > -1 ; i--) {
17537                _t.cleanWord(node.childNodes[i]);
17538             }
17539         }
17540         
17541         
17542         if (!node) {
17543             this.cleanWord(this.doc.body);
17544             return;
17545         }
17546         if (node.nodeName == "#text") {
17547             // clean up silly Windows -- stuff?
17548             return; 
17549         }
17550         if (node.nodeName == "#comment") {
17551             node.parentNode.removeChild(node);
17552             // clean up silly Windows -- stuff?
17553             return; 
17554         }
17555         
17556         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17557             node.parentNode.removeChild(node);
17558             return;
17559         }
17560         
17561         // remove - but keep children..
17562         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17563             while (node.childNodes.length) {
17564                 var cn = node.childNodes[0];
17565                 node.removeChild(cn);
17566                 node.parentNode.insertBefore(cn, node);
17567             }
17568             node.parentNode.removeChild(node);
17569             cleanWordChildren();
17570             return;
17571         }
17572         // clean styles
17573         if (node.className.length) {
17574             
17575             var cn = node.className.split(/\W+/);
17576             var cna = [];
17577             Roo.each(cn, function(cls) {
17578                 if (cls.match(/Mso[a-zA-Z]+/)) {
17579                     return;
17580                 }
17581                 cna.push(cls);
17582             });
17583             node.className = cna.length ? cna.join(' ') : '';
17584             if (!cna.length) {
17585                 node.removeAttribute("class");
17586             }
17587         }
17588         
17589         if (node.hasAttribute("lang")) {
17590             node.removeAttribute("lang");
17591         }
17592         
17593         if (node.hasAttribute("style")) {
17594             
17595             var styles = node.getAttribute("style").split(";");
17596             var nstyle = [];
17597             Roo.each(styles, function(s) {
17598                 if (!s.match(/:/)) {
17599                     return;
17600                 }
17601                 var kv = s.split(":");
17602                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17603                     return;
17604                 }
17605                 // what ever is left... we allow.
17606                 nstyle.push(s);
17607             });
17608             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17609             if (!nstyle.length) {
17610                 node.removeAttribute('style');
17611             }
17612         }
17613         
17614         cleanWordChildren();
17615         
17616         
17617     },
17618     domToHTML : function(currentElement, depth, nopadtext) {
17619         
17620         depth = depth || 0;
17621         nopadtext = nopadtext || false;
17622     
17623         if (!currentElement) {
17624             return this.domToHTML(this.doc.body);
17625         }
17626         
17627         //Roo.log(currentElement);
17628         var j;
17629         var allText = false;
17630         var nodeName = currentElement.nodeName;
17631         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17632         
17633         if  (nodeName == '#text') {
17634             return currentElement.nodeValue;
17635         }
17636         
17637         
17638         var ret = '';
17639         if (nodeName != 'BODY') {
17640              
17641             var i = 0;
17642             // Prints the node tagName, such as <A>, <IMG>, etc
17643             if (tagName) {
17644                 var attr = [];
17645                 for(i = 0; i < currentElement.attributes.length;i++) {
17646                     // quoting?
17647                     var aname = currentElement.attributes.item(i).name;
17648                     if (!currentElement.attributes.item(i).value.length) {
17649                         continue;
17650                     }
17651                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17652                 }
17653                 
17654                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17655             } 
17656             else {
17657                 
17658                 // eack
17659             }
17660         } else {
17661             tagName = false;
17662         }
17663         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17664             return ret;
17665         }
17666         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17667             nopadtext = true;
17668         }
17669         
17670         
17671         // Traverse the tree
17672         i = 0;
17673         var currentElementChild = currentElement.childNodes.item(i);
17674         var allText = true;
17675         var innerHTML  = '';
17676         lastnode = '';
17677         while (currentElementChild) {
17678             // Formatting code (indent the tree so it looks nice on the screen)
17679             var nopad = nopadtext;
17680             if (lastnode == 'SPAN') {
17681                 nopad  = true;
17682             }
17683             // text
17684             if  (currentElementChild.nodeName == '#text') {
17685                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
17686                 if (!nopad && toadd.length > 80) {
17687                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
17688                 }
17689                 innerHTML  += toadd;
17690                 
17691                 i++;
17692                 currentElementChild = currentElement.childNodes.item(i);
17693                 lastNode = '';
17694                 continue;
17695             }
17696             allText = false;
17697             
17698             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
17699                 
17700             // Recursively traverse the tree structure of the child node
17701             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
17702             lastnode = currentElementChild.nodeName;
17703             i++;
17704             currentElementChild=currentElement.childNodes.item(i);
17705         }
17706         
17707         ret += innerHTML;
17708         
17709         if (!allText) {
17710                 // The remaining code is mostly for formatting the tree
17711             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
17712         }
17713         
17714         
17715         if (tagName) {
17716             ret+= "</"+tagName+">";
17717         }
17718         return ret;
17719         
17720     },
17721         
17722     applyBlacklists : function()
17723     {
17724         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
17725         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
17726         
17727         this.white = [];
17728         this.black = [];
17729         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
17730             if (b.indexOf(tag) > -1) {
17731                 return;
17732             }
17733             this.white.push(tag);
17734             
17735         }, this);
17736         
17737         Roo.each(w, function(tag) {
17738             if (b.indexOf(tag) > -1) {
17739                 return;
17740             }
17741             if (this.white.indexOf(tag) > -1) {
17742                 return;
17743             }
17744             this.white.push(tag);
17745             
17746         }, this);
17747         
17748         
17749         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
17750             if (w.indexOf(tag) > -1) {
17751                 return;
17752             }
17753             this.black.push(tag);
17754             
17755         }, this);
17756         
17757         Roo.each(b, function(tag) {
17758             if (w.indexOf(tag) > -1) {
17759                 return;
17760             }
17761             if (this.black.indexOf(tag) > -1) {
17762                 return;
17763             }
17764             this.black.push(tag);
17765             
17766         }, this);
17767         
17768         
17769         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
17770         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
17771         
17772         this.cwhite = [];
17773         this.cblack = [];
17774         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
17775             if (b.indexOf(tag) > -1) {
17776                 return;
17777             }
17778             this.cwhite.push(tag);
17779             
17780         }, this);
17781         
17782         Roo.each(w, function(tag) {
17783             if (b.indexOf(tag) > -1) {
17784                 return;
17785             }
17786             if (this.cwhite.indexOf(tag) > -1) {
17787                 return;
17788             }
17789             this.cwhite.push(tag);
17790             
17791         }, this);
17792         
17793         
17794         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
17795             if (w.indexOf(tag) > -1) {
17796                 return;
17797             }
17798             this.cblack.push(tag);
17799             
17800         }, this);
17801         
17802         Roo.each(b, function(tag) {
17803             if (w.indexOf(tag) > -1) {
17804                 return;
17805             }
17806             if (this.cblack.indexOf(tag) > -1) {
17807                 return;
17808             }
17809             this.cblack.push(tag);
17810             
17811         }, this);
17812     }
17813     
17814     // hide stuff that is not compatible
17815     /**
17816      * @event blur
17817      * @hide
17818      */
17819     /**
17820      * @event change
17821      * @hide
17822      */
17823     /**
17824      * @event focus
17825      * @hide
17826      */
17827     /**
17828      * @event specialkey
17829      * @hide
17830      */
17831     /**
17832      * @cfg {String} fieldClass @hide
17833      */
17834     /**
17835      * @cfg {String} focusClass @hide
17836      */
17837     /**
17838      * @cfg {String} autoCreate @hide
17839      */
17840     /**
17841      * @cfg {String} inputType @hide
17842      */
17843     /**
17844      * @cfg {String} invalidClass @hide
17845      */
17846     /**
17847      * @cfg {String} invalidText @hide
17848      */
17849     /**
17850      * @cfg {String} msgFx @hide
17851      */
17852     /**
17853      * @cfg {String} validateOnBlur @hide
17854      */
17855 });
17856
17857 Roo.HtmlEditorCore.white = [
17858         'area', 'br', 'img', 'input', 'hr', 'wbr',
17859         
17860        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
17861        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
17862        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
17863        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
17864        'table',   'ul',         'xmp', 
17865        
17866        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
17867       'thead',   'tr', 
17868      
17869       'dir', 'menu', 'ol', 'ul', 'dl',
17870        
17871       'embed',  'object'
17872 ];
17873
17874
17875 Roo.HtmlEditorCore.black = [
17876     //    'embed',  'object', // enable - backend responsiblity to clean thiese
17877         'applet', // 
17878         'base',   'basefont', 'bgsound', 'blink',  'body', 
17879         'frame',  'frameset', 'head',    'html',   'ilayer', 
17880         'iframe', 'layer',  'link',     'meta',    'object',   
17881         'script', 'style' ,'title',  'xml' // clean later..
17882 ];
17883 Roo.HtmlEditorCore.clean = [
17884     'script', 'style', 'title', 'xml'
17885 ];
17886 Roo.HtmlEditorCore.remove = [
17887     'font'
17888 ];
17889 // attributes..
17890
17891 Roo.HtmlEditorCore.ablack = [
17892     'on'
17893 ];
17894     
17895 Roo.HtmlEditorCore.aclean = [ 
17896     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
17897 ];
17898
17899 // protocols..
17900 Roo.HtmlEditorCore.pwhite= [
17901         'http',  'https',  'mailto'
17902 ];
17903
17904 // white listed style attributes.
17905 Roo.HtmlEditorCore.cwhite= [
17906       //  'text-align', /// default is to allow most things..
17907       
17908          
17909 //        'font-size'//??
17910 ];
17911
17912 // black listed style attributes.
17913 Roo.HtmlEditorCore.cblack= [
17914       //  'font-size' -- this can be set by the project 
17915 ];
17916
17917
17918 Roo.HtmlEditorCore.swapCodes   =[ 
17919     [    8211, "--" ], 
17920     [    8212, "--" ], 
17921     [    8216,  "'" ],  
17922     [    8217, "'" ],  
17923     [    8220, '"' ],  
17924     [    8221, '"' ],  
17925     [    8226, "*" ],  
17926     [    8230, "..." ]
17927 ]; 
17928
17929     /*
17930  * - LGPL
17931  *
17932  * HtmlEditor
17933  * 
17934  */
17935
17936 /**
17937  * @class Roo.bootstrap.HtmlEditor
17938  * @extends Roo.bootstrap.TextArea
17939  * Bootstrap HtmlEditor class
17940
17941  * @constructor
17942  * Create a new HtmlEditor
17943  * @param {Object} config The config object
17944  */
17945
17946 Roo.bootstrap.HtmlEditor = function(config){
17947     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17948     if (!this.toolbars) {
17949         this.toolbars = [];
17950     }
17951     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17952     this.addEvents({
17953             /**
17954              * @event initialize
17955              * Fires when the editor is fully initialized (including the iframe)
17956              * @param {HtmlEditor} this
17957              */
17958             initialize: true,
17959             /**
17960              * @event activate
17961              * Fires when the editor is first receives the focus. Any insertion must wait
17962              * until after this event.
17963              * @param {HtmlEditor} this
17964              */
17965             activate: true,
17966              /**
17967              * @event beforesync
17968              * Fires before the textarea is updated with content from the editor iframe. Return false
17969              * to cancel the sync.
17970              * @param {HtmlEditor} this
17971              * @param {String} html
17972              */
17973             beforesync: true,
17974              /**
17975              * @event beforepush
17976              * Fires before the iframe editor is updated with content from the textarea. Return false
17977              * to cancel the push.
17978              * @param {HtmlEditor} this
17979              * @param {String} html
17980              */
17981             beforepush: true,
17982              /**
17983              * @event sync
17984              * Fires when the textarea is updated with content from the editor iframe.
17985              * @param {HtmlEditor} this
17986              * @param {String} html
17987              */
17988             sync: true,
17989              /**
17990              * @event push
17991              * Fires when the iframe editor is updated with content from the textarea.
17992              * @param {HtmlEditor} this
17993              * @param {String} html
17994              */
17995             push: true,
17996              /**
17997              * @event editmodechange
17998              * Fires when the editor switches edit modes
17999              * @param {HtmlEditor} this
18000              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18001              */
18002             editmodechange: true,
18003             /**
18004              * @event editorevent
18005              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18006              * @param {HtmlEditor} this
18007              */
18008             editorevent: true,
18009             /**
18010              * @event firstfocus
18011              * Fires when on first focus - needed by toolbars..
18012              * @param {HtmlEditor} this
18013              */
18014             firstfocus: true,
18015             /**
18016              * @event autosave
18017              * Auto save the htmlEditor value as a file into Events
18018              * @param {HtmlEditor} this
18019              */
18020             autosave: true,
18021             /**
18022              * @event savedpreview
18023              * preview the saved version of htmlEditor
18024              * @param {HtmlEditor} this
18025              */
18026             savedpreview: true
18027         });
18028 };
18029
18030
18031 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
18032     
18033     
18034       /**
18035      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18036      */
18037     toolbars : false,
18038    
18039      /**
18040      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
18041      *                        Roo.resizable.
18042      */
18043     resizable : false,
18044      /**
18045      * @cfg {Number} height (in pixels)
18046      */   
18047     height: 300,
18048    /**
18049      * @cfg {Number} width (in pixels)
18050      */   
18051     width: false,
18052     
18053     /**
18054      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18055      * 
18056      */
18057     stylesheets: false,
18058     
18059     // id of frame..
18060     frameId: false,
18061     
18062     // private properties
18063     validationEvent : false,
18064     deferHeight: true,
18065     initialized : false,
18066     activated : false,
18067     
18068     onFocus : Roo.emptyFn,
18069     iframePad:3,
18070     hideMode:'offsets',
18071     
18072     
18073     tbContainer : false,
18074     
18075     toolbarContainer :function() {
18076         return this.wrap.select('.x-html-editor-tb',true).first();
18077     },
18078
18079     /**
18080      * Protected method that will not generally be called directly. It
18081      * is called when the editor creates its toolbar. Override this method if you need to
18082      * add custom toolbar buttons.
18083      * @param {HtmlEditor} editor
18084      */
18085     createToolbar : function(){
18086         
18087         Roo.log("create toolbars");
18088         
18089         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18090         this.toolbars[0].render(this.toolbarContainer());
18091         
18092         return;
18093         
18094 //        if (!editor.toolbars || !editor.toolbars.length) {
18095 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18096 //        }
18097 //        
18098 //        for (var i =0 ; i < editor.toolbars.length;i++) {
18099 //            editor.toolbars[i] = Roo.factory(
18100 //                    typeof(editor.toolbars[i]) == 'string' ?
18101 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
18102 //                Roo.bootstrap.HtmlEditor);
18103 //            editor.toolbars[i].init(editor);
18104 //        }
18105     },
18106
18107      
18108     // private
18109     onRender : function(ct, position)
18110     {
18111        // Roo.log("Call onRender: " + this.xtype);
18112         var _t = this;
18113         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18114       
18115         this.wrap = this.inputEl().wrap({
18116             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18117         });
18118         
18119         this.editorcore.onRender(ct, position);
18120          
18121         if (this.resizable) {
18122             this.resizeEl = new Roo.Resizable(this.wrap, {
18123                 pinned : true,
18124                 wrap: true,
18125                 dynamic : true,
18126                 minHeight : this.height,
18127                 height: this.height,
18128                 handles : this.resizable,
18129                 width: this.width,
18130                 listeners : {
18131                     resize : function(r, w, h) {
18132                         _t.onResize(w,h); // -something
18133                     }
18134                 }
18135             });
18136             
18137         }
18138         this.createToolbar(this);
18139        
18140         
18141         if(!this.width && this.resizable){
18142             this.setSize(this.wrap.getSize());
18143         }
18144         if (this.resizeEl) {
18145             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18146             // should trigger onReize..
18147         }
18148         
18149     },
18150
18151     // private
18152     onResize : function(w, h)
18153     {
18154         Roo.log('resize: ' +w + ',' + h );
18155         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18156         var ew = false;
18157         var eh = false;
18158         
18159         if(this.inputEl() ){
18160             if(typeof w == 'number'){
18161                 var aw = w - this.wrap.getFrameWidth('lr');
18162                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18163                 ew = aw;
18164             }
18165             if(typeof h == 'number'){
18166                  var tbh = -11;  // fixme it needs to tool bar size!
18167                 for (var i =0; i < this.toolbars.length;i++) {
18168                     // fixme - ask toolbars for heights?
18169                     tbh += this.toolbars[i].el.getHeight();
18170                     //if (this.toolbars[i].footer) {
18171                     //    tbh += this.toolbars[i].footer.el.getHeight();
18172                     //}
18173                 }
18174               
18175                 
18176                 
18177                 
18178                 
18179                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18180                 ah -= 5; // knock a few pixes off for look..
18181                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18182                 var eh = ah;
18183             }
18184         }
18185         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18186         this.editorcore.onResize(ew,eh);
18187         
18188     },
18189
18190     /**
18191      * Toggles the editor between standard and source edit mode.
18192      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18193      */
18194     toggleSourceEdit : function(sourceEditMode)
18195     {
18196         this.editorcore.toggleSourceEdit(sourceEditMode);
18197         
18198         if(this.editorcore.sourceEditMode){
18199             Roo.log('editor - showing textarea');
18200             
18201 //            Roo.log('in');
18202 //            Roo.log(this.syncValue());
18203             this.syncValue();
18204             this.inputEl().removeClass(['hide', 'x-hidden']);
18205             this.inputEl().dom.removeAttribute('tabIndex');
18206             this.inputEl().focus();
18207         }else{
18208             Roo.log('editor - hiding textarea');
18209 //            Roo.log('out')
18210 //            Roo.log(this.pushValue()); 
18211             this.pushValue();
18212             
18213             this.inputEl().addClass(['hide', 'x-hidden']);
18214             this.inputEl().dom.setAttribute('tabIndex', -1);
18215             //this.deferFocus();
18216         }
18217          
18218         if(this.resizable){
18219             this.setSize(this.wrap.getSize());
18220         }
18221         
18222         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18223     },
18224  
18225     // private (for BoxComponent)
18226     adjustSize : Roo.BoxComponent.prototype.adjustSize,
18227
18228     // private (for BoxComponent)
18229     getResizeEl : function(){
18230         return this.wrap;
18231     },
18232
18233     // private (for BoxComponent)
18234     getPositionEl : function(){
18235         return this.wrap;
18236     },
18237
18238     // private
18239     initEvents : function(){
18240         this.originalValue = this.getValue();
18241     },
18242
18243 //    /**
18244 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18245 //     * @method
18246 //     */
18247 //    markInvalid : Roo.emptyFn,
18248 //    /**
18249 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18250 //     * @method
18251 //     */
18252 //    clearInvalid : Roo.emptyFn,
18253
18254     setValue : function(v){
18255         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18256         this.editorcore.pushValue();
18257     },
18258
18259      
18260     // private
18261     deferFocus : function(){
18262         this.focus.defer(10, this);
18263     },
18264
18265     // doc'ed in Field
18266     focus : function(){
18267         this.editorcore.focus();
18268         
18269     },
18270       
18271
18272     // private
18273     onDestroy : function(){
18274         
18275         
18276         
18277         if(this.rendered){
18278             
18279             for (var i =0; i < this.toolbars.length;i++) {
18280                 // fixme - ask toolbars for heights?
18281                 this.toolbars[i].onDestroy();
18282             }
18283             
18284             this.wrap.dom.innerHTML = '';
18285             this.wrap.remove();
18286         }
18287     },
18288
18289     // private
18290     onFirstFocus : function(){
18291         //Roo.log("onFirstFocus");
18292         this.editorcore.onFirstFocus();
18293          for (var i =0; i < this.toolbars.length;i++) {
18294             this.toolbars[i].onFirstFocus();
18295         }
18296         
18297     },
18298     
18299     // private
18300     syncValue : function()
18301     {   
18302         this.editorcore.syncValue();
18303     },
18304     
18305     pushValue : function()
18306     {   
18307         this.editorcore.pushValue();
18308     }
18309      
18310     
18311     // hide stuff that is not compatible
18312     /**
18313      * @event blur
18314      * @hide
18315      */
18316     /**
18317      * @event change
18318      * @hide
18319      */
18320     /**
18321      * @event focus
18322      * @hide
18323      */
18324     /**
18325      * @event specialkey
18326      * @hide
18327      */
18328     /**
18329      * @cfg {String} fieldClass @hide
18330      */
18331     /**
18332      * @cfg {String} focusClass @hide
18333      */
18334     /**
18335      * @cfg {String} autoCreate @hide
18336      */
18337     /**
18338      * @cfg {String} inputType @hide
18339      */
18340     /**
18341      * @cfg {String} invalidClass @hide
18342      */
18343     /**
18344      * @cfg {String} invalidText @hide
18345      */
18346     /**
18347      * @cfg {String} msgFx @hide
18348      */
18349     /**
18350      * @cfg {String} validateOnBlur @hide
18351      */
18352 });
18353  
18354     
18355    
18356    
18357    
18358       
18359 Roo.namespace('Roo.bootstrap.htmleditor');
18360 /**
18361  * @class Roo.bootstrap.HtmlEditorToolbar1
18362  * Basic Toolbar
18363  * 
18364  * Usage:
18365  *
18366  new Roo.bootstrap.HtmlEditor({
18367     ....
18368     toolbars : [
18369         new Roo.bootstrap.HtmlEditorToolbar1({
18370             disable : { fonts: 1 , format: 1, ..., ... , ...],
18371             btns : [ .... ]
18372         })
18373     }
18374      
18375  * 
18376  * @cfg {Object} disable List of elements to disable..
18377  * @cfg {Array} btns List of additional buttons.
18378  * 
18379  * 
18380  * NEEDS Extra CSS? 
18381  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18382  */
18383  
18384 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18385 {
18386     
18387     Roo.apply(this, config);
18388     
18389     // default disabled, based on 'good practice'..
18390     this.disable = this.disable || {};
18391     Roo.applyIf(this.disable, {
18392         fontSize : true,
18393         colors : true,
18394         specialElements : true
18395     });
18396     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18397     
18398     this.editor = config.editor;
18399     this.editorcore = config.editor.editorcore;
18400     
18401     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18402     
18403     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18404     // dont call parent... till later.
18405 }
18406 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
18407      
18408     bar : true,
18409     
18410     editor : false,
18411     editorcore : false,
18412     
18413     
18414     formats : [
18415         "p" ,  
18416         "h1","h2","h3","h4","h5","h6", 
18417         "pre", "code", 
18418         "abbr", "acronym", "address", "cite", "samp", "var",
18419         'div','span'
18420     ],
18421     
18422     onRender : function(ct, position)
18423     {
18424        // Roo.log("Call onRender: " + this.xtype);
18425         
18426        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18427        Roo.log(this.el);
18428        this.el.dom.style.marginBottom = '0';
18429        var _this = this;
18430        var editorcore = this.editorcore;
18431        var editor= this.editor;
18432        
18433        var children = [];
18434        var btn = function(id,cmd , toggle, handler){
18435        
18436             var  event = toggle ? 'toggle' : 'click';
18437        
18438             var a = {
18439                 size : 'sm',
18440                 xtype: 'Button',
18441                 xns: Roo.bootstrap,
18442                 glyphicon : id,
18443                 cmd : id || cmd,
18444                 enableToggle:toggle !== false,
18445                 //html : 'submit'
18446                 pressed : toggle ? false : null,
18447                 listeners : {}
18448             }
18449             a.listeners[toggle ? 'toggle' : 'click'] = function() {
18450                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
18451             }
18452             children.push(a);
18453             return a;
18454        }
18455         
18456         var style = {
18457                 xtype: 'Button',
18458                 size : 'sm',
18459                 xns: Roo.bootstrap,
18460                 glyphicon : 'font',
18461                 //html : 'submit'
18462                 menu : {
18463                     xtype: 'Menu',
18464                     xns: Roo.bootstrap,
18465                     items:  []
18466                 }
18467         };
18468         Roo.each(this.formats, function(f) {
18469             style.menu.items.push({
18470                 xtype :'MenuItem',
18471                 xns: Roo.bootstrap,
18472                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18473                 tagname : f,
18474                 listeners : {
18475                     click : function()
18476                     {
18477                         editorcore.insertTag(this.tagname);
18478                         editor.focus();
18479                     }
18480                 }
18481                 
18482             });
18483         });
18484          children.push(style);   
18485             
18486             
18487         btn('bold',false,true);
18488         btn('italic',false,true);
18489         btn('align-left', 'justifyleft',true);
18490         btn('align-center', 'justifycenter',true);
18491         btn('align-right' , 'justifyright',true);
18492         btn('link', false, false, function(btn) {
18493             //Roo.log("create link?");
18494             var url = prompt(this.createLinkText, this.defaultLinkValue);
18495             if(url && url != 'http:/'+'/'){
18496                 this.editorcore.relayCmd('createlink', url);
18497             }
18498         }),
18499         btn('list','insertunorderedlist',true);
18500         btn('pencil', false,true, function(btn){
18501                 Roo.log(this);
18502                 
18503                 this.toggleSourceEdit(btn.pressed);
18504         });
18505         /*
18506         var cog = {
18507                 xtype: 'Button',
18508                 size : 'sm',
18509                 xns: Roo.bootstrap,
18510                 glyphicon : 'cog',
18511                 //html : 'submit'
18512                 menu : {
18513                     xtype: 'Menu',
18514                     xns: Roo.bootstrap,
18515                     items:  []
18516                 }
18517         };
18518         
18519         cog.menu.items.push({
18520             xtype :'MenuItem',
18521             xns: Roo.bootstrap,
18522             html : Clean styles,
18523             tagname : f,
18524             listeners : {
18525                 click : function()
18526                 {
18527                     editorcore.insertTag(this.tagname);
18528                     editor.focus();
18529                 }
18530             }
18531             
18532         });
18533        */
18534         
18535          
18536        this.xtype = 'NavSimplebar';
18537         
18538         for(var i=0;i< children.length;i++) {
18539             
18540             this.buttons.add(this.addxtypeChild(children[i]));
18541             
18542         }
18543         
18544         editor.on('editorevent', this.updateToolbar, this);
18545     },
18546     onBtnClick : function(id)
18547     {
18548        this.editorcore.relayCmd(id);
18549        this.editorcore.focus();
18550     },
18551     
18552     /**
18553      * Protected method that will not generally be called directly. It triggers
18554      * a toolbar update by reading the markup state of the current selection in the editor.
18555      */
18556     updateToolbar: function(){
18557
18558         if(!this.editorcore.activated){
18559             this.editor.onFirstFocus(); // is this neeed?
18560             return;
18561         }
18562
18563         var btns = this.buttons; 
18564         var doc = this.editorcore.doc;
18565         btns.get('bold').setActive(doc.queryCommandState('bold'));
18566         btns.get('italic').setActive(doc.queryCommandState('italic'));
18567         //btns.get('underline').setActive(doc.queryCommandState('underline'));
18568         
18569         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18570         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18571         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18572         
18573         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18574         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18575          /*
18576         
18577         var ans = this.editorcore.getAllAncestors();
18578         if (this.formatCombo) {
18579             
18580             
18581             var store = this.formatCombo.store;
18582             this.formatCombo.setValue("");
18583             for (var i =0; i < ans.length;i++) {
18584                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18585                     // select it..
18586                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18587                     break;
18588                 }
18589             }
18590         }
18591         
18592         
18593         
18594         // hides menus... - so this cant be on a menu...
18595         Roo.bootstrap.MenuMgr.hideAll();
18596         */
18597         Roo.bootstrap.MenuMgr.hideAll();
18598         //this.editorsyncValue();
18599     },
18600     onFirstFocus: function() {
18601         this.buttons.each(function(item){
18602            item.enable();
18603         });
18604     },
18605     toggleSourceEdit : function(sourceEditMode){
18606         
18607           
18608         if(sourceEditMode){
18609             Roo.log("disabling buttons");
18610            this.buttons.each( function(item){
18611                 if(item.cmd != 'pencil'){
18612                     item.disable();
18613                 }
18614             });
18615           
18616         }else{
18617             Roo.log("enabling buttons");
18618             if(this.editorcore.initialized){
18619                 this.buttons.each( function(item){
18620                     item.enable();
18621                 });
18622             }
18623             
18624         }
18625         Roo.log("calling toggole on editor");
18626         // tell the editor that it's been pressed..
18627         this.editor.toggleSourceEdit(sourceEditMode);
18628        
18629     }
18630 });
18631
18632
18633
18634
18635
18636 /**
18637  * @class Roo.bootstrap.Table.AbstractSelectionModel
18638  * @extends Roo.util.Observable
18639  * Abstract base class for grid SelectionModels.  It provides the interface that should be
18640  * implemented by descendant classes.  This class should not be directly instantiated.
18641  * @constructor
18642  */
18643 Roo.bootstrap.Table.AbstractSelectionModel = function(){
18644     this.locked = false;
18645     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
18646 };
18647
18648
18649 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
18650     /** @ignore Called by the grid automatically. Do not call directly. */
18651     init : function(grid){
18652         this.grid = grid;
18653         this.initEvents();
18654     },
18655
18656     /**
18657      * Locks the selections.
18658      */
18659     lock : function(){
18660         this.locked = true;
18661     },
18662
18663     /**
18664      * Unlocks the selections.
18665      */
18666     unlock : function(){
18667         this.locked = false;
18668     },
18669
18670     /**
18671      * Returns true if the selections are locked.
18672      * @return {Boolean}
18673      */
18674     isLocked : function(){
18675         return this.locked;
18676     }
18677 });
18678 /**
18679  * @extends Roo.bootstrap.Table.AbstractSelectionModel
18680  * @class Roo.bootstrap.Table.RowSelectionModel
18681  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
18682  * It supports multiple selections and keyboard selection/navigation. 
18683  * @constructor
18684  * @param {Object} config
18685  */
18686
18687 Roo.bootstrap.Table.RowSelectionModel = function(config){
18688     Roo.apply(this, config);
18689     this.selections = new Roo.util.MixedCollection(false, function(o){
18690         return o.id;
18691     });
18692
18693     this.last = false;
18694     this.lastActive = false;
18695
18696     this.addEvents({
18697         /**
18698              * @event selectionchange
18699              * Fires when the selection changes
18700              * @param {SelectionModel} this
18701              */
18702             "selectionchange" : true,
18703         /**
18704              * @event afterselectionchange
18705              * Fires after the selection changes (eg. by key press or clicking)
18706              * @param {SelectionModel} this
18707              */
18708             "afterselectionchange" : true,
18709         /**
18710              * @event beforerowselect
18711              * Fires when a row is selected being selected, return false to cancel.
18712              * @param {SelectionModel} this
18713              * @param {Number} rowIndex The selected index
18714              * @param {Boolean} keepExisting False if other selections will be cleared
18715              */
18716             "beforerowselect" : true,
18717         /**
18718              * @event rowselect
18719              * Fires when a row is selected.
18720              * @param {SelectionModel} this
18721              * @param {Number} rowIndex The selected index
18722              * @param {Roo.data.Record} r The record
18723              */
18724             "rowselect" : true,
18725         /**
18726              * @event rowdeselect
18727              * Fires when a row is deselected.
18728              * @param {SelectionModel} this
18729              * @param {Number} rowIndex The selected index
18730              */
18731         "rowdeselect" : true
18732     });
18733     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
18734     this.locked = false;
18735 };
18736
18737 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
18738     /**
18739      * @cfg {Boolean} singleSelect
18740      * True to allow selection of only one row at a time (defaults to false)
18741      */
18742     singleSelect : false,
18743
18744     // private
18745     initEvents : function(){
18746
18747         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
18748             this.grid.on("mousedown", this.handleMouseDown, this);
18749         }else{ // allow click to work like normal
18750             this.grid.on("rowclick", this.handleDragableRowClick, this);
18751         }
18752
18753         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
18754             "up" : function(e){
18755                 if(!e.shiftKey){
18756                     this.selectPrevious(e.shiftKey);
18757                 }else if(this.last !== false && this.lastActive !== false){
18758                     var last = this.last;
18759                     this.selectRange(this.last,  this.lastActive-1);
18760                     this.grid.getView().focusRow(this.lastActive);
18761                     if(last !== false){
18762                         this.last = last;
18763                     }
18764                 }else{
18765                     this.selectFirstRow();
18766                 }
18767                 this.fireEvent("afterselectionchange", this);
18768             },
18769             "down" : function(e){
18770                 if(!e.shiftKey){
18771                     this.selectNext(e.shiftKey);
18772                 }else if(this.last !== false && this.lastActive !== false){
18773                     var last = this.last;
18774                     this.selectRange(this.last,  this.lastActive+1);
18775                     this.grid.getView().focusRow(this.lastActive);
18776                     if(last !== false){
18777                         this.last = last;
18778                     }
18779                 }else{
18780                     this.selectFirstRow();
18781                 }
18782                 this.fireEvent("afterselectionchange", this);
18783             },
18784             scope: this
18785         });
18786
18787         var view = this.grid.view;
18788         view.on("refresh", this.onRefresh, this);
18789         view.on("rowupdated", this.onRowUpdated, this);
18790         view.on("rowremoved", this.onRemove, this);
18791     },
18792
18793     // private
18794     onRefresh : function(){
18795         var ds = this.grid.dataSource, i, v = this.grid.view;
18796         var s = this.selections;
18797         s.each(function(r){
18798             if((i = ds.indexOfId(r.id)) != -1){
18799                 v.onRowSelect(i);
18800             }else{
18801                 s.remove(r);
18802             }
18803         });
18804     },
18805
18806     // private
18807     onRemove : function(v, index, r){
18808         this.selections.remove(r);
18809     },
18810
18811     // private
18812     onRowUpdated : function(v, index, r){
18813         if(this.isSelected(r)){
18814             v.onRowSelect(index);
18815         }
18816     },
18817
18818     /**
18819      * Select records.
18820      * @param {Array} records The records to select
18821      * @param {Boolean} keepExisting (optional) True to keep existing selections
18822      */
18823     selectRecords : function(records, keepExisting){
18824         if(!keepExisting){
18825             this.clearSelections();
18826         }
18827         var ds = this.grid.dataSource;
18828         for(var i = 0, len = records.length; i < len; i++){
18829             this.selectRow(ds.indexOf(records[i]), true);
18830         }
18831     },
18832
18833     /**
18834      * Gets the number of selected rows.
18835      * @return {Number}
18836      */
18837     getCount : function(){
18838         return this.selections.length;
18839     },
18840
18841     /**
18842      * Selects the first row in the grid.
18843      */
18844     selectFirstRow : function(){
18845         this.selectRow(0);
18846     },
18847
18848     /**
18849      * Select the last row.
18850      * @param {Boolean} keepExisting (optional) True to keep existing selections
18851      */
18852     selectLastRow : function(keepExisting){
18853         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
18854     },
18855
18856     /**
18857      * Selects the row immediately following the last selected row.
18858      * @param {Boolean} keepExisting (optional) True to keep existing selections
18859      */
18860     selectNext : function(keepExisting){
18861         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
18862             this.selectRow(this.last+1, keepExisting);
18863             this.grid.getView().focusRow(this.last);
18864         }
18865     },
18866
18867     /**
18868      * Selects the row that precedes the last selected row.
18869      * @param {Boolean} keepExisting (optional) True to keep existing selections
18870      */
18871     selectPrevious : function(keepExisting){
18872         if(this.last){
18873             this.selectRow(this.last-1, keepExisting);
18874             this.grid.getView().focusRow(this.last);
18875         }
18876     },
18877
18878     /**
18879      * Returns the selected records
18880      * @return {Array} Array of selected records
18881      */
18882     getSelections : function(){
18883         return [].concat(this.selections.items);
18884     },
18885
18886     /**
18887      * Returns the first selected record.
18888      * @return {Record}
18889      */
18890     getSelected : function(){
18891         return this.selections.itemAt(0);
18892     },
18893
18894
18895     /**
18896      * Clears all selections.
18897      */
18898     clearSelections : function(fast){
18899         if(this.locked) return;
18900         if(fast !== true){
18901             var ds = this.grid.dataSource;
18902             var s = this.selections;
18903             s.each(function(r){
18904                 this.deselectRow(ds.indexOfId(r.id));
18905             }, this);
18906             s.clear();
18907         }else{
18908             this.selections.clear();
18909         }
18910         this.last = false;
18911     },
18912
18913
18914     /**
18915      * Selects all rows.
18916      */
18917     selectAll : function(){
18918         if(this.locked) return;
18919         this.selections.clear();
18920         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18921             this.selectRow(i, true);
18922         }
18923     },
18924
18925     /**
18926      * Returns True if there is a selection.
18927      * @return {Boolean}
18928      */
18929     hasSelection : function(){
18930         return this.selections.length > 0;
18931     },
18932
18933     /**
18934      * Returns True if the specified row is selected.
18935      * @param {Number/Record} record The record or index of the record to check
18936      * @return {Boolean}
18937      */
18938     isSelected : function(index){
18939         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18940         return (r && this.selections.key(r.id) ? true : false);
18941     },
18942
18943     /**
18944      * Returns True if the specified record id is selected.
18945      * @param {String} id The id of record to check
18946      * @return {Boolean}
18947      */
18948     isIdSelected : function(id){
18949         return (this.selections.key(id) ? true : false);
18950     },
18951
18952     // private
18953     handleMouseDown : function(e, t){
18954         var view = this.grid.getView(), rowIndex;
18955         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18956             return;
18957         };
18958         if(e.shiftKey && this.last !== false){
18959             var last = this.last;
18960             this.selectRange(last, rowIndex, e.ctrlKey);
18961             this.last = last; // reset the last
18962             view.focusRow(rowIndex);
18963         }else{
18964             var isSelected = this.isSelected(rowIndex);
18965             if(e.button !== 0 && isSelected){
18966                 view.focusRow(rowIndex);
18967             }else if(e.ctrlKey && isSelected){
18968                 this.deselectRow(rowIndex);
18969             }else if(!isSelected){
18970                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18971                 view.focusRow(rowIndex);
18972             }
18973         }
18974         this.fireEvent("afterselectionchange", this);
18975     },
18976     // private
18977     handleDragableRowClick :  function(grid, rowIndex, e) 
18978     {
18979         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18980             this.selectRow(rowIndex, false);
18981             grid.view.focusRow(rowIndex);
18982              this.fireEvent("afterselectionchange", this);
18983         }
18984     },
18985     
18986     /**
18987      * Selects multiple rows.
18988      * @param {Array} rows Array of the indexes of the row to select
18989      * @param {Boolean} keepExisting (optional) True to keep existing selections
18990      */
18991     selectRows : function(rows, keepExisting){
18992         if(!keepExisting){
18993             this.clearSelections();
18994         }
18995         for(var i = 0, len = rows.length; i < len; i++){
18996             this.selectRow(rows[i], true);
18997         }
18998     },
18999
19000     /**
19001      * Selects a range of rows. All rows in between startRow and endRow are also selected.
19002      * @param {Number} startRow The index of the first row in the range
19003      * @param {Number} endRow The index of the last row in the range
19004      * @param {Boolean} keepExisting (optional) True to retain existing selections
19005      */
19006     selectRange : function(startRow, endRow, keepExisting){
19007         if(this.locked) return;
19008         if(!keepExisting){
19009             this.clearSelections();
19010         }
19011         if(startRow <= endRow){
19012             for(var i = startRow; i <= endRow; i++){
19013                 this.selectRow(i, true);
19014             }
19015         }else{
19016             for(var i = startRow; i >= endRow; i--){
19017                 this.selectRow(i, true);
19018             }
19019         }
19020     },
19021
19022     /**
19023      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19024      * @param {Number} startRow The index of the first row in the range
19025      * @param {Number} endRow The index of the last row in the range
19026      */
19027     deselectRange : function(startRow, endRow, preventViewNotify){
19028         if(this.locked) return;
19029         for(var i = startRow; i <= endRow; i++){
19030             this.deselectRow(i, preventViewNotify);
19031         }
19032     },
19033
19034     /**
19035      * Selects a row.
19036      * @param {Number} row The index of the row to select
19037      * @param {Boolean} keepExisting (optional) True to keep existing selections
19038      */
19039     selectRow : function(index, keepExisting, preventViewNotify){
19040         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19041         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19042             if(!keepExisting || this.singleSelect){
19043                 this.clearSelections();
19044             }
19045             var r = this.grid.dataSource.getAt(index);
19046             this.selections.add(r);
19047             this.last = this.lastActive = index;
19048             if(!preventViewNotify){
19049                 this.grid.getView().onRowSelect(index);
19050             }
19051             this.fireEvent("rowselect", this, index, r);
19052             this.fireEvent("selectionchange", this);
19053         }
19054     },
19055
19056     /**
19057      * Deselects a row.
19058      * @param {Number} row The index of the row to deselect
19059      */
19060     deselectRow : function(index, preventViewNotify){
19061         if(this.locked) return;
19062         if(this.last == index){
19063             this.last = false;
19064         }
19065         if(this.lastActive == index){
19066             this.lastActive = false;
19067         }
19068         var r = this.grid.dataSource.getAt(index);
19069         this.selections.remove(r);
19070         if(!preventViewNotify){
19071             this.grid.getView().onRowDeselect(index);
19072         }
19073         this.fireEvent("rowdeselect", this, index);
19074         this.fireEvent("selectionchange", this);
19075     },
19076
19077     // private
19078     restoreLast : function(){
19079         if(this._last){
19080             this.last = this._last;
19081         }
19082     },
19083
19084     // private
19085     acceptsNav : function(row, col, cm){
19086         return !cm.isHidden(col) && cm.isCellEditable(col, row);
19087     },
19088
19089     // private
19090     onEditorKey : function(field, e){
19091         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19092         if(k == e.TAB){
19093             e.stopEvent();
19094             ed.completeEdit();
19095             if(e.shiftKey){
19096                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19097             }else{
19098                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19099             }
19100         }else if(k == e.ENTER && !e.ctrlKey){
19101             e.stopEvent();
19102             ed.completeEdit();
19103             if(e.shiftKey){
19104                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19105             }else{
19106                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19107             }
19108         }else if(k == e.ESC){
19109             ed.cancelEdit();
19110         }
19111         if(newCell){
19112             g.startEditing(newCell[0], newCell[1]);
19113         }
19114     }
19115 });/*
19116  * Based on:
19117  * Ext JS Library 1.1.1
19118  * Copyright(c) 2006-2007, Ext JS, LLC.
19119  *
19120  * Originally Released Under LGPL - original licence link has changed is not relivant.
19121  *
19122  * Fork - LGPL
19123  * <script type="text/javascript">
19124  */
19125  
19126 /**
19127  * @class Roo.bootstrap.PagingToolbar
19128  * @extends Roo.Row
19129  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19130  * @constructor
19131  * Create a new PagingToolbar
19132  * @param {Object} config The config object
19133  */
19134 Roo.bootstrap.PagingToolbar = function(config)
19135 {
19136     // old args format still supported... - xtype is prefered..
19137         // created from xtype...
19138     var ds = config.dataSource;
19139     this.toolbarItems = [];
19140     if (config.items) {
19141         this.toolbarItems = config.items;
19142 //        config.items = [];
19143     }
19144     
19145     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19146     this.ds = ds;
19147     this.cursor = 0;
19148     if (ds) { 
19149         this.bind(ds);
19150     }
19151     
19152     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19153     
19154 };
19155
19156 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19157     /**
19158      * @cfg {Roo.data.Store} dataSource
19159      * The underlying data store providing the paged data
19160      */
19161     /**
19162      * @cfg {String/HTMLElement/Element} container
19163      * container The id or element that will contain the toolbar
19164      */
19165     /**
19166      * @cfg {Boolean} displayInfo
19167      * True to display the displayMsg (defaults to false)
19168      */
19169     /**
19170      * @cfg {Number} pageSize
19171      * The number of records to display per page (defaults to 20)
19172      */
19173     pageSize: 20,
19174     /**
19175      * @cfg {String} displayMsg
19176      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19177      */
19178     displayMsg : 'Displaying {0} - {1} of {2}',
19179     /**
19180      * @cfg {String} emptyMsg
19181      * The message to display when no records are found (defaults to "No data to display")
19182      */
19183     emptyMsg : 'No data to display',
19184     /**
19185      * Customizable piece of the default paging text (defaults to "Page")
19186      * @type String
19187      */
19188     beforePageText : "Page",
19189     /**
19190      * Customizable piece of the default paging text (defaults to "of %0")
19191      * @type String
19192      */
19193     afterPageText : "of {0}",
19194     /**
19195      * Customizable piece of the default paging text (defaults to "First Page")
19196      * @type String
19197      */
19198     firstText : "First Page",
19199     /**
19200      * Customizable piece of the default paging text (defaults to "Previous Page")
19201      * @type String
19202      */
19203     prevText : "Previous Page",
19204     /**
19205      * Customizable piece of the default paging text (defaults to "Next Page")
19206      * @type String
19207      */
19208     nextText : "Next Page",
19209     /**
19210      * Customizable piece of the default paging text (defaults to "Last Page")
19211      * @type String
19212      */
19213     lastText : "Last Page",
19214     /**
19215      * Customizable piece of the default paging text (defaults to "Refresh")
19216      * @type String
19217      */
19218     refreshText : "Refresh",
19219
19220     buttons : false,
19221     // private
19222     onRender : function(ct, position) 
19223     {
19224         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19225         this.navgroup.parentId = this.id;
19226         this.navgroup.onRender(this.el, null);
19227         // add the buttons to the navgroup
19228         
19229         if(this.displayInfo){
19230             Roo.log(this.el.select('ul.navbar-nav',true).first());
19231             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19232             this.displayEl = this.el.select('.x-paging-info', true).first();
19233 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19234 //            this.displayEl = navel.el.select('span',true).first();
19235         }
19236         
19237         var _this = this;
19238         
19239         if(this.buttons){
19240             Roo.each(_this.buttons, function(e){
19241                Roo.factory(e).onRender(_this.el, null);
19242             });
19243         }
19244             
19245         Roo.each(_this.toolbarItems, function(e) {
19246             _this.navgroup.addItem(e);
19247         });
19248         
19249         this.first = this.navgroup.addItem({
19250             tooltip: this.firstText,
19251             cls: "prev",
19252             icon : 'fa fa-backward',
19253             disabled: true,
19254             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19255         });
19256         
19257         this.prev =  this.navgroup.addItem({
19258             tooltip: this.prevText,
19259             cls: "prev",
19260             icon : 'fa fa-step-backward',
19261             disabled: true,
19262             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
19263         });
19264     //this.addSeparator();
19265         
19266         
19267         var field = this.navgroup.addItem( {
19268             tagtype : 'span',
19269             cls : 'x-paging-position',
19270             
19271             html : this.beforePageText  +
19272                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19273                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
19274          } ); //?? escaped?
19275         
19276         this.field = field.el.select('input', true).first();
19277         this.field.on("keydown", this.onPagingKeydown, this);
19278         this.field.on("focus", function(){this.dom.select();});
19279     
19280     
19281         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
19282         //this.field.setHeight(18);
19283         //this.addSeparator();
19284         this.next = this.navgroup.addItem({
19285             tooltip: this.nextText,
19286             cls: "next",
19287             html : ' <i class="fa fa-step-forward">',
19288             disabled: true,
19289             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
19290         });
19291         this.last = this.navgroup.addItem({
19292             tooltip: this.lastText,
19293             icon : 'fa fa-forward',
19294             cls: "next",
19295             disabled: true,
19296             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
19297         });
19298     //this.addSeparator();
19299         this.loading = this.navgroup.addItem({
19300             tooltip: this.refreshText,
19301             icon: 'fa fa-refresh',
19302             
19303             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19304         });
19305
19306     },
19307
19308     // private
19309     updateInfo : function(){
19310         if(this.displayEl){
19311             var count = this.ds.getCount();
19312             var msg = count == 0 ?
19313                 this.emptyMsg :
19314                 String.format(
19315                     this.displayMsg,
19316                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
19317                 );
19318             this.displayEl.update(msg);
19319         }
19320     },
19321
19322     // private
19323     onLoad : function(ds, r, o){
19324        this.cursor = o.params ? o.params.start : 0;
19325        var d = this.getPageData(),
19326             ap = d.activePage,
19327             ps = d.pages;
19328         
19329        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19330        this.field.dom.value = ap;
19331        this.first.setDisabled(ap == 1);
19332        this.prev.setDisabled(ap == 1);
19333        this.next.setDisabled(ap == ps);
19334        this.last.setDisabled(ap == ps);
19335        this.loading.enable();
19336        this.updateInfo();
19337     },
19338
19339     // private
19340     getPageData : function(){
19341         var total = this.ds.getTotalCount();
19342         return {
19343             total : total,
19344             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19345             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19346         };
19347     },
19348
19349     // private
19350     onLoadError : function(){
19351         this.loading.enable();
19352     },
19353
19354     // private
19355     onPagingKeydown : function(e){
19356         var k = e.getKey();
19357         var d = this.getPageData();
19358         if(k == e.RETURN){
19359             var v = this.field.dom.value, pageNum;
19360             if(!v || isNaN(pageNum = parseInt(v, 10))){
19361                 this.field.dom.value = d.activePage;
19362                 return;
19363             }
19364             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19365             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19366             e.stopEvent();
19367         }
19368         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))
19369         {
19370           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19371           this.field.dom.value = pageNum;
19372           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19373           e.stopEvent();
19374         }
19375         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19376         {
19377           var v = this.field.dom.value, pageNum; 
19378           var increment = (e.shiftKey) ? 10 : 1;
19379           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19380             increment *= -1;
19381           if(!v || isNaN(pageNum = parseInt(v, 10))) {
19382             this.field.dom.value = d.activePage;
19383             return;
19384           }
19385           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19386           {
19387             this.field.dom.value = parseInt(v, 10) + increment;
19388             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19389             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19390           }
19391           e.stopEvent();
19392         }
19393     },
19394
19395     // private
19396     beforeLoad : function(){
19397         if(this.loading){
19398             this.loading.disable();
19399         }
19400     },
19401
19402     // private
19403     onClick : function(which){
19404         var ds = this.ds;
19405         if (!ds) {
19406             return;
19407         }
19408         switch(which){
19409             case "first":
19410                 ds.load({params:{start: 0, limit: this.pageSize}});
19411             break;
19412             case "prev":
19413                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19414             break;
19415             case "next":
19416                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19417             break;
19418             case "last":
19419                 var total = ds.getTotalCount();
19420                 var extra = total % this.pageSize;
19421                 var lastStart = extra ? (total - extra) : total-this.pageSize;
19422                 ds.load({params:{start: lastStart, limit: this.pageSize}});
19423             break;
19424             case "refresh":
19425                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19426             break;
19427         }
19428     },
19429
19430     /**
19431      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19432      * @param {Roo.data.Store} store The data store to unbind
19433      */
19434     unbind : function(ds){
19435         ds.un("beforeload", this.beforeLoad, this);
19436         ds.un("load", this.onLoad, this);
19437         ds.un("loadexception", this.onLoadError, this);
19438         ds.un("remove", this.updateInfo, this);
19439         ds.un("add", this.updateInfo, this);
19440         this.ds = undefined;
19441     },
19442
19443     /**
19444      * Binds the paging toolbar to the specified {@link Roo.data.Store}
19445      * @param {Roo.data.Store} store The data store to bind
19446      */
19447     bind : function(ds){
19448         ds.on("beforeload", this.beforeLoad, this);
19449         ds.on("load", this.onLoad, this);
19450         ds.on("loadexception", this.onLoadError, this);
19451         ds.on("remove", this.updateInfo, this);
19452         ds.on("add", this.updateInfo, this);
19453         this.ds = ds;
19454     }
19455 });/*
19456  * - LGPL
19457  *
19458  * element
19459  * 
19460  */
19461
19462 /**
19463  * @class Roo.bootstrap.MessageBar
19464  * @extends Roo.bootstrap.Component
19465  * Bootstrap MessageBar class
19466  * @cfg {String} html contents of the MessageBar
19467  * @cfg {String} weight (info | success | warning | danger) default info
19468  * @cfg {String} beforeClass insert the bar before the given class
19469  * @cfg {Boolean} closable (true | false) default false
19470  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19471  * 
19472  * @constructor
19473  * Create a new Element
19474  * @param {Object} config The config object
19475  */
19476
19477 Roo.bootstrap.MessageBar = function(config){
19478     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19479 };
19480
19481 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
19482     
19483     html: '',
19484     weight: 'info',
19485     closable: false,
19486     fixed: false,
19487     beforeClass: 'bootstrap-sticky-wrap',
19488     
19489     getAutoCreate : function(){
19490         
19491         var cfg = {
19492             tag: 'div',
19493             cls: 'alert alert-dismissable alert-' + this.weight,
19494             cn: [
19495                 {
19496                     tag: 'span',
19497                     cls: 'message',
19498                     html: this.html || ''
19499                 }
19500             ]
19501         }
19502         
19503         if(this.fixed){
19504             cfg.cls += ' alert-messages-fixed';
19505         }
19506         
19507         if(this.closable){
19508             cfg.cn.push({
19509                 tag: 'button',
19510                 cls: 'close',
19511                 html: 'x'
19512             });
19513         }
19514         
19515         return cfg;
19516     },
19517     
19518     onRender : function(ct, position)
19519     {
19520         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19521         
19522         if(!this.el){
19523             var cfg = Roo.apply({},  this.getAutoCreate());
19524             cfg.id = Roo.id();
19525             
19526             if (this.cls) {
19527                 cfg.cls += ' ' + this.cls;
19528             }
19529             if (this.style) {
19530                 cfg.style = this.style;
19531             }
19532             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19533             
19534             this.el.setVisibilityMode(Roo.Element.DISPLAY);
19535         }
19536         
19537         this.el.select('>button.close').on('click', this.hide, this);
19538         
19539     },
19540     
19541     show : function()
19542     {
19543         if (!this.rendered) {
19544             this.render();
19545         }
19546         
19547         this.el.show();
19548         
19549         this.fireEvent('show', this);
19550         
19551     },
19552     
19553     hide : function()
19554     {
19555         if (!this.rendered) {
19556             this.render();
19557         }
19558         
19559         this.el.hide();
19560         
19561         this.fireEvent('hide', this);
19562     },
19563     
19564     update : function()
19565     {
19566 //        var e = this.el.dom.firstChild;
19567 //        
19568 //        if(this.closable){
19569 //            e = e.nextSibling;
19570 //        }
19571 //        
19572 //        e.data = this.html || '';
19573
19574         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19575     }
19576    
19577 });
19578
19579  
19580
19581      /*
19582  * - LGPL
19583  *
19584  * Graph
19585  * 
19586  */
19587
19588
19589 /**
19590  * @class Roo.bootstrap.Graph
19591  * @extends Roo.bootstrap.Component
19592  * Bootstrap Graph class
19593 > Prameters
19594  -sm {number} sm 4
19595  -md {number} md 5
19596  @cfg {String} graphtype  bar | vbar | pie
19597  @cfg {number} g_x coodinator | centre x (pie)
19598  @cfg {number} g_y coodinator | centre y (pie)
19599  @cfg {number} g_r radius (pie)
19600  @cfg {number} g_height height of the chart (respected by all elements in the set)
19601  @cfg {number} g_width width of the chart (respected by all elements in the set)
19602  @cfg {Object} title The title of the chart
19603     
19604  -{Array}  values
19605  -opts (object) options for the chart 
19606      o {
19607      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19608      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19609      o vgutter (number)
19610      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.
19611      o stacked (boolean) whether or not to tread values as in a stacked bar chart
19612      o to
19613      o stretch (boolean)
19614      o }
19615  -opts (object) options for the pie
19616      o{
19617      o cut
19618      o startAngle (number)
19619      o endAngle (number)
19620      } 
19621  *
19622  * @constructor
19623  * Create a new Input
19624  * @param {Object} config The config object
19625  */
19626
19627 Roo.bootstrap.Graph = function(config){
19628     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
19629     
19630     this.addEvents({
19631         // img events
19632         /**
19633          * @event click
19634          * The img click event for the img.
19635          * @param {Roo.EventObject} e
19636          */
19637         "click" : true
19638     });
19639 };
19640
19641 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
19642     
19643     sm: 4,
19644     md: 5,
19645     graphtype: 'bar',
19646     g_height: 250,
19647     g_width: 400,
19648     g_x: 50,
19649     g_y: 50,
19650     g_r: 30,
19651     opts:{
19652         //g_colors: this.colors,
19653         g_type: 'soft',
19654         g_gutter: '20%'
19655
19656     },
19657     title : false,
19658
19659     getAutoCreate : function(){
19660         
19661         var cfg = {
19662             tag: 'div',
19663             html : null
19664         }
19665         
19666         
19667         return  cfg;
19668     },
19669
19670     onRender : function(ct,position){
19671         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
19672         this.raphael = Raphael(this.el.dom);
19673         
19674                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19675                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19676                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
19677                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
19678                 /*
19679                 r.text(160, 10, "Single Series Chart").attr(txtattr);
19680                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
19681                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
19682                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
19683                 
19684                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
19685                 r.barchart(330, 10, 300, 220, data1);
19686                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
19687                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
19688                 */
19689                 
19690                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19691                 // r.barchart(30, 30, 560, 250,  xdata, {
19692                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
19693                 //     axis : "0 0 1 1",
19694                 //     axisxlabels :  xdata
19695                 //     //yvalues : cols,
19696                    
19697                 // });
19698 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
19699 //        
19700 //        this.load(null,xdata,{
19701 //                axis : "0 0 1 1",
19702 //                axisxlabels :  xdata
19703 //                });
19704
19705     },
19706
19707     load : function(graphtype,xdata,opts){
19708         this.raphael.clear();
19709         if(!graphtype) {
19710             graphtype = this.graphtype;
19711         }
19712         if(!opts){
19713             opts = this.opts;
19714         }
19715         var r = this.raphael,
19716             fin = function () {
19717                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
19718             },
19719             fout = function () {
19720                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
19721             },
19722             pfin = function() {
19723                 this.sector.stop();
19724                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
19725
19726                 if (this.label) {
19727                     this.label[0].stop();
19728                     this.label[0].attr({ r: 7.5 });
19729                     this.label[1].attr({ "font-weight": 800 });
19730                 }
19731             },
19732             pfout = function() {
19733                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
19734
19735                 if (this.label) {
19736                     this.label[0].animate({ r: 5 }, 500, "bounce");
19737                     this.label[1].attr({ "font-weight": 400 });
19738                 }
19739             };
19740
19741         switch(graphtype){
19742             case 'bar':
19743                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19744                 break;
19745             case 'hbar':
19746                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
19747                 break;
19748             case 'pie':
19749 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
19750 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
19751 //            
19752                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
19753                 
19754                 break;
19755
19756         }
19757         
19758         if(this.title){
19759             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
19760         }
19761         
19762     },
19763     
19764     setTitle: function(o)
19765     {
19766         this.title = o;
19767     },
19768     
19769     initEvents: function() {
19770         
19771         if(!this.href){
19772             this.el.on('click', this.onClick, this);
19773         }
19774     },
19775     
19776     onClick : function(e)
19777     {
19778         Roo.log('img onclick');
19779         this.fireEvent('click', this, e);
19780     }
19781    
19782 });
19783
19784  
19785 /*
19786  * - LGPL
19787  *
19788  * numberBox
19789  * 
19790  */
19791 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19792
19793 /**
19794  * @class Roo.bootstrap.dash.NumberBox
19795  * @extends Roo.bootstrap.Component
19796  * Bootstrap NumberBox class
19797  * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
19798  * @cfg {String} headline Box headline
19799  * @cfg {String} content Box content
19800  * @cfg {String} icon Box icon
19801  * @cfg {String} footer Footer text
19802  * @cfg {String} fhref Footer href
19803  * 
19804  * @constructor
19805  * Create a new NumberBox
19806  * @param {Object} config The config object
19807  */
19808
19809
19810 Roo.bootstrap.dash.NumberBox = function(config){
19811     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
19812     
19813 };
19814
19815 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
19816     
19817     bgcolor : 'aqua',
19818     headline : '',
19819     content : '',
19820     icon : '',
19821     footer : '',
19822     fhref : '',
19823     ficon : '',
19824     
19825     getAutoCreate : function(){
19826         
19827         var cfg = {
19828             tag : 'div',
19829             cls : 'small-box bg-' + this.bgcolor,
19830             cn : [
19831                 {
19832                     tag : 'div',
19833                     cls : 'inner',
19834                     cn :[
19835                         {
19836                             tag : 'h3',
19837                             cls : 'roo-headline',
19838                             html : this.headline
19839                         },
19840                         {
19841                             tag : 'p',
19842                             cls : 'roo-content',
19843                             html : this.content
19844                         }
19845                     ]
19846                 }
19847             ]
19848         }
19849         
19850         if(this.icon){
19851             cfg.cn.push({
19852                 tag : 'div',
19853                 cls : 'icon',
19854                 cn :[
19855                     {
19856                         tag : 'i',
19857                         cls : 'ion ' + this.icon
19858                     }
19859                 ]
19860             });
19861         }
19862         
19863         if(this.footer){
19864             var footer = {
19865                 tag : 'a',
19866                 cls : 'small-box-footer',
19867                 href : this.fhref || '#',
19868                 html : this.footer
19869             };
19870             
19871             cfg.cn.push(footer);
19872             
19873         }
19874         
19875         return  cfg;
19876     },
19877
19878     onRender : function(ct,position){
19879         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19880
19881
19882        
19883                 
19884     },
19885
19886     setHeadline: function (value)
19887     {
19888         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19889     },
19890     
19891     setFooter: function (value, href)
19892     {
19893         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19894         
19895         if(href){
19896             this.el.select('a.small-box-footer',true).first().attr('href', href);
19897         }
19898         
19899     },
19900
19901     setContent: function (value)
19902     {
19903         this.el.select('.roo-content',true).first().dom.innerHTML = value;
19904     },
19905
19906     initEvents: function() 
19907     {   
19908         
19909     }
19910     
19911 });
19912
19913  
19914 /*
19915  * - LGPL
19916  *
19917  * TabBox
19918  * 
19919  */
19920 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19921
19922 /**
19923  * @class Roo.bootstrap.dash.TabBox
19924  * @extends Roo.bootstrap.Component
19925  * Bootstrap TabBox class
19926  * @cfg {String} title Title of the TabBox
19927  * @cfg {String} icon Icon of the TabBox
19928  * @cfg {Boolean} showtabs (true|false) show the tabs default true
19929  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
19930  * 
19931  * @constructor
19932  * Create a new TabBox
19933  * @param {Object} config The config object
19934  */
19935
19936
19937 Roo.bootstrap.dash.TabBox = function(config){
19938     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19939     this.addEvents({
19940         // raw events
19941         /**
19942          * @event addpane
19943          * When a pane is added
19944          * @param {Roo.bootstrap.dash.TabPane} pane
19945          */
19946         "addpane" : true,
19947         /**
19948          * @event activatepane
19949          * When a pane is activated
19950          * @param {Roo.bootstrap.dash.TabPane} pane
19951          */
19952         "activatepane" : true
19953         
19954          
19955     });
19956     
19957     this.panes = [];
19958 };
19959
19960 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
19961
19962     title : '',
19963     icon : false,
19964     showtabs : true,
19965     tabScrollable : false,
19966     
19967     getChildContainer : function()
19968     {
19969         return this.el.select('.tab-content', true).first();
19970     },
19971     
19972     getAutoCreate : function(){
19973         
19974         var header = {
19975             tag: 'li',
19976             cls: 'pull-left header',
19977             html: this.title,
19978             cn : []
19979         };
19980         
19981         if(this.icon){
19982             header.cn.push({
19983                 tag: 'i',
19984                 cls: 'fa ' + this.icon
19985             });
19986         }
19987         
19988         var h = {
19989             tag: 'ul',
19990             cls: 'nav nav-tabs pull-right',
19991             cn: [
19992                 header
19993             ]
19994         };
19995         
19996         if(this.tabScrollable){
19997             h = {
19998                 tag: 'div',
19999                 cls: 'tab-header',
20000                 cn: [
20001                     {
20002                         tag: 'ul',
20003                         cls: 'nav nav-tabs pull-right',
20004                         cn: [
20005                             header
20006                         ]
20007                     }
20008                 ]
20009             }
20010         }
20011         
20012         var cfg = {
20013             tag: 'div',
20014             cls: 'nav-tabs-custom',
20015             cn: [
20016                 h,
20017                 {
20018                     tag: 'div',
20019                     cls: 'tab-content no-padding',
20020                     cn: []
20021                 }
20022             ]
20023         }
20024
20025         return  cfg;
20026     },
20027     initEvents : function()
20028     {
20029         //Roo.log('add add pane handler');
20030         this.on('addpane', this.onAddPane, this);
20031     },
20032      /**
20033      * Updates the box title
20034      * @param {String} html to set the title to.
20035      */
20036     setTitle : function(value)
20037     {
20038         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20039     },
20040     onAddPane : function(pane)
20041     {
20042         this.panes.push(pane);
20043         //Roo.log('addpane');
20044         //Roo.log(pane);
20045         // tabs are rendere left to right..
20046         if(!this.showtabs){
20047             return;
20048         }
20049         
20050         var ctr = this.el.select('.nav-tabs', true).first();
20051          
20052          
20053         var existing = ctr.select('.nav-tab',true);
20054         var qty = existing.getCount();;
20055         
20056         
20057         var tab = ctr.createChild({
20058             tag : 'li',
20059             cls : 'nav-tab' + (qty ? '' : ' active'),
20060             cn : [
20061                 {
20062                     tag : 'a',
20063                     href:'#',
20064                     html : pane.title
20065                 }
20066             ]
20067         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20068         pane.tab = tab;
20069         
20070         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20071         if (!qty) {
20072             pane.el.addClass('active');
20073         }
20074         
20075                 
20076     },
20077     onTabClick : function(ev,un,ob,pane)
20078     {
20079         //Roo.log('tab - prev default');
20080         ev.preventDefault();
20081         
20082         
20083         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20084         pane.tab.addClass('active');
20085         //Roo.log(pane.title);
20086         this.getChildContainer().select('.tab-pane',true).removeClass('active');
20087         // technically we should have a deactivate event.. but maybe add later.
20088         // and it should not de-activate the selected tab...
20089         this.fireEvent('activatepane', pane);
20090         pane.el.addClass('active');
20091         pane.fireEvent('activate');
20092         
20093         
20094     },
20095     
20096     getActivePane : function()
20097     {
20098         var r = false;
20099         Roo.each(this.panes, function(p) {
20100             if(p.el.hasClass('active')){
20101                 r = p;
20102                 return false;
20103             }
20104             
20105             return;
20106         });
20107         
20108         return r;
20109     }
20110     
20111     
20112 });
20113
20114  
20115 /*
20116  * - LGPL
20117  *
20118  * Tab pane
20119  * 
20120  */
20121 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20122 /**
20123  * @class Roo.bootstrap.TabPane
20124  * @extends Roo.bootstrap.Component
20125  * Bootstrap TabPane class
20126  * @cfg {Boolean} active (false | true) Default false
20127  * @cfg {String} title title of panel
20128
20129  * 
20130  * @constructor
20131  * Create a new TabPane
20132  * @param {Object} config The config object
20133  */
20134
20135 Roo.bootstrap.dash.TabPane = function(config){
20136     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20137     
20138     this.addEvents({
20139         // raw events
20140         /**
20141          * @event activate
20142          * When a pane is activated
20143          * @param {Roo.bootstrap.dash.TabPane} pane
20144          */
20145         "activate" : true
20146          
20147     });
20148 };
20149
20150 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
20151     
20152     active : false,
20153     title : '',
20154     
20155     // the tabBox that this is attached to.
20156     tab : false,
20157      
20158     getAutoCreate : function() 
20159     {
20160         var cfg = {
20161             tag: 'div',
20162             cls: 'tab-pane'
20163         }
20164         
20165         if(this.active){
20166             cfg.cls += ' active';
20167         }
20168         
20169         return cfg;
20170     },
20171     initEvents  : function()
20172     {
20173         //Roo.log('trigger add pane handler');
20174         this.parent().fireEvent('addpane', this)
20175     },
20176     
20177      /**
20178      * Updates the tab title 
20179      * @param {String} html to set the title to.
20180      */
20181     setTitle: function(str)
20182     {
20183         if (!this.tab) {
20184             return;
20185         }
20186         this.title = str;
20187         this.tab.select('a', true).first().dom.innerHTML = str;
20188         
20189     }
20190     
20191     
20192     
20193 });
20194
20195  
20196
20197
20198  /*
20199  * - LGPL
20200  *
20201  * menu
20202  * 
20203  */
20204 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20205
20206 /**
20207  * @class Roo.bootstrap.menu.Menu
20208  * @extends Roo.bootstrap.Component
20209  * Bootstrap Menu class - container for Menu
20210  * @cfg {String} html Text of the menu
20211  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20212  * @cfg {String} icon Font awesome icon
20213  * @cfg {String} pos Menu align to (top | bottom) default bottom
20214  * 
20215  * 
20216  * @constructor
20217  * Create a new Menu
20218  * @param {Object} config The config object
20219  */
20220
20221
20222 Roo.bootstrap.menu.Menu = function(config){
20223     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20224     
20225     this.addEvents({
20226         /**
20227          * @event beforeshow
20228          * Fires before this menu is displayed
20229          * @param {Roo.bootstrap.menu.Menu} this
20230          */
20231         beforeshow : true,
20232         /**
20233          * @event beforehide
20234          * Fires before this menu is hidden
20235          * @param {Roo.bootstrap.menu.Menu} this
20236          */
20237         beforehide : true,
20238         /**
20239          * @event show
20240          * Fires after this menu is displayed
20241          * @param {Roo.bootstrap.menu.Menu} this
20242          */
20243         show : true,
20244         /**
20245          * @event hide
20246          * Fires after this menu is hidden
20247          * @param {Roo.bootstrap.menu.Menu} this
20248          */
20249         hide : true,
20250         /**
20251          * @event click
20252          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20253          * @param {Roo.bootstrap.menu.Menu} this
20254          * @param {Roo.EventObject} e
20255          */
20256         click : true
20257     });
20258     
20259 };
20260
20261 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
20262     
20263     submenu : false,
20264     html : '',
20265     weight : 'default',
20266     icon : false,
20267     pos : 'bottom',
20268     
20269     
20270     getChildContainer : function() {
20271         if(this.isSubMenu){
20272             return this.el;
20273         }
20274         
20275         return this.el.select('ul.dropdown-menu', true).first();  
20276     },
20277     
20278     getAutoCreate : function()
20279     {
20280         var text = [
20281             {
20282                 tag : 'span',
20283                 cls : 'roo-menu-text',
20284                 html : this.html
20285             }
20286         ];
20287         
20288         if(this.icon){
20289             text.unshift({
20290                 tag : 'i',
20291                 cls : 'fa ' + this.icon
20292             })
20293         }
20294         
20295         
20296         var cfg = {
20297             tag : 'div',
20298             cls : 'btn-group',
20299             cn : [
20300                 {
20301                     tag : 'button',
20302                     cls : 'dropdown-button btn btn-' + this.weight,
20303                     cn : text
20304                 },
20305                 {
20306                     tag : 'button',
20307                     cls : 'dropdown-toggle btn btn-' + this.weight,
20308                     cn : [
20309                         {
20310                             tag : 'span',
20311                             cls : 'caret'
20312                         }
20313                     ]
20314                 },
20315                 {
20316                     tag : 'ul',
20317                     cls : 'dropdown-menu'
20318                 }
20319             ]
20320             
20321         };
20322         
20323         if(this.pos == 'top'){
20324             cfg.cls += ' dropup';
20325         }
20326         
20327         if(this.isSubMenu){
20328             cfg = {
20329                 tag : 'ul',
20330                 cls : 'dropdown-menu'
20331             }
20332         }
20333         
20334         return cfg;
20335     },
20336     
20337     onRender : function(ct, position)
20338     {
20339         this.isSubMenu = ct.hasClass('dropdown-submenu');
20340         
20341         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20342     },
20343     
20344     initEvents : function() 
20345     {
20346         if(this.isSubMenu){
20347             return;
20348         }
20349         
20350         this.hidden = true;
20351         
20352         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20353         this.triggerEl.on('click', this.onTriggerPress, this);
20354         
20355         this.buttonEl = this.el.select('button.dropdown-button', true).first();
20356         this.buttonEl.on('click', this.onClick, this);
20357         
20358     },
20359     
20360     list : function()
20361     {
20362         if(this.isSubMenu){
20363             return this.el;
20364         }
20365         
20366         return this.el.select('ul.dropdown-menu', true).first();
20367     },
20368     
20369     onClick : function(e)
20370     {
20371         this.fireEvent("click", this, e);
20372     },
20373     
20374     onTriggerPress  : function(e)
20375     {   
20376         if (this.isVisible()) {
20377             this.hide();
20378         } else {
20379             this.show();
20380         }
20381     },
20382     
20383     isVisible : function(){
20384         return !this.hidden;
20385     },
20386     
20387     show : function()
20388     {
20389         this.fireEvent("beforeshow", this);
20390         
20391         this.hidden = false;
20392         this.el.addClass('open');
20393         
20394         Roo.get(document).on("mouseup", this.onMouseUp, this);
20395         
20396         this.fireEvent("show", this);
20397         
20398         
20399     },
20400     
20401     hide : function()
20402     {
20403         this.fireEvent("beforehide", this);
20404         
20405         this.hidden = true;
20406         this.el.removeClass('open');
20407         
20408         Roo.get(document).un("mouseup", this.onMouseUp);
20409         
20410         this.fireEvent("hide", this);
20411     },
20412     
20413     onMouseUp : function()
20414     {
20415         this.hide();
20416     }
20417     
20418 });
20419
20420  
20421  /*
20422  * - LGPL
20423  *
20424  * menu item
20425  * 
20426  */
20427 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20428
20429 /**
20430  * @class Roo.bootstrap.menu.Item
20431  * @extends Roo.bootstrap.Component
20432  * Bootstrap MenuItem class
20433  * @cfg {Boolean} submenu (true | false) default false
20434  * @cfg {String} html text of the item
20435  * @cfg {String} href the link
20436  * @cfg {Boolean} disable (true | false) default false
20437  * @cfg {Boolean} preventDefault (true | false) default true
20438  * @cfg {String} icon Font awesome icon
20439  * @cfg {String} pos Submenu align to (left | right) default right 
20440  * 
20441  * 
20442  * @constructor
20443  * Create a new Item
20444  * @param {Object} config The config object
20445  */
20446
20447
20448 Roo.bootstrap.menu.Item = function(config){
20449     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20450     this.addEvents({
20451         /**
20452          * @event mouseover
20453          * Fires when the mouse is hovering over this menu
20454          * @param {Roo.bootstrap.menu.Item} this
20455          * @param {Roo.EventObject} e
20456          */
20457         mouseover : true,
20458         /**
20459          * @event mouseout
20460          * Fires when the mouse exits this menu
20461          * @param {Roo.bootstrap.menu.Item} this
20462          * @param {Roo.EventObject} e
20463          */
20464         mouseout : true,
20465         // raw events
20466         /**
20467          * @event click
20468          * The raw click event for the entire grid.
20469          * @param {Roo.EventObject} e
20470          */
20471         click : true
20472     });
20473 };
20474
20475 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
20476     
20477     submenu : false,
20478     href : '',
20479     html : '',
20480     preventDefault: true,
20481     disable : false,
20482     icon : false,
20483     pos : 'right',
20484     
20485     getAutoCreate : function()
20486     {
20487         var text = [
20488             {
20489                 tag : 'span',
20490                 cls : 'roo-menu-item-text',
20491                 html : this.html
20492             }
20493         ];
20494         
20495         if(this.icon){
20496             text.unshift({
20497                 tag : 'i',
20498                 cls : 'fa ' + this.icon
20499             })
20500         }
20501         
20502         var cfg = {
20503             tag : 'li',
20504             cn : [
20505                 {
20506                     tag : 'a',
20507                     href : this.href || '#',
20508                     cn : text
20509                 }
20510             ]
20511         };
20512         
20513         if(this.disable){
20514             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20515         }
20516         
20517         if(this.submenu){
20518             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20519             
20520             if(this.pos == 'left'){
20521                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20522             }
20523         }
20524         
20525         return cfg;
20526     },
20527     
20528     initEvents : function() 
20529     {
20530         this.el.on('mouseover', this.onMouseOver, this);
20531         this.el.on('mouseout', this.onMouseOut, this);
20532         
20533         this.el.select('a', true).first().on('click', this.onClick, this);
20534         
20535     },
20536     
20537     onClick : function(e)
20538     {
20539         if(this.preventDefault){
20540             e.preventDefault();
20541         }
20542         
20543         this.fireEvent("click", this, e);
20544     },
20545     
20546     onMouseOver : function(e)
20547     {
20548         if(this.submenu && this.pos == 'left'){
20549             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20550         }
20551         
20552         this.fireEvent("mouseover", this, e);
20553     },
20554     
20555     onMouseOut : function(e)
20556     {
20557         this.fireEvent("mouseout", this, e);
20558     }
20559 });
20560
20561  
20562
20563  /*
20564  * - LGPL
20565  *
20566  * menu separator
20567  * 
20568  */
20569 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20570
20571 /**
20572  * @class Roo.bootstrap.menu.Separator
20573  * @extends Roo.bootstrap.Component
20574  * Bootstrap Separator class
20575  * 
20576  * @constructor
20577  * Create a new Separator
20578  * @param {Object} config The config object
20579  */
20580
20581
20582 Roo.bootstrap.menu.Separator = function(config){
20583     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20584 };
20585
20586 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
20587     
20588     getAutoCreate : function(){
20589         var cfg = {
20590             tag : 'li',
20591             cls: 'divider'
20592         };
20593         
20594         return cfg;
20595     }
20596    
20597 });
20598
20599  
20600
20601  /*
20602  * - LGPL
20603  *
20604  * Tooltip
20605  * 
20606  */
20607
20608 /**
20609  * @class Roo.bootstrap.Tooltip
20610  * Bootstrap Tooltip class
20611  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20612  * to determine which dom element triggers the tooltip.
20613  * 
20614  * It needs to add support for additional attributes like tooltip-position
20615  * 
20616  * @constructor
20617  * Create a new Toolti
20618  * @param {Object} config The config object
20619  */
20620
20621 Roo.bootstrap.Tooltip = function(config){
20622     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20623 };
20624
20625 Roo.apply(Roo.bootstrap.Tooltip, {
20626     /**
20627      * @function init initialize tooltip monitoring.
20628      * @static
20629      */
20630     currentEl : false,
20631     currentTip : false,
20632     currentRegion : false,
20633     
20634     //  init : delay?
20635     
20636     init : function()
20637     {
20638         Roo.get(document).on('mouseover', this.enter ,this);
20639         Roo.get(document).on('mouseout', this.leave, this);
20640          
20641         
20642         this.currentTip = new Roo.bootstrap.Tooltip();
20643     },
20644     
20645     enter : function(ev)
20646     {
20647         var dom = ev.getTarget();
20648         //Roo.log(['enter',dom]);
20649         var el = Roo.fly(dom);
20650         if (this.currentEl) {
20651             //Roo.log(dom);
20652             //Roo.log(this.currentEl);
20653             //Roo.log(this.currentEl.contains(dom));
20654             if (this.currentEl == el) {
20655                 return;
20656             }
20657             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
20658                 return;
20659             }
20660
20661         }
20662         
20663         
20664         
20665         if (this.currentTip) {
20666             this.currentTip.hide();
20667         }    
20668         //Roo.log(el);
20669         if (!el.attr('tooltip')) { // parents who have tip?
20670             return;
20671         }
20672         this.currentEl = el;
20673         this.currentTip.bind(el);
20674         this.currentRegion = Roo.lib.Region.getRegion(dom);
20675         this.currentTip.enter();
20676         
20677     },
20678     leave : function(ev)
20679     {
20680         var dom = ev.getTarget();
20681         //Roo.log(['leave',dom]);
20682         if (!this.currentEl) {
20683             return;
20684         }
20685         
20686         
20687         if (dom != this.currentEl.dom) {
20688             return;
20689         }
20690         var xy = ev.getXY();
20691         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
20692             return;
20693         }
20694         // only activate leave if mouse cursor is outside... bounding box..
20695         
20696         
20697         
20698         
20699         if (this.currentTip) {
20700             this.currentTip.leave();
20701         }
20702         //Roo.log('clear currentEl');
20703         this.currentEl = false;
20704         
20705         
20706     },
20707     alignment : {
20708         'left' : ['r-l', [-2,0], 'right'],
20709         'right' : ['l-r', [2,0], 'left'],
20710         'bottom' : ['t-b', [0,2], 'top'],
20711         'top' : [ 'b-t', [0,-2], 'bottom']
20712     }
20713     
20714 });
20715
20716
20717 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
20718     
20719     
20720     bindEl : false,
20721     
20722     delay : null, // can be { show : 300 , hide: 500}
20723     
20724     timeout : null,
20725     
20726     hoverState : null, //???
20727     
20728     placement : 'bottom', 
20729     
20730     getAutoCreate : function(){
20731     
20732         var cfg = {
20733            cls : 'tooltip',
20734            role : 'tooltip',
20735            cn : [
20736                 {
20737                     cls : 'tooltip-arrow'
20738                 },
20739                 {
20740                     cls : 'tooltip-inner',
20741                 }
20742            ]
20743         };
20744         
20745         return cfg;
20746     },
20747     bind : function(el)
20748     {
20749         this.bindEl = el;
20750     },
20751       
20752     
20753     enter : function () {
20754        
20755         if (this.timeout != null) {
20756             clearTimeout(this.timeout);
20757         }
20758         
20759         this.hoverState = 'in'
20760          //Roo.log("enter - show");
20761         if (!this.delay || !this.delay.show) {
20762             this.show();
20763             return 
20764         }
20765         var _t = this;
20766         this.timeout = setTimeout(function () {
20767             if (_t.hoverState == 'in') {
20768                 _t.show();
20769             }
20770         }, this.delay.show)
20771     },
20772     leave : function()
20773     {
20774         clearTimeout(this.timeout);
20775     
20776         this.hoverState = 'out'
20777          if (!this.delay || !this.delay.hide) {
20778             this.hide();
20779             return 
20780         }
20781        
20782         var _t = this;
20783         this.timeout = setTimeout(function () {
20784             //Roo.log("leave - timeout");
20785             
20786             if (_t.hoverState == 'out') {
20787                 _t.hide();
20788                 Roo.bootstrap.Tooltip.currentEl = false;
20789             }
20790         }, delay)
20791     },
20792     
20793     show : function ()
20794     {
20795         if (!this.el) {
20796             this.render(document.body);
20797         }
20798         // set content.
20799         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
20800         this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
20801         
20802         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
20803         
20804         var placement = typeof this.placement == 'function' ?
20805             this.placement.call(this, this.el, on_el) :
20806             this.placement;
20807             
20808         var autoToken = /\s?auto?\s?/i;
20809         var autoPlace = autoToken.test(placement);
20810         if (autoPlace) {
20811             placement = placement.replace(autoToken, '') || 'top';
20812         }
20813         
20814         //this.el.detach()
20815         //this.el.setXY([0,0]);
20816         this.el.show();
20817         //this.el.dom.style.display='block';
20818         this.el.addClass(placement);
20819         
20820         //this.el.appendTo(on_el);
20821         
20822         var p = this.getPosition();
20823         var box = this.el.getBox();
20824         
20825         if (autoPlace) {
20826             // fixme..
20827         }
20828         var align = Roo.bootstrap.Tooltip.alignment[placement]
20829         this.el.alignTo(this.bindEl, align[0],align[1]);
20830         //var arrow = this.el.select('.arrow',true).first();
20831         //arrow.set(align[2], 
20832         
20833         this.el.addClass('in fade');
20834         this.hoverState = null;
20835         
20836         if (this.el.hasClass('fade')) {
20837             // fade it?
20838         }
20839         
20840     },
20841     hide : function()
20842     {
20843          
20844         if (!this.el) {
20845             return;
20846         }
20847         //this.el.setXY([0,0]);
20848         this.el.removeClass('in');
20849         //this.el.hide();
20850         
20851     }
20852     
20853 });
20854  
20855
20856