sync
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31        
32     this.addEvents({
33         /**
34          * @event childrenrendered
35          * Fires when the children have been rendered..
36          * @param {Roo.bootstrap.Component} this
37          */
38         "childrenrendered" : true
39         
40         
41         
42     });
43     
44     
45 };
46
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
48     
49     
50     allowDomMove : false, // to stop relocations in parent onRender...
51     
52     cls : false,
53     
54     style : false,
55     
56     autoCreate : false,
57     
58     tooltip : null,
59     /**
60      * Initialize Events for the element
61      */
62     initEvents : function() { },
63     
64     xattr : false,
65     
66     parentId : false,
67     
68     can_build_overlaid : true,
69     
70     container_method : false,
71     
72     dataId : false,
73     
74     name : false,
75     
76     parent: function() {
77         // returns the parent component..
78         return Roo.ComponentMgr.get(this.parentId)
79         
80         
81     },
82     
83     // private
84     onRender : function(ct, position)
85     {
86        // Roo.log("Call onRender: " + this.xtype);
87         
88         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
89         
90         if(this.el){
91             if (this.el.attr('xtype')) {
92                 this.el.attr('xtypex', this.el.attr('xtype'));
93                 this.el.dom.removeAttribute('xtype');
94                 
95                 this.initEvents();
96             }
97             
98             return;
99         }
100         
101          
102         
103         var cfg = Roo.apply({},  this.getAutoCreate());
104         cfg.id = Roo.id();
105         
106         // fill in the extra attributes 
107         if (this.xattr && typeof(this.xattr) =='object') {
108             for (var i in this.xattr) {
109                 cfg[i] = this.xattr[i];
110             }
111         }
112         
113         if(this.dataId){
114             cfg.dataId = this.dataId;
115         }
116         
117         if (this.cls) {
118             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
119         }
120         
121         if (this.style) { // fixme needs to support more complex style data.
122             cfg.style = this.style;
123         }
124         
125         if(this.name){
126             cfg.name = this.name;
127         }
128         
129        
130         
131         this.el = ct.createChild(cfg, position);
132         
133         if (this.tooltip) {
134             this.tooltipEl().attr('tooltip', this.tooltip);
135         }
136         
137         if(this.tabIndex !== undefined){
138             this.el.dom.setAttribute('tabIndex', this.tabIndex);
139         }
140         this.initEvents();
141         
142         
143     },
144     /**
145      * Fetch the element to add children to
146      * @return {Roo.Element} defaults to this.el
147      */
148     getChildContainer : function()
149     {
150         return this.el;
151     },
152     /**
153      * Fetch the element to display the tooltip on.
154      * @return {Roo.Element} defaults to this.el
155      */
156     tooltipEl : function()
157     {
158         return this.el;
159     },
160         
161     addxtype  : function(tree,cntr)
162     {
163         var cn = this;
164         
165         cn = Roo.factory(tree);
166            
167         cn.parentType = this.xtype; //??
168         cn.parentId = this.id;
169         
170         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171         if (typeof(cn.container_method) == 'string') {
172             cntr = cn.container_method;
173         }
174         
175         
176         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
177         
178         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
179         
180         var build_from_html =  Roo.XComponent.build_from_html;
181           
182         var is_body  = (tree.xtype == 'Body') ;
183           
184         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
185           
186         var self_cntr_el = Roo.get(this[cntr](false));
187         
188         // do not try and build conditional elements 
189         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
190             return false;
191         }
192         
193         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195                 return this.addxtypeChild(tree,cntr);
196             }
197             
198             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199                 
200             if(echild){
201                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202             }
203             
204             Roo.log('skipping render');
205             return cn;
206             
207         }
208         
209         var ret = false;
210         
211         while (true) {
212             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213             
214             if (!echild) {
215                 break;
216             }
217             
218             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
219                 break;
220             }
221             
222             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
223         }
224         return ret;
225     },
226     
227     addxtypeChild : function (tree, cntr)
228     {
229         Roo.debug && Roo.log('addxtypeChild:' + cntr);
230         var cn = this;
231         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
232         
233         
234         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
235                     (typeof(tree['flexy:foreach']) != 'undefined');
236           
237         
238         
239          skip_children = false;
240         // render the element if it's not BODY.
241         if (tree.xtype != 'Body') {
242            
243             cn = Roo.factory(tree);
244            
245             cn.parentType = this.xtype; //??
246             cn.parentId = this.id;
247             
248             var build_from_html =  Roo.XComponent.build_from_html;
249             
250             
251             // does the container contain child eleemnts with 'xtype' attributes.
252             // that match this xtype..
253             // note - when we render we create these as well..
254             // so we should check to see if body has xtype set.
255             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
256                
257                 var self_cntr_el = Roo.get(this[cntr](false));
258                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
259                 
260                 
261                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
262                 // and are not displayed -this causes this to use up the wrong element when matching.
263                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
264                 
265                 
266                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
267                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
268                   
269                   
270                   
271                     cn.el = echild;
272                   //  Roo.log("GOT");
273                     //echild.dom.removeAttribute('xtype');
274                 } else {
275                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
276                     Roo.debug && Roo.log(self_cntr_el);
277                     Roo.debug && Roo.log(echild);
278                     Roo.debug && Roo.log(cn);
279                 }
280             }
281            
282             
283            
284             // if object has flexy:if - then it may or may not be rendered.
285             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
286                 // skip a flexy if element.
287                 Roo.debug && Roo.log('skipping render');
288                 Roo.debug && Roo.log(tree);
289                 if (!cn.el) {
290                     Roo.debug && Roo.log('skipping all children');
291                     skip_children = true;
292                 }
293                 
294              } else {
295                  
296                 // actually if flexy:foreach is found, we really want to create 
297                 // multiple copies here...
298                 //Roo.log('render');
299                 //Roo.log(this[cntr]());
300                 cn.render(this[cntr](true));
301              }
302             // then add the element..
303         }
304         
305         
306         // handle the kids..
307         
308         var nitems = [];
309         /*
310         if (typeof (tree.menu) != 'undefined') {
311             tree.menu.parentType = cn.xtype;
312             tree.menu.triggerEl = cn.el;
313             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
314             
315         }
316         */
317         if (!tree.items || !tree.items.length) {
318             cn.items = nitems;
319             return cn;
320         }
321         var items = tree.items;
322         delete tree.items;
323         
324         //Roo.log(items.length);
325             // add the items..
326         if (!skip_children) {    
327             for(var i =0;i < items.length;i++) {
328                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
329             }
330         }
331         
332         cn.items = nitems;
333         
334         this.fireEvent('childrenrendered', this);
335         
336         return cn;
337     } 
338     
339     
340 });
341
342  /*
343  * - LGPL
344  *
345  * Body
346  * 
347  */
348
349 /**
350  * @class Roo.bootstrap.Body
351  * @extends Roo.bootstrap.Component
352  * Bootstrap Body class
353  * 
354  * @constructor
355  * Create a new body
356  * @param {Object} config The config object
357  */
358
359 Roo.bootstrap.Body = function(config){
360     Roo.bootstrap.Body.superclass.constructor.call(this, config);
361     this.el = Roo.get(document.body);
362     if (this.cls && this.cls.length) {
363         Roo.get(document.body).addClass(this.cls);
364     }
365 };
366
367 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
368       
369         autoCreate : {
370         cls: 'container'
371     },
372     onRender : function(ct, position)
373     {
374        /* Roo.log("Roo.bootstrap.Body - onRender");
375         if (this.cls && this.cls.length) {
376             Roo.get(document.body).addClass(this.cls);
377         }
378         // style??? xttr???
379         */
380     }
381     
382     
383  
384    
385 });
386
387  /*
388  * - LGPL
389  *
390  * button group
391  * 
392  */
393
394
395 /**
396  * @class Roo.bootstrap.ButtonGroup
397  * @extends Roo.bootstrap.Component
398  * Bootstrap ButtonGroup class
399  * @cfg {String} size lg | sm | xs (default empty normal)
400  * @cfg {String} align vertical | justified  (default none)
401  * @cfg {String} direction up | down (default down)
402  * @cfg {Boolean} toolbar false | true
403  * @cfg {Boolean} btn true | false
404  * 
405  * 
406  * @constructor
407  * Create a new Input
408  * @param {Object} config The config object
409  */
410
411 Roo.bootstrap.ButtonGroup = function(config){
412     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
413 };
414
415 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
416     
417     size: '',
418     align: '',
419     direction: '',
420     toolbar: false,
421     btn: true,
422
423     getAutoCreate : function(){
424         var cfg = {
425             cls: 'btn-group',
426             html : null
427         }
428         
429         cfg.html = this.html || cfg.html;
430         
431         if (this.toolbar) {
432             cfg = {
433                 cls: 'btn-toolbar',
434                 html: null
435             }
436             
437             return cfg;
438         }
439         
440         if (['vertical','justified'].indexOf(this.align)!==-1) {
441             cfg.cls = 'btn-group-' + this.align;
442             
443             if (this.align == 'justified') {
444                 console.log(this.items);
445             }
446         }
447         
448         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
449             cfg.cls += ' btn-group-' + this.size;
450         }
451         
452         if (this.direction == 'up') {
453             cfg.cls += ' dropup' ;
454         }
455         
456         return cfg;
457     }
458    
459 });
460
461  /*
462  * - LGPL
463  *
464  * button
465  * 
466  */
467
468 /**
469  * @class Roo.bootstrap.Button
470  * @extends Roo.bootstrap.Component
471  * Bootstrap Button class
472  * @cfg {String} html The button content
473  * @cfg {String} weight (  primary | success | info | warning | danger | link ) default 
474  * @cfg {String} size ( lg | sm | xs)
475  * @cfg {String} tag ( a | input | submit)
476  * @cfg {String} href empty or href
477  * @cfg {Boolean} disabled default false;
478  * @cfg {Boolean} isClose default false;
479  * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
480  * @cfg {String} badge text for badge
481  * @cfg {String} theme default 
482  * @cfg {Boolean} inverse 
483  * @cfg {Boolean} toggle 
484  * @cfg {String} ontext text for on toggle state
485  * @cfg {String} offtext text for off toggle state
486  * @cfg {Boolean} defaulton 
487  * @cfg {Boolean} preventDefault  default true
488  * @cfg {Boolean} removeClass remove the standard class..
489  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
490  * 
491  * @constructor
492  * Create a new button
493  * @param {Object} config The config object
494  */
495
496
497 Roo.bootstrap.Button = function(config){
498     Roo.bootstrap.Button.superclass.constructor.call(this, config);
499     this.addEvents({
500         // raw events
501         /**
502          * @event click
503          * When a butotn is pressed
504          * @param {Roo.EventObject} e
505          */
506         "click" : true,
507          /**
508          * @event toggle
509          * After the button has been toggles
510          * @param {Roo.EventObject} e
511          * @param {boolean} pressed (also available as button.pressed)
512          */
513         "toggle" : true
514     });
515 };
516
517 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
518     html: false,
519     active: false,
520     weight: '',
521     size: '',
522     tag: 'button',
523     href: '',
524     disabled: false,
525     isClose: false,
526     glyphicon: '',
527     badge: '',
528     theme: 'default',
529     inverse: false,
530     
531     toggle: false,
532     ontext: 'ON',
533     offtext: 'OFF',
534     defaulton: true,
535     preventDefault: true,
536     removeClass: false,
537     name: false,
538     target: false,
539     
540     
541     pressed : null,
542      
543     
544     getAutoCreate : function(){
545         
546         var cfg = {
547             tag : 'button',
548             cls : 'roo-button',
549             html: ''
550         };
551         
552         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
553             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
554             this.tag = 'button';
555         } else {
556             cfg.tag = this.tag;
557         }
558         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
559         
560         if (this.toggle == true) {
561             cfg={
562                 tag: 'div',
563                 cls: 'slider-frame roo-button',
564                 cn: [
565                     {
566                         tag: 'span',
567                         'data-on-text':'ON',
568                         'data-off-text':'OFF',
569                         cls: 'slider-button',
570                         html: this.offtext
571                     }
572                 ]
573             };
574             
575             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
576                 cfg.cls += ' '+this.weight;
577             }
578             
579             return cfg;
580         }
581         
582         if (this.isClose) {
583             cfg.cls += ' close';
584             
585             cfg["aria-hidden"] = true;
586             
587             cfg.html = "&times;";
588             
589             return cfg;
590         }
591         
592          
593         if (this.theme==='default') {
594             cfg.cls = 'btn roo-button';
595             
596             //if (this.parentType != 'Navbar') {
597             this.weight = this.weight.length ?  this.weight : 'default';
598             //}
599             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
600                 
601                 cfg.cls += ' btn-' + this.weight;
602             }
603         } else if (this.theme==='glow') {
604             
605             cfg.tag = 'a';
606             cfg.cls = 'btn-glow roo-button';
607             
608             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
609                 
610                 cfg.cls += ' ' + this.weight;
611             }
612         }
613    
614         
615         if (this.inverse) {
616             this.cls += ' inverse';
617         }
618         
619         
620         if (this.active) {
621             cfg.cls += ' active';
622         }
623         
624         if (this.disabled) {
625             cfg.disabled = 'disabled';
626         }
627         
628         if (this.items) {
629             Roo.log('changing to ul' );
630             cfg.tag = 'ul';
631             this.glyphicon = 'caret';
632         }
633         
634         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
635          
636         //gsRoo.log(this.parentType);
637         if (this.parentType === 'Navbar' && !this.parent().bar) {
638             Roo.log('changing to li?');
639             
640             cfg.tag = 'li';
641             
642             cfg.cls = '';
643             cfg.cn =  [{
644                 tag : 'a',
645                 cls : 'roo-button',
646                 html : this.html,
647                 href : this.href || '#'
648             }];
649             if (this.menu) {
650                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
651                 cfg.cls += ' dropdown';
652             }   
653             
654             delete cfg.html;
655             
656         }
657         
658        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
659         
660         if (this.glyphicon) {
661             cfg.html = ' ' + cfg.html;
662             
663             cfg.cn = [
664                 {
665                     tag: 'span',
666                     cls: 'glyphicon glyphicon-' + this.glyphicon
667                 }
668             ];
669         }
670         
671         if (this.badge) {
672             cfg.html += ' ';
673             
674             cfg.tag = 'a';
675             
676 //            cfg.cls='btn roo-button';
677             
678             cfg.href=this.href;
679             
680             var value = cfg.html;
681             
682             if(this.glyphicon){
683                 value = {
684                             tag: 'span',
685                             cls: 'glyphicon glyphicon-' + this.glyphicon,
686                             html: this.html
687                         };
688                 
689             }
690             
691             cfg.cn = [
692                 value,
693                 {
694                     tag: 'span',
695                     cls: 'badge',
696                     html: this.badge
697                 }
698             ];
699             
700             cfg.html='';
701         }
702         
703         if (this.menu) {
704             cfg.cls += ' dropdown';
705             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
706         }
707         
708         if (cfg.tag !== 'a' && this.href !== '') {
709             throw "Tag must be a to set href.";
710         } else if (this.href.length > 0) {
711             cfg.href = this.href;
712         }
713         
714         if(this.removeClass){
715             cfg.cls = '';
716         }
717         
718         if(this.target){
719             cfg.target = this.target;
720         }
721         
722         return cfg;
723     },
724     initEvents: function() {
725        // Roo.log('init events?');
726 //        Roo.log(this.el.dom);
727         // add the menu...
728         
729         if (typeof (this.menu) != 'undefined') {
730             this.menu.parentType = this.xtype;
731             this.menu.triggerEl = this.el;
732             this.addxtype(Roo.apply({}, this.menu));
733         }
734
735
736        if (this.el.hasClass('roo-button')) {
737             this.el.on('click', this.onClick, this);
738        } else {
739             this.el.select('.roo-button').on('click', this.onClick, this);
740        }
741        
742        if(this.removeClass){
743            this.el.on('click', this.onClick, this);
744        }
745        
746        this.el.enableDisplayMode();
747         
748     },
749     onClick : function(e)
750     {
751         if (this.disabled) {
752             return;
753         }
754         
755         
756         Roo.log('button on click ');
757         if(this.preventDefault){
758             e.preventDefault();
759         }
760         if (this.pressed === true || this.pressed === false) {
761             this.pressed = !this.pressed;
762             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
763             this.fireEvent('toggle', this, e, this.pressed);
764         }
765         
766         
767         this.fireEvent('click', this, e);
768     },
769     
770     /**
771      * Enables this button
772      */
773     enable : function()
774     {
775         this.disabled = false;
776         this.el.removeClass('disabled');
777     },
778     
779     /**
780      * Disable this button
781      */
782     disable : function()
783     {
784         this.disabled = true;
785         this.el.addClass('disabled');
786     },
787      /**
788      * sets the active state on/off, 
789      * @param {Boolean} state (optional) Force a particular state
790      */
791     setActive : function(v) {
792         
793         this.el[v ? 'addClass' : 'removeClass']('active');
794     },
795      /**
796      * toggles the current active state 
797      */
798     toggleActive : function()
799     {
800        var active = this.el.hasClass('active');
801        this.setActive(!active);
802        
803         
804     },
805     setText : function(str)
806     {
807         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
808     },
809     getText : function()
810     {
811         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
812     },
813     hide: function() {
814        
815      
816         this.el.hide();   
817     },
818     show: function() {
819        
820         this.el.show();   
821     }
822     
823     
824 });
825
826  /*
827  * - LGPL
828  *
829  * column
830  * 
831  */
832
833 /**
834  * @class Roo.bootstrap.Column
835  * @extends Roo.bootstrap.Component
836  * Bootstrap Column class
837  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
838  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
839  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
840  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
841  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
842  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
843  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
844  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
845  *
846  * 
847  * @cfg {Boolean} hidden (true|false) hide the element
848  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
849  * @cfg {String} fa (ban|check|...) font awesome icon
850  * @cfg {Number} fasize (1|2|....) font awsome size
851
852  * @cfg {String} icon (info-sign|check|...) glyphicon name
853
854  * @cfg {String} html content of column.
855  * 
856  * @constructor
857  * Create a new Column
858  * @param {Object} config The config object
859  */
860
861 Roo.bootstrap.Column = function(config){
862     Roo.bootstrap.Column.superclass.constructor.call(this, config);
863 };
864
865 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
866     
867     xs: false,
868     sm: false,
869     md: false,
870     lg: false,
871     xsoff: false,
872     smoff: false,
873     mdoff: false,
874     lgoff: false,
875     html: '',
876     offset: 0,
877     alert: false,
878     fa: false,
879     icon : false,
880     hidden : false,
881     fasize : 1,
882     
883     getAutoCreate : function(){
884         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
885         
886         cfg = {
887             tag: 'div',
888             cls: 'column'
889         };
890         
891         var settings=this;
892         ['xs','sm','md','lg'].map(function(size){
893             //Roo.log( size + ':' + settings[size]);
894             
895             if (settings[size+'off'] !== false) {
896                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
897             }
898             
899             if (settings[size] === false) {
900                 return;
901             }
902             Roo.log(settings[size]);
903             if (!settings[size]) { // 0 = hidden
904                 cfg.cls += ' hidden-' + size;
905                 return;
906             }
907             cfg.cls += ' col-' + size + '-' + settings[size];
908             
909         });
910         
911         if (this.hidden) {
912             cfg.cls += ' hidden';
913         }
914         
915         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
916             cfg.cls +=' alert alert-' + this.alert;
917         }
918         
919         
920         if (this.html.length) {
921             cfg.html = this.html;
922         }
923         if (this.fa) {
924             var fasize = '';
925             if (this.fasize > 1) {
926                 fasize = ' fa-' + this.fasize + 'x';
927             }
928             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
929             
930             
931         }
932         if (this.icon) {
933             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
934         }
935         
936         return cfg;
937     }
938    
939 });
940
941  
942
943  /*
944  * - LGPL
945  *
946  * page container.
947  * 
948  */
949
950
951 /**
952  * @class Roo.bootstrap.Container
953  * @extends Roo.bootstrap.Component
954  * Bootstrap Container class
955  * @cfg {Boolean} jumbotron is it a jumbotron element
956  * @cfg {String} html content of element
957  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
958  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
959  * @cfg {String} header content of header (for panel)
960  * @cfg {String} footer content of footer (for panel)
961  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
962  * @cfg {String} tag (header|aside|section) type of HTML tag.
963  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
964  * @cfg {String} fa (ban|check|...) font awesome icon
965  * @cfg {String} icon (info-sign|check|...) glyphicon name
966  * @cfg {Boolean} hidden (true|false) hide the element
967
968  *     
969  * @constructor
970  * Create a new Container
971  * @param {Object} config The config object
972  */
973
974 Roo.bootstrap.Container = function(config){
975     Roo.bootstrap.Container.superclass.constructor.call(this, config);
976 };
977
978 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
979     
980     jumbotron : false,
981     well: '',
982     panel : '',
983     header: '',
984     footer : '',
985     sticky: '',
986     tag : false,
987     alert : false,
988     fa: false,
989     icon : false,
990   
991      
992     getChildContainer : function() {
993         
994         if(!this.el){
995             return false;
996         }
997         
998         if (this.panel.length) {
999             return this.el.select('.panel-body',true).first();
1000         }
1001         
1002         return this.el;
1003     },
1004     
1005     
1006     getAutoCreate : function(){
1007         
1008         var cfg = {
1009             tag : this.tag || 'div',
1010             html : '',
1011             cls : ''
1012         };
1013         if (this.jumbotron) {
1014             cfg.cls = 'jumbotron';
1015         }
1016         
1017         
1018         
1019         // - this is applied by the parent..
1020         //if (this.cls) {
1021         //    cfg.cls = this.cls + '';
1022         //}
1023         
1024         if (this.sticky.length) {
1025             
1026             var bd = Roo.get(document.body);
1027             if (!bd.hasClass('bootstrap-sticky')) {
1028                 bd.addClass('bootstrap-sticky');
1029                 Roo.select('html',true).setStyle('height', '100%');
1030             }
1031              
1032             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1033         }
1034         
1035         
1036         if (this.well.length) {
1037             switch (this.well) {
1038                 case 'lg':
1039                 case 'sm':
1040                     cfg.cls +=' well well-' +this.well;
1041                     break;
1042                 default:
1043                     cfg.cls +=' well';
1044                     break;
1045             }
1046         }
1047         
1048         if (this.hidden) {
1049             cfg.cls += ' hidden';
1050         }
1051         
1052         
1053         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1054             cfg.cls +=' alert alert-' + this.alert;
1055         }
1056         
1057         var body = cfg;
1058         
1059         if (this.panel.length) {
1060             cfg.cls += ' panel panel-' + this.panel;
1061             cfg.cn = [];
1062             if (this.header.length) {
1063                 cfg.cn.push({
1064                     
1065                     cls : 'panel-heading',
1066                     cn : [{
1067                         tag: 'h3',
1068                         cls : 'panel-title',
1069                         html : this.header
1070                     }]
1071                     
1072                 });
1073             }
1074             body = false;
1075             cfg.cn.push({
1076                 cls : 'panel-body',
1077                 html : this.html
1078             });
1079             
1080             
1081             if (this.footer.length) {
1082                 cfg.cn.push({
1083                     cls : 'panel-footer',
1084                     html : this.footer
1085                     
1086                 });
1087             }
1088             
1089         }
1090         
1091         if (body) {
1092             body.html = this.html || cfg.html;
1093             // prefix with the icons..
1094             if (this.fa) {
1095                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1096             }
1097             if (this.icon) {
1098                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1099             }
1100             
1101             
1102         }
1103         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1104             cfg.cls =  'container';
1105         }
1106         
1107         return cfg;
1108     },
1109     
1110     titleEl : function()
1111     {
1112         if(!this.el || !this.panel.length || !this.header.length){
1113             return;
1114         }
1115         
1116         return this.el.select('.panel-title',true).first();
1117     },
1118     
1119     setTitle : function(v)
1120     {
1121         var titleEl = this.titleEl();
1122         
1123         if(!titleEl){
1124             return;
1125         }
1126         
1127         titleEl.dom.innerHTML = v;
1128     },
1129     
1130     getTitle : function()
1131     {
1132         
1133         var titleEl = this.titleEl();
1134         
1135         if(!titleEl){
1136             return '';
1137         }
1138         
1139         return titleEl.dom.innerHTML;
1140     },
1141     
1142     show : function() {
1143         this.el.removeClass('hidden');
1144     },
1145     hide: function() {
1146         if (!this.el.hasClass('hidden')) {
1147             this.el.addClass('hidden');
1148         }
1149         
1150     }
1151    
1152 });
1153
1154  /*
1155  * - LGPL
1156  *
1157  * image
1158  * 
1159  */
1160
1161
1162 /**
1163  * @class Roo.bootstrap.Img
1164  * @extends Roo.bootstrap.Component
1165  * Bootstrap Img class
1166  * @cfg {Boolean} imgResponsive false | true
1167  * @cfg {String} border rounded | circle | thumbnail
1168  * @cfg {String} src image source
1169  * @cfg {String} alt image alternative text
1170  * @cfg {String} href a tag href
1171  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1172  * 
1173  * @constructor
1174  * Create a new Input
1175  * @param {Object} config The config object
1176  */
1177
1178 Roo.bootstrap.Img = function(config){
1179     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1180     
1181     this.addEvents({
1182         // img events
1183         /**
1184          * @event click
1185          * The img click event for the img.
1186          * @param {Roo.EventObject} e
1187          */
1188         "click" : true
1189     });
1190 };
1191
1192 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1193     
1194     imgResponsive: true,
1195     border: '',
1196     src: '',
1197     href: false,
1198     target: false,
1199
1200     getAutoCreate : function(){
1201         
1202         var cfg = {
1203             tag: 'img',
1204             cls: (this.imgResponsive) ? 'img-responsive' : '',
1205             html : null
1206         }
1207         
1208         cfg.html = this.html || cfg.html;
1209         
1210         cfg.src = this.src || cfg.src;
1211         
1212         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1213             cfg.cls += ' img-' + this.border;
1214         }
1215         
1216         if(this.alt){
1217             cfg.alt = this.alt;
1218         }
1219         
1220         if(this.href){
1221             var a = {
1222                 tag: 'a',
1223                 href: this.href,
1224                 cn: [
1225                     cfg
1226                 ]
1227             }
1228             
1229             if(this.target){
1230                 a.target = this.target;
1231             }
1232             
1233         }
1234         
1235         
1236         return (this.href) ? a : cfg;
1237     },
1238     
1239     initEvents: function() {
1240         
1241         if(!this.href){
1242             this.el.on('click', this.onClick, this);
1243         }
1244     },
1245     
1246     onClick : function(e)
1247     {
1248         Roo.log('img onclick');
1249         this.fireEvent('click', this, e);
1250     }
1251    
1252 });
1253
1254  /*
1255  * - LGPL
1256  *
1257  * image
1258  * 
1259  */
1260
1261
1262 /**
1263  * @class Roo.bootstrap.Link
1264  * @extends Roo.bootstrap.Component
1265  * Bootstrap Link Class
1266  * @cfg {String} alt image alternative text
1267  * @cfg {String} href a tag href
1268  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1269  * @cfg {String} html the content of the link.
1270  * @cfg {String} anchor name for the anchor link
1271
1272  * @cfg {Boolean} preventDefault (true | false) default false
1273
1274  * 
1275  * @constructor
1276  * Create a new Input
1277  * @param {Object} config The config object
1278  */
1279
1280 Roo.bootstrap.Link = function(config){
1281     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1282     
1283     this.addEvents({
1284         // img events
1285         /**
1286          * @event click
1287          * The img click event for the img.
1288          * @param {Roo.EventObject} e
1289          */
1290         "click" : true
1291     });
1292 };
1293
1294 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1295     
1296     href: false,
1297     target: false,
1298     preventDefault: false,
1299     anchor : false,
1300     alt : false,
1301
1302     getAutoCreate : function()
1303     {
1304         
1305         var cfg = {
1306             tag: 'a'
1307         };
1308         // anchor's do not require html/href...
1309         if (this.anchor === false) {
1310             cfg.html = this.html || 'html-missing';
1311             cfg.href = this.href || '#';
1312         } else {
1313             cfg.name = this.anchor;
1314             if (this.html !== false) {
1315                 cfg.html = this.html;
1316             }
1317             if (this.href !== false) {
1318                 cfg.href = this.href;
1319             }
1320         }
1321         
1322         if(this.alt !== false){
1323             cfg.alt = this.alt;
1324         }
1325         
1326         
1327         if(this.target !== false) {
1328             cfg.target = this.target;
1329         }
1330         
1331         return cfg;
1332     },
1333     
1334     initEvents: function() {
1335         
1336         if(!this.href || this.preventDefault){
1337             this.el.on('click', this.onClick, this);
1338         }
1339     },
1340     
1341     onClick : function(e)
1342     {
1343         if(this.preventDefault){
1344             e.preventDefault();
1345         }
1346         //Roo.log('img onclick');
1347         this.fireEvent('click', this, e);
1348     }
1349    
1350 });
1351
1352  /*
1353  * - LGPL
1354  *
1355  * header
1356  * 
1357  */
1358
1359 /**
1360  * @class Roo.bootstrap.Header
1361  * @extends Roo.bootstrap.Component
1362  * Bootstrap Header class
1363  * @cfg {String} html content of header
1364  * @cfg {Number} level (1|2|3|4|5|6) default 1
1365  * 
1366  * @constructor
1367  * Create a new Header
1368  * @param {Object} config The config object
1369  */
1370
1371
1372 Roo.bootstrap.Header  = function(config){
1373     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1374 };
1375
1376 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1377     
1378     //href : false,
1379     html : false,
1380     level : 1,
1381     
1382     
1383     
1384     getAutoCreate : function(){
1385         
1386         
1387         
1388         var cfg = {
1389             tag: 'h' + (1 *this.level),
1390             html: this.html || ''
1391         } ;
1392         
1393         return cfg;
1394     }
1395    
1396 });
1397
1398  
1399
1400  /*
1401  * Based on:
1402  * Ext JS Library 1.1.1
1403  * Copyright(c) 2006-2007, Ext JS, LLC.
1404  *
1405  * Originally Released Under LGPL - original licence link has changed is not relivant.
1406  *
1407  * Fork - LGPL
1408  * <script type="text/javascript">
1409  */
1410  
1411 /**
1412  * @class Roo.bootstrap.MenuMgr
1413  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1414  * @singleton
1415  */
1416 Roo.bootstrap.MenuMgr = function(){
1417    var menus, active, groups = {}, attached = false, lastShow = new Date();
1418
1419    // private - called when first menu is created
1420    function init(){
1421        menus = {};
1422        active = new Roo.util.MixedCollection();
1423        Roo.get(document).addKeyListener(27, function(){
1424            if(active.length > 0){
1425                hideAll();
1426            }
1427        });
1428    }
1429
1430    // private
1431    function hideAll(){
1432        if(active && active.length > 0){
1433            var c = active.clone();
1434            c.each(function(m){
1435                m.hide();
1436            });
1437        }
1438    }
1439
1440    // private
1441    function onHide(m){
1442        active.remove(m);
1443        if(active.length < 1){
1444            Roo.get(document).un("mouseup", onMouseDown);
1445             
1446            attached = false;
1447        }
1448    }
1449
1450    // private
1451    function onShow(m){
1452        var last = active.last();
1453        lastShow = new Date();
1454        active.add(m);
1455        if(!attached){
1456           Roo.get(document).on("mouseup", onMouseDown);
1457            
1458            attached = true;
1459        }
1460        if(m.parentMenu){
1461           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1462           m.parentMenu.activeChild = m;
1463        }else if(last && last.isVisible()){
1464           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1465        }
1466    }
1467
1468    // private
1469    function onBeforeHide(m){
1470        if(m.activeChild){
1471            m.activeChild.hide();
1472        }
1473        if(m.autoHideTimer){
1474            clearTimeout(m.autoHideTimer);
1475            delete m.autoHideTimer;
1476        }
1477    }
1478
1479    // private
1480    function onBeforeShow(m){
1481        var pm = m.parentMenu;
1482        if(!pm && !m.allowOtherMenus){
1483            hideAll();
1484        }else if(pm && pm.activeChild && active != m){
1485            pm.activeChild.hide();
1486        }
1487    }
1488
1489    // private
1490    function onMouseDown(e){
1491         Roo.log("on MouseDown");
1492         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1493            hideAll();
1494         }
1495         
1496         
1497    }
1498
1499    // private
1500    function onBeforeCheck(mi, state){
1501        if(state){
1502            var g = groups[mi.group];
1503            for(var i = 0, l = g.length; i < l; i++){
1504                if(g[i] != mi){
1505                    g[i].setChecked(false);
1506                }
1507            }
1508        }
1509    }
1510
1511    return {
1512
1513        /**
1514         * Hides all menus that are currently visible
1515         */
1516        hideAll : function(){
1517             hideAll();  
1518        },
1519
1520        // private
1521        register : function(menu){
1522            if(!menus){
1523                init();
1524            }
1525            menus[menu.id] = menu;
1526            menu.on("beforehide", onBeforeHide);
1527            menu.on("hide", onHide);
1528            menu.on("beforeshow", onBeforeShow);
1529            menu.on("show", onShow);
1530            var g = menu.group;
1531            if(g && menu.events["checkchange"]){
1532                if(!groups[g]){
1533                    groups[g] = [];
1534                }
1535                groups[g].push(menu);
1536                menu.on("checkchange", onCheck);
1537            }
1538        },
1539
1540         /**
1541          * Returns a {@link Roo.menu.Menu} object
1542          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1543          * be used to generate and return a new Menu instance.
1544          */
1545        get : function(menu){
1546            if(typeof menu == "string"){ // menu id
1547                return menus[menu];
1548            }else if(menu.events){  // menu instance
1549                return menu;
1550            }
1551            /*else if(typeof menu.length == 'number'){ // array of menu items?
1552                return new Roo.bootstrap.Menu({items:menu});
1553            }else{ // otherwise, must be a config
1554                return new Roo.bootstrap.Menu(menu);
1555            }
1556            */
1557            return false;
1558        },
1559
1560        // private
1561        unregister : function(menu){
1562            delete menus[menu.id];
1563            menu.un("beforehide", onBeforeHide);
1564            menu.un("hide", onHide);
1565            menu.un("beforeshow", onBeforeShow);
1566            menu.un("show", onShow);
1567            var g = menu.group;
1568            if(g && menu.events["checkchange"]){
1569                groups[g].remove(menu);
1570                menu.un("checkchange", onCheck);
1571            }
1572        },
1573
1574        // private
1575        registerCheckable : function(menuItem){
1576            var g = menuItem.group;
1577            if(g){
1578                if(!groups[g]){
1579                    groups[g] = [];
1580                }
1581                groups[g].push(menuItem);
1582                menuItem.on("beforecheckchange", onBeforeCheck);
1583            }
1584        },
1585
1586        // private
1587        unregisterCheckable : function(menuItem){
1588            var g = menuItem.group;
1589            if(g){
1590                groups[g].remove(menuItem);
1591                menuItem.un("beforecheckchange", onBeforeCheck);
1592            }
1593        }
1594    };
1595 }();/*
1596  * - LGPL
1597  *
1598  * menu
1599  * 
1600  */
1601
1602 /**
1603  * @class Roo.bootstrap.Menu
1604  * @extends Roo.bootstrap.Component
1605  * Bootstrap Menu class - container for MenuItems
1606  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1607  * 
1608  * @constructor
1609  * Create a new Menu
1610  * @param {Object} config The config object
1611  */
1612
1613
1614 Roo.bootstrap.Menu = function(config){
1615     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1616     if (this.registerMenu) {
1617         Roo.bootstrap.MenuMgr.register(this);
1618     }
1619     this.addEvents({
1620         /**
1621          * @event beforeshow
1622          * Fires before this menu is displayed
1623          * @param {Roo.menu.Menu} this
1624          */
1625         beforeshow : true,
1626         /**
1627          * @event beforehide
1628          * Fires before this menu is hidden
1629          * @param {Roo.menu.Menu} this
1630          */
1631         beforehide : true,
1632         /**
1633          * @event show
1634          * Fires after this menu is displayed
1635          * @param {Roo.menu.Menu} this
1636          */
1637         show : true,
1638         /**
1639          * @event hide
1640          * Fires after this menu is hidden
1641          * @param {Roo.menu.Menu} this
1642          */
1643         hide : true,
1644         /**
1645          * @event click
1646          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1647          * @param {Roo.menu.Menu} this
1648          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1649          * @param {Roo.EventObject} e
1650          */
1651         click : true,
1652         /**
1653          * @event mouseover
1654          * Fires when the mouse is hovering over this menu
1655          * @param {Roo.menu.Menu} this
1656          * @param {Roo.EventObject} e
1657          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658          */
1659         mouseover : true,
1660         /**
1661          * @event mouseout
1662          * Fires when the mouse exits this menu
1663          * @param {Roo.menu.Menu} this
1664          * @param {Roo.EventObject} e
1665          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1666          */
1667         mouseout : true,
1668         /**
1669          * @event itemclick
1670          * Fires when a menu item contained in this menu is clicked
1671          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1672          * @param {Roo.EventObject} e
1673          */
1674         itemclick: true
1675     });
1676     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1677 };
1678
1679 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1680     
1681    /// html : false,
1682     //align : '',
1683     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1684     type: false,
1685     /**
1686      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1687      */
1688     registerMenu : true,
1689     
1690     menuItems :false, // stores the menu items..
1691     
1692     hidden:true,
1693     
1694     parentMenu : false,
1695     
1696     getChildContainer : function() {
1697         return this.el;  
1698     },
1699     
1700     getAutoCreate : function(){
1701          
1702         //if (['right'].indexOf(this.align)!==-1) {
1703         //    cfg.cn[1].cls += ' pull-right'
1704         //}
1705         
1706         
1707         var cfg = {
1708             tag : 'ul',
1709             cls : 'dropdown-menu' ,
1710             style : 'z-index:1000'
1711             
1712         }
1713         
1714         if (this.type === 'submenu') {
1715             cfg.cls = 'submenu active';
1716         }
1717         if (this.type === 'treeview') {
1718             cfg.cls = 'treeview-menu';
1719         }
1720         
1721         return cfg;
1722     },
1723     initEvents : function() {
1724         
1725        // Roo.log("ADD event");
1726        // Roo.log(this.triggerEl.dom);
1727         this.triggerEl.on('click', this.onTriggerPress, this);
1728         this.triggerEl.addClass('dropdown-toggle');
1729         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1730
1731         this.el.on("mouseover", this.onMouseOver, this);
1732         this.el.on("mouseout", this.onMouseOut, this);
1733         
1734         
1735     },
1736     findTargetItem : function(e){
1737         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1738         if(!t){
1739             return false;
1740         }
1741         //Roo.log(t);         Roo.log(t.id);
1742         if(t && t.id){
1743             //Roo.log(this.menuitems);
1744             return this.menuitems.get(t.id);
1745             
1746             //return this.items.get(t.menuItemId);
1747         }
1748         
1749         return false;
1750     },
1751     onClick : function(e){
1752         Roo.log("menu.onClick");
1753         var t = this.findTargetItem(e);
1754         if(!t || t.isContainer){
1755             return;
1756         }
1757         Roo.log(e);
1758         /*
1759         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1760             if(t == this.activeItem && t.shouldDeactivate(e)){
1761                 this.activeItem.deactivate();
1762                 delete this.activeItem;
1763                 return;
1764             }
1765             if(t.canActivate){
1766                 this.setActiveItem(t, true);
1767             }
1768             return;
1769             
1770             
1771         }
1772         */
1773        
1774         Roo.log('pass click event');
1775         
1776         t.onClick(e);
1777         
1778         this.fireEvent("click", this, t, e);
1779         
1780         this.hide();
1781     },
1782      onMouseOver : function(e){
1783         var t  = this.findTargetItem(e);
1784         //Roo.log(t);
1785         //if(t){
1786         //    if(t.canActivate && !t.disabled){
1787         //        this.setActiveItem(t, true);
1788         //    }
1789         //}
1790         
1791         this.fireEvent("mouseover", this, e, t);
1792     },
1793     isVisible : function(){
1794         return !this.hidden;
1795     },
1796      onMouseOut : function(e){
1797         var t  = this.findTargetItem(e);
1798         
1799         //if(t ){
1800         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1801         //        this.activeItem.deactivate();
1802         //        delete this.activeItem;
1803         //    }
1804         //}
1805         this.fireEvent("mouseout", this, e, t);
1806     },
1807     
1808     
1809     /**
1810      * Displays this menu relative to another element
1811      * @param {String/HTMLElement/Roo.Element} element The element to align to
1812      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1813      * the element (defaults to this.defaultAlign)
1814      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1815      */
1816     show : function(el, pos, parentMenu){
1817         this.parentMenu = parentMenu;
1818         if(!this.el){
1819             this.render();
1820         }
1821         this.fireEvent("beforeshow", this);
1822         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1823     },
1824      /**
1825      * Displays this menu at a specific xy position
1826      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1827      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1828      */
1829     showAt : function(xy, parentMenu, /* private: */_e){
1830         this.parentMenu = parentMenu;
1831         if(!this.el){
1832             this.render();
1833         }
1834         if(_e !== false){
1835             this.fireEvent("beforeshow", this);
1836             
1837             //xy = this.el.adjustForConstraints(xy);
1838         }
1839         //this.el.setXY(xy);
1840         //this.el.show();
1841         this.hideMenuItems();
1842         this.hidden = false;
1843         this.triggerEl.addClass('open');
1844         this.focus();
1845         this.fireEvent("show", this);
1846     },
1847     
1848     focus : function(){
1849         return;
1850         if(!this.hidden){
1851             this.doFocus.defer(50, this);
1852         }
1853     },
1854
1855     doFocus : function(){
1856         if(!this.hidden){
1857             this.focusEl.focus();
1858         }
1859     },
1860
1861     /**
1862      * Hides this menu and optionally all parent menus
1863      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1864      */
1865     hide : function(deep){
1866         
1867         this.hideMenuItems();
1868         if(this.el && this.isVisible()){
1869             this.fireEvent("beforehide", this);
1870             if(this.activeItem){
1871                 this.activeItem.deactivate();
1872                 this.activeItem = null;
1873             }
1874             this.triggerEl.removeClass('open');;
1875             this.hidden = true;
1876             this.fireEvent("hide", this);
1877         }
1878         if(deep === true && this.parentMenu){
1879             this.parentMenu.hide(true);
1880         }
1881     },
1882     
1883     onTriggerPress  : function(e)
1884     {
1885         
1886         Roo.log('trigger press');
1887         //Roo.log(e.getTarget());
1888        // Roo.log(this.triggerEl.dom);
1889         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1890             return;
1891         }
1892         if (this.isVisible()) {
1893             Roo.log('hide');
1894             this.hide();
1895         } else {
1896             this.show(this.triggerEl, false, false);
1897         }
1898         
1899         
1900     },
1901     
1902          
1903        
1904     
1905     hideMenuItems : function()
1906     {
1907         //$(backdrop).remove()
1908         Roo.select('.open',true).each(function(aa) {
1909             
1910             aa.removeClass('open');
1911           //var parent = getParent($(this))
1912           //var relatedTarget = { relatedTarget: this }
1913           
1914            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1915           //if (e.isDefaultPrevented()) return
1916            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1917         })
1918     },
1919     addxtypeChild : function (tree, cntr) {
1920         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1921           
1922         this.menuitems.add(comp);
1923         return comp;
1924
1925     },
1926     getEl : function()
1927     {
1928         Roo.log(this.el);
1929         return this.el;
1930     }
1931 });
1932
1933  
1934  /*
1935  * - LGPL
1936  *
1937  * menu item
1938  * 
1939  */
1940
1941
1942 /**
1943  * @class Roo.bootstrap.MenuItem
1944  * @extends Roo.bootstrap.Component
1945  * Bootstrap MenuItem class
1946  * @cfg {String} html the menu label
1947  * @cfg {String} href the link
1948  * @cfg {Boolean} preventDefault (true | false) default true
1949  * @cfg {Boolean} isContainer (true | false) default false
1950  * 
1951  * 
1952  * @constructor
1953  * Create a new MenuItem
1954  * @param {Object} config The config object
1955  */
1956
1957
1958 Roo.bootstrap.MenuItem = function(config){
1959     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1960     this.addEvents({
1961         // raw events
1962         /**
1963          * @event click
1964          * The raw click event for the entire grid.
1965          * @param {Roo.EventObject} e
1966          */
1967         "click" : true
1968     });
1969 };
1970
1971 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1972     
1973     href : false,
1974     html : false,
1975     preventDefault: true,
1976     isContainer : false,
1977     
1978     getAutoCreate : function(){
1979         
1980         if(this.isContainer){
1981             return {
1982                 tag: 'li',
1983                 cls: 'dropdown-menu-item'
1984             };
1985         }
1986         
1987         var cfg= {
1988             tag: 'li',
1989             cls: 'dropdown-menu-item',
1990             cn: [
1991                     {
1992                         tag : 'a',
1993                         href : '#',
1994                         html : 'Link'
1995                     }
1996                 ]
1997         };
1998         if (this.parent().type == 'treeview') {
1999             cfg.cls = 'treeview-menu';
2000         }
2001         
2002         cfg.cn[0].href = this.href || cfg.cn[0].href ;
2003         cfg.cn[0].html = this.html || cfg.cn[0].html ;
2004         return cfg;
2005     },
2006     
2007     initEvents: function() {
2008         
2009         //this.el.select('a').on('click', this.onClick, this);
2010         
2011     },
2012     onClick : function(e)
2013     {
2014         Roo.log('item on click ');
2015         //if(this.preventDefault){
2016         //    e.preventDefault();
2017         //}
2018         //this.parent().hideMenuItems();
2019         
2020         this.fireEvent('click', this, e);
2021     },
2022     getEl : function()
2023     {
2024         return this.el;
2025     }
2026 });
2027
2028  
2029
2030  /*
2031  * - LGPL
2032  *
2033  * menu separator
2034  * 
2035  */
2036
2037
2038 /**
2039  * @class Roo.bootstrap.MenuSeparator
2040  * @extends Roo.bootstrap.Component
2041  * Bootstrap MenuSeparator class
2042  * 
2043  * @constructor
2044  * Create a new MenuItem
2045  * @param {Object} config The config object
2046  */
2047
2048
2049 Roo.bootstrap.MenuSeparator = function(config){
2050     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2051 };
2052
2053 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2054     
2055     getAutoCreate : function(){
2056         var cfg = {
2057             cls: 'divider',
2058             tag : 'li'
2059         };
2060         
2061         return cfg;
2062     }
2063    
2064 });
2065
2066  
2067
2068  
2069 /*
2070 * Licence: LGPL
2071 */
2072
2073 /**
2074  * @class Roo.bootstrap.Modal
2075  * @extends Roo.bootstrap.Component
2076  * Bootstrap Modal class
2077  * @cfg {String} title Title of dialog
2078  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2079  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn 
2080  * @cfg {Boolean} specificTitle default false
2081  * @cfg {Array} buttons Array of buttons or standard button set..
2082  * @cfg {String} buttonPosition (left|right|center) default right
2083  * @cfg {Boolean} animate default true
2084  * @cfg {Boolean} allow_close default true
2085  * 
2086  * @constructor
2087  * Create a new Modal Dialog
2088  * @param {Object} config The config object
2089  */
2090
2091 Roo.bootstrap.Modal = function(config){
2092     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2093     this.addEvents({
2094         // raw events
2095         /**
2096          * @event btnclick
2097          * The raw btnclick event for the button
2098          * @param {Roo.EventObject} e
2099          */
2100         "btnclick" : true
2101     });
2102     this.buttons = this.buttons || [];
2103      
2104     if (this.tmpl) {
2105         this.tmpl = Roo.factory(this.tmpl);
2106     }
2107     
2108 };
2109
2110 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2111     
2112     title : 'test dialog',
2113    
2114     buttons : false,
2115     
2116     // set on load...
2117      
2118     html: false,
2119     
2120     tmp: false,
2121     
2122     specificTitle: false,
2123     
2124     buttonPosition: 'right',
2125     
2126     allow_close : true,
2127     
2128     animate : true,
2129     
2130     
2131      // private
2132     bodyEl:  false,
2133     footerEl:  false,
2134     titleEl:  false,
2135     closeEl:  false,
2136     
2137     
2138     onRender : function(ct, position)
2139     {
2140         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2141      
2142         if(!this.el){
2143             var cfg = Roo.apply({},  this.getAutoCreate());
2144             cfg.id = Roo.id();
2145             //if(!cfg.name){
2146             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2147             //}
2148             //if (!cfg.name.length) {
2149             //    delete cfg.name;
2150            // }
2151             if (this.cls) {
2152                 cfg.cls += ' ' + this.cls;
2153             }
2154             if (this.style) {
2155                 cfg.style = this.style;
2156             }
2157             this.el = Roo.get(document.body).createChild(cfg, position);
2158         }
2159         //var type = this.el.dom.type;
2160         
2161         
2162         
2163         
2164         if(this.tabIndex !== undefined){
2165             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2166         }
2167         
2168         
2169         this.bodyEl = this.el.select('.modal-body',true).first();
2170         this.closeEl = this.el.select('.modal-header .close', true).first();
2171         this.footerEl = this.el.select('.modal-footer',true).first();
2172         this.titleEl = this.el.select('.modal-title',true).first();
2173         
2174         
2175          
2176         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2177         this.maskEl.enableDisplayMode("block");
2178         this.maskEl.hide();
2179         //this.el.addClass("x-dlg-modal");
2180     
2181         if (this.buttons.length) {
2182             Roo.each(this.buttons, function(bb) {
2183                 b = Roo.apply({}, bb);
2184                 b.xns = b.xns || Roo.bootstrap;
2185                 b.xtype = b.xtype || 'Button';
2186                 if (typeof(b.listeners) == 'undefined') {
2187                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2188                 }
2189                 
2190                 var btn = Roo.factory(b);
2191                 
2192                 btn.onRender(this.el.select('.modal-footer div').first());
2193                 
2194             },this);
2195         }
2196         // render the children.
2197         var nitems = [];
2198         
2199         if(typeof(this.items) != 'undefined'){
2200             var items = this.items;
2201             delete this.items;
2202
2203             for(var i =0;i < items.length;i++) {
2204                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2205             }
2206         }
2207         
2208         this.items = nitems;
2209         
2210         // where are these used - they used to be body/close/footer
2211         
2212        
2213         this.initEvents();
2214         //this.el.addClass([this.fieldClass, this.cls]);
2215         
2216     },
2217     getAutoCreate : function(){
2218         
2219         
2220         var bdy = {
2221                 cls : 'modal-body',
2222                 html : this.html || ''
2223         };
2224         
2225         var title = {
2226             tag: 'h4',
2227             cls : 'modal-title',
2228             html : this.title
2229         };
2230         
2231         if(this.specificTitle){
2232             title = this.title;
2233             
2234         };
2235         
2236         var header = [];
2237         if (this.allow_close) {
2238             header.push({
2239                 tag: 'button',
2240                 cls : 'close',
2241                 html : '&times'
2242             });
2243         }
2244         header.push(title);
2245         
2246         var modal = {
2247             cls: "modal",
2248             style : 'display: none',
2249             cn : [
2250                 {
2251                     cls: "modal-dialog",
2252                     cn : [
2253                         {
2254                             cls : "modal-content",
2255                             cn : [
2256                                 {
2257                                     cls : 'modal-header',
2258                                     cn : header
2259                                 },
2260                                 bdy,
2261                                 {
2262                                     cls : 'modal-footer',
2263                                     cn : [
2264                                         {
2265                                             tag: 'div',
2266                                             cls: 'btn-' + this.buttonPosition
2267                                         }
2268                                     ]
2269                                     
2270                                 }
2271                                 
2272                                 
2273                             ]
2274                             
2275                         }
2276                     ]
2277                         
2278                 }
2279             ]
2280         };
2281         
2282         if(this.animate){
2283             modal.cls += ' fade';
2284         }
2285         
2286         return modal;
2287           
2288     },
2289     getChildContainer : function() {
2290          
2291          return this.bodyEl;
2292         
2293     },
2294     getButtonContainer : function() {
2295          return this.el.select('.modal-footer div',true).first();
2296         
2297     },
2298     initEvents : function()
2299     {
2300         if (this.allow_close) {
2301             this.closeEl.on('click', this.hide, this);
2302         }
2303
2304     },
2305     show : function() {
2306         
2307         if (!this.rendered) {
2308             this.render();
2309         }
2310         
2311         this.el.setStyle('display', 'block');
2312         
2313         if(this.animate){
2314             var _this = this;
2315             (function(){ _this.el.addClass('in'); }).defer(50);
2316         }else{
2317             this.el.addClass('in');
2318         }
2319         
2320         // not sure how we can show data in here.. 
2321         //if (this.tmpl) {
2322         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2323         //}
2324         
2325         Roo.get(document.body).addClass("x-body-masked");
2326         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2327         this.maskEl.show();
2328         this.el.setStyle('zIndex', '10001');
2329        
2330         this.fireEvent('show', this);
2331         
2332         
2333     },
2334     hide : function()
2335     {
2336         this.maskEl.hide();
2337         Roo.get(document.body).removeClass("x-body-masked");
2338         this.el.removeClass('in');
2339         
2340         if(this.animate){
2341             var _this = this;
2342             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2343         }else{
2344             this.el.setStyle('display', 'none');
2345         }
2346         
2347         this.fireEvent('hide', this);
2348     },
2349     
2350     addButton : function(str, cb)
2351     {
2352          
2353         
2354         var b = Roo.apply({}, { html : str } );
2355         b.xns = b.xns || Roo.bootstrap;
2356         b.xtype = b.xtype || 'Button';
2357         if (typeof(b.listeners) == 'undefined') {
2358             b.listeners = { click : cb.createDelegate(this)  };
2359         }
2360         
2361         var btn = Roo.factory(b);
2362            
2363         btn.onRender(this.el.select('.modal-footer div').first());
2364         
2365         return btn;   
2366        
2367     },
2368     
2369     setDefaultButton : function(btn)
2370     {
2371         //this.el.select('.modal-footer').()
2372     },
2373     resizeTo: function(w,h)
2374     {
2375         // skip..
2376     },
2377     setContentSize  : function(w, h)
2378     {
2379         
2380     },
2381     onButtonClick: function(btn,e)
2382     {
2383         //Roo.log([a,b,c]);
2384         this.fireEvent('btnclick', btn.name, e);
2385     },
2386      /**
2387      * Set the title of the Dialog
2388      * @param {String} str new Title
2389      */
2390     setTitle: function(str) {
2391         this.titleEl.dom.innerHTML = str;    
2392     },
2393     /**
2394      * Set the body of the Dialog
2395      * @param {String} str new Title
2396      */
2397     setBody: function(str) {
2398         this.bodyEl.dom.innerHTML = str;    
2399     },
2400     /**
2401      * Set the body of the Dialog using the template
2402      * @param {Obj} data - apply this data to the template and replace the body contents.
2403      */
2404     applyBody: function(obj)
2405     {
2406         if (!this.tmpl) {
2407             Roo.log("Error - using apply Body without a template");
2408             //code
2409         }
2410         this.tmpl.overwrite(this.bodyEl, obj);
2411     }
2412     
2413 });
2414
2415
2416 Roo.apply(Roo.bootstrap.Modal,  {
2417     /**
2418          * Button config that displays a single OK button
2419          * @type Object
2420          */
2421         OK :  [{
2422             name : 'ok',
2423             weight : 'primary',
2424             html : 'OK'
2425         }], 
2426         /**
2427          * Button config that displays Yes and No buttons
2428          * @type Object
2429          */
2430         YESNO : [
2431             {
2432                 name  : 'no',
2433                 html : 'No'
2434             },
2435             {
2436                 name  :'yes',
2437                 weight : 'primary',
2438                 html : 'Yes'
2439             }
2440         ],
2441         
2442         /**
2443          * Button config that displays OK and Cancel buttons
2444          * @type Object
2445          */
2446         OKCANCEL : [
2447             {
2448                name : 'cancel',
2449                 html : 'Cancel'
2450             },
2451             {
2452                 name : 'ok',
2453                 weight : 'primary',
2454                 html : 'OK'
2455             }
2456         ],
2457         /**
2458          * Button config that displays Yes, No and Cancel buttons
2459          * @type Object
2460          */
2461         YESNOCANCEL : [
2462             {
2463                 name : 'yes',
2464                 weight : 'primary',
2465                 html : 'Yes'
2466             },
2467             {
2468                 name : 'no',
2469                 html : 'No'
2470             },
2471             {
2472                 name : 'cancel',
2473                 html : 'Cancel'
2474             }
2475         ]
2476 });
2477  
2478  /*
2479  * - LGPL
2480  *
2481  * messagebox - can be used as a replace
2482  * 
2483  */
2484 /**
2485  * @class Roo.MessageBox
2486  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2487  * Example usage:
2488  *<pre><code>
2489 // Basic alert:
2490 Roo.Msg.alert('Status', 'Changes saved successfully.');
2491
2492 // Prompt for user data:
2493 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2494     if (btn == 'ok'){
2495         // process text value...
2496     }
2497 });
2498
2499 // Show a dialog using config options:
2500 Roo.Msg.show({
2501    title:'Save Changes?',
2502    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2503    buttons: Roo.Msg.YESNOCANCEL,
2504    fn: processResult,
2505    animEl: 'elId'
2506 });
2507 </code></pre>
2508  * @singleton
2509  */
2510 Roo.bootstrap.MessageBox = function(){
2511     var dlg, opt, mask, waitTimer;
2512     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2513     var buttons, activeTextEl, bwidth;
2514
2515     
2516     // private
2517     var handleButton = function(button){
2518         dlg.hide();
2519         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2520     };
2521
2522     // private
2523     var handleHide = function(){
2524         if(opt && opt.cls){
2525             dlg.el.removeClass(opt.cls);
2526         }
2527         //if(waitTimer){
2528         //    Roo.TaskMgr.stop(waitTimer);
2529         //    waitTimer = null;
2530         //}
2531     };
2532
2533     // private
2534     var updateButtons = function(b){
2535         var width = 0;
2536         if(!b){
2537             buttons["ok"].hide();
2538             buttons["cancel"].hide();
2539             buttons["yes"].hide();
2540             buttons["no"].hide();
2541             //dlg.footer.dom.style.display = 'none';
2542             return width;
2543         }
2544         dlg.footerEl.dom.style.display = '';
2545         for(var k in buttons){
2546             if(typeof buttons[k] != "function"){
2547                 if(b[k]){
2548                     buttons[k].show();
2549                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2550                     width += buttons[k].el.getWidth()+15;
2551                 }else{
2552                     buttons[k].hide();
2553                 }
2554             }
2555         }
2556         return width;
2557     };
2558
2559     // private
2560     var handleEsc = function(d, k, e){
2561         if(opt && opt.closable !== false){
2562             dlg.hide();
2563         }
2564         if(e){
2565             e.stopEvent();
2566         }
2567     };
2568
2569     return {
2570         /**
2571          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2572          * @return {Roo.BasicDialog} The BasicDialog element
2573          */
2574         getDialog : function(){
2575            if(!dlg){
2576                 dlg = new Roo.bootstrap.Modal( {
2577                     //draggable: true,
2578                     //resizable:false,
2579                     //constraintoviewport:false,
2580                     //fixedcenter:true,
2581                     //collapsible : false,
2582                     //shim:true,
2583                     //modal: true,
2584                   //  width:400,
2585                   //  height:100,
2586                     //buttonAlign:"center",
2587                     closeClick : function(){
2588                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2589                             handleButton("no");
2590                         }else{
2591                             handleButton("cancel");
2592                         }
2593                     }
2594                 });
2595                 dlg.render();
2596                 dlg.on("hide", handleHide);
2597                 mask = dlg.mask;
2598                 //dlg.addKeyListener(27, handleEsc);
2599                 buttons = {};
2600                 this.buttons = buttons;
2601                 var bt = this.buttonText;
2602                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2603                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2604                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2605                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2606                 Roo.log(buttons)
2607                 bodyEl = dlg.bodyEl.createChild({
2608
2609                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2610                         '<textarea class="roo-mb-textarea"></textarea>' +
2611                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2612                 });
2613                 msgEl = bodyEl.dom.firstChild;
2614                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2615                 textboxEl.enableDisplayMode();
2616                 textboxEl.addKeyListener([10,13], function(){
2617                     if(dlg.isVisible() && opt && opt.buttons){
2618                         if(opt.buttons.ok){
2619                             handleButton("ok");
2620                         }else if(opt.buttons.yes){
2621                             handleButton("yes");
2622                         }
2623                     }
2624                 });
2625                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2626                 textareaEl.enableDisplayMode();
2627                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2628                 progressEl.enableDisplayMode();
2629                 var pf = progressEl.dom.firstChild;
2630                 if (pf) {
2631                     pp = Roo.get(pf.firstChild);
2632                     pp.setHeight(pf.offsetHeight);
2633                 }
2634                 
2635             }
2636             return dlg;
2637         },
2638
2639         /**
2640          * Updates the message box body text
2641          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2642          * the XHTML-compliant non-breaking space character '&amp;#160;')
2643          * @return {Roo.MessageBox} This message box
2644          */
2645         updateText : function(text){
2646             if(!dlg.isVisible() && !opt.width){
2647                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2648             }
2649             msgEl.innerHTML = text || '&#160;';
2650       
2651             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2652             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2653             var w = Math.max(
2654                     Math.min(opt.width || cw , this.maxWidth), 
2655                     Math.max(opt.minWidth || this.minWidth, bwidth)
2656             );
2657             if(opt.prompt){
2658                 activeTextEl.setWidth(w);
2659             }
2660             if(dlg.isVisible()){
2661                 dlg.fixedcenter = false;
2662             }
2663             // to big, make it scroll. = But as usual stupid IE does not support
2664             // !important..
2665             
2666             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2667                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2668                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2669             } else {
2670                 bodyEl.dom.style.height = '';
2671                 bodyEl.dom.style.overflowY = '';
2672             }
2673             if (cw > w) {
2674                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2675             } else {
2676                 bodyEl.dom.style.overflowX = '';
2677             }
2678             
2679             dlg.setContentSize(w, bodyEl.getHeight());
2680             if(dlg.isVisible()){
2681                 dlg.fixedcenter = true;
2682             }
2683             return this;
2684         },
2685
2686         /**
2687          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2688          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2689          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2690          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2691          * @return {Roo.MessageBox} This message box
2692          */
2693         updateProgress : function(value, text){
2694             if(text){
2695                 this.updateText(text);
2696             }
2697             if (pp) { // weird bug on my firefox - for some reason this is not defined
2698                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2699             }
2700             return this;
2701         },        
2702
2703         /**
2704          * Returns true if the message box is currently displayed
2705          * @return {Boolean} True if the message box is visible, else false
2706          */
2707         isVisible : function(){
2708             return dlg && dlg.isVisible();  
2709         },
2710
2711         /**
2712          * Hides the message box if it is displayed
2713          */
2714         hide : function(){
2715             if(this.isVisible()){
2716                 dlg.hide();
2717             }  
2718         },
2719
2720         /**
2721          * Displays a new message box, or reinitializes an existing message box, based on the config options
2722          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2723          * The following config object properties are supported:
2724          * <pre>
2725 Property    Type             Description
2726 ----------  ---------------  ------------------------------------------------------------------------------------
2727 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2728                                    closes (defaults to undefined)
2729 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2730                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2731 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2732                                    progress and wait dialogs will ignore this property and always hide the
2733                                    close button as they can only be closed programmatically.
2734 cls               String           A custom CSS class to apply to the message box element
2735 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2736                                    displayed (defaults to 75)
2737 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2738                                    function will be btn (the name of the button that was clicked, if applicable,
2739                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2740                                    Progress and wait dialogs will ignore this option since they do not respond to
2741                                    user actions and can only be closed programmatically, so any required function
2742                                    should be called by the same code after it closes the dialog.
2743 icon              String           A CSS class that provides a background image to be used as an icon for
2744                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2745 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2746 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2747 modal             Boolean          False to allow user interaction with the page while the message box is
2748                                    displayed (defaults to true)
2749 msg               String           A string that will replace the existing message box body text (defaults
2750                                    to the XHTML-compliant non-breaking space character '&#160;')
2751 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2752 progress          Boolean          True to display a progress bar (defaults to false)
2753 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2754 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2755 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2756 title             String           The title text
2757 value             String           The string value to set into the active textbox element if displayed
2758 wait              Boolean          True to display a progress bar (defaults to false)
2759 width             Number           The width of the dialog in pixels
2760 </pre>
2761          *
2762          * Example usage:
2763          * <pre><code>
2764 Roo.Msg.show({
2765    title: 'Address',
2766    msg: 'Please enter your address:',
2767    width: 300,
2768    buttons: Roo.MessageBox.OKCANCEL,
2769    multiline: true,
2770    fn: saveAddress,
2771    animEl: 'addAddressBtn'
2772 });
2773 </code></pre>
2774          * @param {Object} config Configuration options
2775          * @return {Roo.MessageBox} This message box
2776          */
2777         show : function(options)
2778         {
2779             
2780             // this causes nightmares if you show one dialog after another
2781             // especially on callbacks..
2782              
2783             if(this.isVisible()){
2784                 
2785                 this.hide();
2786                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2787                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2788                 Roo.log("New Dialog Message:" +  options.msg )
2789                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2790                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2791                 
2792             }
2793             var d = this.getDialog();
2794             opt = options;
2795             d.setTitle(opt.title || "&#160;");
2796             d.closeEl.setDisplayed(opt.closable !== false);
2797             activeTextEl = textboxEl;
2798             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2799             if(opt.prompt){
2800                 if(opt.multiline){
2801                     textboxEl.hide();
2802                     textareaEl.show();
2803                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2804                         opt.multiline : this.defaultTextHeight);
2805                     activeTextEl = textareaEl;
2806                 }else{
2807                     textboxEl.show();
2808                     textareaEl.hide();
2809                 }
2810             }else{
2811                 textboxEl.hide();
2812                 textareaEl.hide();
2813             }
2814             progressEl.setDisplayed(opt.progress === true);
2815             this.updateProgress(0);
2816             activeTextEl.dom.value = opt.value || "";
2817             if(opt.prompt){
2818                 dlg.setDefaultButton(activeTextEl);
2819             }else{
2820                 var bs = opt.buttons;
2821                 var db = null;
2822                 if(bs && bs.ok){
2823                     db = buttons["ok"];
2824                 }else if(bs && bs.yes){
2825                     db = buttons["yes"];
2826                 }
2827                 dlg.setDefaultButton(db);
2828             }
2829             bwidth = updateButtons(opt.buttons);
2830             this.updateText(opt.msg);
2831             if(opt.cls){
2832                 d.el.addClass(opt.cls);
2833             }
2834             d.proxyDrag = opt.proxyDrag === true;
2835             d.modal = opt.modal !== false;
2836             d.mask = opt.modal !== false ? mask : false;
2837             if(!d.isVisible()){
2838                 // force it to the end of the z-index stack so it gets a cursor in FF
2839                 document.body.appendChild(dlg.el.dom);
2840                 d.animateTarget = null;
2841                 d.show(options.animEl);
2842             }
2843             return this;
2844         },
2845
2846         /**
2847          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2848          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2849          * and closing the message box when the process is complete.
2850          * @param {String} title The title bar text
2851          * @param {String} msg The message box body text
2852          * @return {Roo.MessageBox} This message box
2853          */
2854         progress : function(title, msg){
2855             this.show({
2856                 title : title,
2857                 msg : msg,
2858                 buttons: false,
2859                 progress:true,
2860                 closable:false,
2861                 minWidth: this.minProgressWidth,
2862                 modal : true
2863             });
2864             return this;
2865         },
2866
2867         /**
2868          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2869          * If a callback function is passed it will be called after the user clicks the button, and the
2870          * id of the button that was clicked will be passed as the only parameter to the callback
2871          * (could also be the top-right close button).
2872          * @param {String} title The title bar text
2873          * @param {String} msg The message box body text
2874          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2875          * @param {Object} scope (optional) The scope of the callback function
2876          * @return {Roo.MessageBox} This message box
2877          */
2878         alert : function(title, msg, fn, scope){
2879             this.show({
2880                 title : title,
2881                 msg : msg,
2882                 buttons: this.OK,
2883                 fn: fn,
2884                 scope : scope,
2885                 modal : true
2886             });
2887             return this;
2888         },
2889
2890         /**
2891          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2892          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2893          * You are responsible for closing the message box when the process is complete.
2894          * @param {String} msg The message box body text
2895          * @param {String} title (optional) The title bar text
2896          * @return {Roo.MessageBox} This message box
2897          */
2898         wait : function(msg, title){
2899             this.show({
2900                 title : title,
2901                 msg : msg,
2902                 buttons: false,
2903                 closable:false,
2904                 progress:true,
2905                 modal:true,
2906                 width:300,
2907                 wait:true
2908             });
2909             waitTimer = Roo.TaskMgr.start({
2910                 run: function(i){
2911                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2912                 },
2913                 interval: 1000
2914             });
2915             return this;
2916         },
2917
2918         /**
2919          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2920          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2921          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2922          * @param {String} title The title bar text
2923          * @param {String} msg The message box body text
2924          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2925          * @param {Object} scope (optional) The scope of the callback function
2926          * @return {Roo.MessageBox} This message box
2927          */
2928         confirm : function(title, msg, fn, scope){
2929             this.show({
2930                 title : title,
2931                 msg : msg,
2932                 buttons: this.YESNO,
2933                 fn: fn,
2934                 scope : scope,
2935                 modal : true
2936             });
2937             return this;
2938         },
2939
2940         /**
2941          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2942          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2943          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2944          * (could also be the top-right close button) and the text that was entered will be passed as the two
2945          * parameters to the callback.
2946          * @param {String} title The title bar text
2947          * @param {String} msg The message box body text
2948          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2949          * @param {Object} scope (optional) The scope of the callback function
2950          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2951          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2952          * @return {Roo.MessageBox} This message box
2953          */
2954         prompt : function(title, msg, fn, scope, multiline){
2955             this.show({
2956                 title : title,
2957                 msg : msg,
2958                 buttons: this.OKCANCEL,
2959                 fn: fn,
2960                 minWidth:250,
2961                 scope : scope,
2962                 prompt:true,
2963                 multiline: multiline,
2964                 modal : true
2965             });
2966             return this;
2967         },
2968
2969         /**
2970          * Button config that displays a single OK button
2971          * @type Object
2972          */
2973         OK : {ok:true},
2974         /**
2975          * Button config that displays Yes and No buttons
2976          * @type Object
2977          */
2978         YESNO : {yes:true, no:true},
2979         /**
2980          * Button config that displays OK and Cancel buttons
2981          * @type Object
2982          */
2983         OKCANCEL : {ok:true, cancel:true},
2984         /**
2985          * Button config that displays Yes, No and Cancel buttons
2986          * @type Object
2987          */
2988         YESNOCANCEL : {yes:true, no:true, cancel:true},
2989
2990         /**
2991          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2992          * @type Number
2993          */
2994         defaultTextHeight : 75,
2995         /**
2996          * The maximum width in pixels of the message box (defaults to 600)
2997          * @type Number
2998          */
2999         maxWidth : 600,
3000         /**
3001          * The minimum width in pixels of the message box (defaults to 100)
3002          * @type Number
3003          */
3004         minWidth : 100,
3005         /**
3006          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3007          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3008          * @type Number
3009          */
3010         minProgressWidth : 250,
3011         /**
3012          * An object containing the default button text strings that can be overriden for localized language support.
3013          * Supported properties are: ok, cancel, yes and no.
3014          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3015          * @type Object
3016          */
3017         buttonText : {
3018             ok : "OK",
3019             cancel : "Cancel",
3020             yes : "Yes",
3021             no : "No"
3022         }
3023     };
3024 }();
3025
3026 /**
3027  * Shorthand for {@link Roo.MessageBox}
3028  */
3029 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3030 Roo.Msg = Roo.Msg || Roo.MessageBox;
3031 /*
3032  * - LGPL
3033  *
3034  * navbar
3035  * 
3036  */
3037
3038 /**
3039  * @class Roo.bootstrap.Navbar
3040  * @extends Roo.bootstrap.Component
3041  * Bootstrap Navbar class
3042
3043  * @constructor
3044  * Create a new Navbar
3045  * @param {Object} config The config object
3046  */
3047
3048
3049 Roo.bootstrap.Navbar = function(config){
3050     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3051     
3052 };
3053
3054 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3055     
3056     
3057    
3058     // private
3059     navItems : false,
3060     loadMask : false,
3061     
3062     
3063     getAutoCreate : function(){
3064         
3065         
3066         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3067         
3068     },
3069     
3070     initEvents :function ()
3071     {
3072         //Roo.log(this.el.select('.navbar-toggle',true));
3073         this.el.select('.navbar-toggle',true).on('click', function() {
3074            // Roo.log('click');
3075             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3076         }, this);
3077         
3078         var mark = {
3079             tag: "div",
3080             cls:"x-dlg-mask"
3081         }
3082         
3083         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3084         
3085         var size = this.el.getSize();
3086         this.maskEl.setSize(size.width, size.height);
3087         this.maskEl.enableDisplayMode("block");
3088         this.maskEl.hide();
3089         
3090         if(this.loadMask){
3091             this.maskEl.show();
3092         }
3093     },
3094     
3095     
3096     getChildContainer : function()
3097     {
3098         if (this.el.select('.collapse').getCount()) {
3099             return this.el.select('.collapse',true).first();
3100         }
3101         
3102         return this.el;
3103     },
3104     
3105     mask : function()
3106     {
3107         this.maskEl.show();
3108     },
3109     
3110     unmask : function()
3111     {
3112         this.maskEl.hide();
3113     } 
3114     
3115     
3116     
3117     
3118 });
3119
3120
3121
3122  
3123
3124  /*
3125  * - LGPL
3126  *
3127  * navbar
3128  * 
3129  */
3130
3131 /**
3132  * @class Roo.bootstrap.NavSimplebar
3133  * @extends Roo.bootstrap.Navbar
3134  * Bootstrap Sidebar class
3135  *
3136  * @cfg {Boolean} inverse is inverted color
3137  * 
3138  * @cfg {String} type (nav | pills | tabs)
3139  * @cfg {Boolean} arrangement stacked | justified
3140  * @cfg {String} align (left | right) alignment
3141  * 
3142  * @cfg {Boolean} main (true|false) main nav bar? default false
3143  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3144  * 
3145  * @cfg {String} tag (header|footer|nav|div) default is nav 
3146
3147  * 
3148  * 
3149  * 
3150  * @constructor
3151  * Create a new Sidebar
3152  * @param {Object} config The config object
3153  */
3154
3155
3156 Roo.bootstrap.NavSimplebar = function(config){
3157     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3158 };
3159
3160 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3161     
3162     inverse: false,
3163     
3164     type: false,
3165     arrangement: '',
3166     align : false,
3167     
3168     
3169     
3170     main : false,
3171     
3172     
3173     tag : false,
3174     
3175     
3176     getAutoCreate : function(){
3177         
3178         
3179         var cfg = {
3180             tag : this.tag || 'div',
3181             cls : 'navbar'
3182         };
3183           
3184         
3185         cfg.cn = [
3186             {
3187                 cls: 'nav',
3188                 tag : 'ul'
3189             }
3190         ];
3191         
3192          
3193         this.type = this.type || 'nav';
3194         if (['tabs','pills'].indexOf(this.type)!==-1) {
3195             cfg.cn[0].cls += ' nav-' + this.type
3196         
3197         
3198         } else {
3199             if (this.type!=='nav') {
3200                 Roo.log('nav type must be nav/tabs/pills')
3201             }
3202             cfg.cn[0].cls += ' navbar-nav'
3203         }
3204         
3205         
3206         
3207         
3208         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3209             cfg.cn[0].cls += ' nav-' + this.arrangement;
3210         }
3211         
3212         
3213         if (this.align === 'right') {
3214             cfg.cn[0].cls += ' navbar-right';
3215         }
3216         
3217         if (this.inverse) {
3218             cfg.cls += ' navbar-inverse';
3219             
3220         }
3221         
3222         
3223         return cfg;
3224     
3225         
3226     }
3227     
3228     
3229     
3230 });
3231
3232
3233
3234  
3235
3236  
3237        /*
3238  * - LGPL
3239  *
3240  * navbar
3241  * 
3242  */
3243
3244 /**
3245  * @class Roo.bootstrap.NavHeaderbar
3246  * @extends Roo.bootstrap.NavSimplebar
3247  * Bootstrap Sidebar class
3248  *
3249  * @cfg {String} brand what is brand
3250  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3251  * @cfg {String} brand_href href of the brand
3252  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3253  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3254  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3255  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3256  * 
3257  * @constructor
3258  * Create a new Sidebar
3259  * @param {Object} config The config object
3260  */
3261
3262
3263 Roo.bootstrap.NavHeaderbar = function(config){
3264     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3265       
3266 };
3267
3268 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3269     
3270     position: '',
3271     brand: '',
3272     brand_href: false,
3273     srButton : true,
3274     autohide : false,
3275     desktopCenter : false,
3276    
3277     
3278     getAutoCreate : function(){
3279         
3280         var   cfg = {
3281             tag: this.nav || 'nav',
3282             cls: 'navbar',
3283             role: 'navigation',
3284             cn: []
3285         };
3286         
3287         var cn = cfg.cn;
3288         if (this.desktopCenter) {
3289             cn.push({cls : 'container', cn : []});
3290             cn = cn[0].cn;
3291         }
3292         
3293         if(this.srButton){
3294             cn.push({
3295                 tag: 'div',
3296                 cls: 'navbar-header',
3297                 cn: [
3298                     {
3299                         tag: 'button',
3300                         type: 'button',
3301                         cls: 'navbar-toggle',
3302                         'data-toggle': 'collapse',
3303                         cn: [
3304                             {
3305                                 tag: 'span',
3306                                 cls: 'sr-only',
3307                                 html: 'Toggle navigation'
3308                             },
3309                             {
3310                                 tag: 'span',
3311                                 cls: 'icon-bar'
3312                             },
3313                             {
3314                                 tag: 'span',
3315                                 cls: 'icon-bar'
3316                             },
3317                             {
3318                                 tag: 'span',
3319                                 cls: 'icon-bar'
3320                             }
3321                         ]
3322                     }
3323                 ]
3324             });
3325         }
3326         
3327         cn.push({
3328             tag: 'div',
3329             cls: 'collapse navbar-collapse',
3330             cn : []
3331         });
3332         
3333         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3334         
3335         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3336             cfg.cls += ' navbar-' + this.position;
3337             
3338             // tag can override this..
3339             
3340             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3341         }
3342         
3343         if (this.brand !== '') {
3344             cn[0].cn.push({
3345                 tag: 'a',
3346                 href: this.brand_href ? this.brand_href : '#',
3347                 cls: 'navbar-brand',
3348                 cn: [
3349                 this.brand
3350                 ]
3351             });
3352         }
3353         
3354         if(this.main){
3355             cfg.cls += ' main-nav';
3356         }
3357         
3358         
3359         return cfg;
3360
3361         
3362     },
3363     getHeaderChildContainer : function()
3364     {
3365         if (this.el.select('.navbar-header').getCount()) {
3366             return this.el.select('.navbar-header',true).first();
3367         }
3368         
3369         return this.getChildContainer();
3370     },
3371     
3372     
3373     initEvents : function()
3374     {
3375         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3376         
3377         if (this.autohide) {
3378             
3379             var prevScroll = 0;
3380             var ft = this.el;
3381             
3382             Roo.get(document).on('scroll',function(e) {
3383                 var ns = Roo.get(document).getScroll().top;
3384                 var os = prevScroll;
3385                 prevScroll = ns;
3386                 
3387                 if(ns > os){
3388                     ft.removeClass('slideDown');
3389                     ft.addClass('slideUp');
3390                     return;
3391                 }
3392                 ft.removeClass('slideUp');
3393                 ft.addClass('slideDown');
3394                  
3395               
3396           },this);
3397         }
3398     }    
3399           
3400       
3401     
3402     
3403 });
3404
3405
3406
3407  
3408
3409  /*
3410  * - LGPL
3411  *
3412  * navbar
3413  * 
3414  */
3415
3416 /**
3417  * @class Roo.bootstrap.NavSidebar
3418  * @extends Roo.bootstrap.Navbar
3419  * Bootstrap Sidebar class
3420  * 
3421  * @constructor
3422  * Create a new Sidebar
3423  * @param {Object} config The config object
3424  */
3425
3426
3427 Roo.bootstrap.NavSidebar = function(config){
3428     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3429 };
3430
3431 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3432     
3433     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3434     
3435     getAutoCreate : function(){
3436         
3437         
3438         return  {
3439             tag: 'div',
3440             cls: 'sidebar sidebar-nav'
3441         };
3442     
3443         
3444     }
3445     
3446     
3447     
3448 });
3449
3450
3451
3452  
3453
3454  /*
3455  * - LGPL
3456  *
3457  * nav group
3458  * 
3459  */
3460
3461 /**
3462  * @class Roo.bootstrap.NavGroup
3463  * @extends Roo.bootstrap.Component
3464  * Bootstrap NavGroup class
3465  * @cfg {String} align left | right
3466  * @cfg {Boolean} inverse false | true
3467  * @cfg {String} type (nav|pills|tab) default nav
3468  * @cfg {String} navId - reference Id for navbar.
3469
3470  * 
3471  * @constructor
3472  * Create a new nav group
3473  * @param {Object} config The config object
3474  */
3475
3476 Roo.bootstrap.NavGroup = function(config){
3477     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3478     this.navItems = [];
3479    
3480     Roo.bootstrap.NavGroup.register(this);
3481      this.addEvents({
3482         /**
3483              * @event changed
3484              * Fires when the active item changes
3485              * @param {Roo.bootstrap.NavGroup} this
3486              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3487              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3488          */
3489         'changed': true
3490      });
3491     
3492 };
3493
3494 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3495     
3496     align: '',
3497     inverse: false,
3498     form: false,
3499     type: 'nav',
3500     navId : '',
3501     // private
3502     
3503     navItems : false, 
3504     
3505     getAutoCreate : function()
3506     {
3507         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3508         
3509         cfg = {
3510             tag : 'ul',
3511             cls: 'nav' 
3512         }
3513         
3514         if (['tabs','pills'].indexOf(this.type)!==-1) {
3515             cfg.cls += ' nav-' + this.type
3516         } else {
3517             if (this.type!=='nav') {
3518                 Roo.log('nav type must be nav/tabs/pills')
3519             }
3520             cfg.cls += ' navbar-nav'
3521         }
3522         
3523         if (this.parent().sidebar) {
3524             cfg = {
3525                 tag: 'ul',
3526                 cls: 'dashboard-menu sidebar-menu'
3527             }
3528             
3529             return cfg;
3530         }
3531         
3532         if (this.form === true) {
3533             cfg = {
3534                 tag: 'form',
3535                 cls: 'navbar-form'
3536             }
3537             
3538             if (this.align === 'right') {
3539                 cfg.cls += ' navbar-right';
3540             } else {
3541                 cfg.cls += ' navbar-left';
3542             }
3543         }
3544         
3545         if (this.align === 'right') {
3546             cfg.cls += ' navbar-right';
3547         }
3548         
3549         if (this.inverse) {
3550             cfg.cls += ' navbar-inverse';
3551             
3552         }
3553         
3554         
3555         return cfg;
3556     },
3557     /**
3558     * sets the active Navigation item
3559     * @param {Roo.bootstrap.NavItem} the new current navitem
3560     */
3561     setActiveItem : function(item)
3562     {
3563         var prev = false;
3564         Roo.each(this.navItems, function(v){
3565             if (v == item) {
3566                 return ;
3567             }
3568             if (v.isActive()) {
3569                 v.setActive(false, true);
3570                 prev = v;
3571                 
3572             }
3573             
3574         });
3575
3576         item.setActive(true, true);
3577         this.fireEvent('changed', this, item, prev);
3578         
3579         
3580     },
3581     /**
3582     * gets the active Navigation item
3583     * @return {Roo.bootstrap.NavItem} the current navitem
3584     */
3585     getActive : function()
3586     {
3587         
3588         var prev = false;
3589         Roo.each(this.navItems, function(v){
3590             
3591             if (v.isActive()) {
3592                 prev = v;
3593                 
3594             }
3595             
3596         });
3597         return prev;
3598     },
3599     
3600     indexOfNav : function()
3601     {
3602         
3603         var prev = false;
3604         Roo.each(this.navItems, function(v,i){
3605             
3606             if (v.isActive()) {
3607                 prev = i;
3608                 
3609             }
3610             
3611         });
3612         return prev;
3613     },
3614     /**
3615     * adds a Navigation item
3616     * @param {Roo.bootstrap.NavItem} the navitem to add
3617     */
3618     addItem : function(cfg)
3619     {
3620         var cn = new Roo.bootstrap.NavItem(cfg);
3621         this.register(cn);
3622         cn.parentId = this.id;
3623         cn.onRender(this.el, null);
3624         return cn;
3625     },
3626     /**
3627     * register a Navigation item
3628     * @param {Roo.bootstrap.NavItem} the navitem to add
3629     */
3630     register : function(item)
3631     {
3632         this.navItems.push( item);
3633         item.navId = this.navId;
3634     
3635     },
3636     
3637     /**
3638     * clear all the Navigation item
3639     */
3640    
3641     clearAll : function()
3642     {
3643         this.navItems = [];
3644         this.el.dom.innerHTML = '';
3645     },
3646     
3647     getNavItem: function(tabId)
3648     {
3649         var ret = false;
3650         Roo.each(this.navItems, function(e) {
3651             if (e.tabId == tabId) {
3652                ret =  e;
3653                return false;
3654             }
3655             return true;
3656             
3657         });
3658         return ret;
3659     },
3660     
3661     setActiveNext : function()
3662     {
3663         var i = this.indexOfNav(this.getActive());
3664         if (i > this.navItems.length) {
3665             return;
3666         }
3667         this.setActiveItem(this.navItems[i+1]);
3668     },
3669     setActivePrev : function()
3670     {
3671         var i = this.indexOfNav(this.getActive());
3672         if (i  < 1) {
3673             return;
3674         }
3675         this.setActiveItem(this.navItems[i-1]);
3676     },
3677     clearWasActive : function(except) {
3678         Roo.each(this.navItems, function(e) {
3679             if (e.tabId != except.tabId && e.was_active) {
3680                e.was_active = false;
3681                return false;
3682             }
3683             return true;
3684             
3685         });
3686     },
3687     getWasActive : function ()
3688     {
3689         var r = false;
3690         Roo.each(this.navItems, function(e) {
3691             if (e.was_active) {
3692                r = e;
3693                return false;
3694             }
3695             return true;
3696             
3697         });
3698         return r;
3699     }
3700     
3701     
3702 });
3703
3704  
3705 Roo.apply(Roo.bootstrap.NavGroup, {
3706     
3707     groups: {},
3708      /**
3709     * register a Navigation Group
3710     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3711     */
3712     register : function(navgrp)
3713     {
3714         this.groups[navgrp.navId] = navgrp;
3715         
3716     },
3717     /**
3718     * fetch a Navigation Group based on the navigation ID
3719     * @param {string} the navgroup to add
3720     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3721     */
3722     get: function(navId) {
3723         if (typeof(this.groups[navId]) == 'undefined') {
3724             return false;
3725             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3726         }
3727         return this.groups[navId] ;
3728     }
3729     
3730     
3731     
3732 });
3733
3734  /*
3735  * - LGPL
3736  *
3737  * row
3738  * 
3739  */
3740
3741 /**
3742  * @class Roo.bootstrap.NavItem
3743  * @extends Roo.bootstrap.Component
3744  * Bootstrap Navbar.NavItem class
3745  * @cfg {String} href  link to
3746  * @cfg {String} html content of button
3747  * @cfg {String} badge text inside badge
3748  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3749  * @cfg {String} glyphicon name of glyphicon
3750  * @cfg {String} icon name of font awesome icon
3751  * @cfg {Boolean} active Is item active
3752  * @cfg {Boolean} disabled Is item disabled
3753  
3754  * @cfg {Boolean} preventDefault (true | false) default false
3755  * @cfg {String} tabId the tab that this item activates.
3756  * @cfg {String} tagtype (a|span) render as a href or span?
3757   
3758  * @constructor
3759  * Create a new Navbar Item
3760  * @param {Object} config The config object
3761  */
3762 Roo.bootstrap.NavItem = function(config){
3763     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3764     this.addEvents({
3765         // raw events
3766         /**
3767          * @event click
3768          * The raw click event for the entire grid.
3769          * @param {Roo.EventObject} e
3770          */
3771         "click" : true,
3772          /**
3773             * @event changed
3774             * Fires when the active item active state changes
3775             * @param {Roo.bootstrap.NavItem} this
3776             * @param {boolean} state the new state
3777              
3778          */
3779         'changed': true
3780     });
3781    
3782 };
3783
3784 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3785     
3786     href: false,
3787     html: '',
3788     badge: '',
3789     icon: false,
3790     glyphicon: false,
3791     active: false,
3792     preventDefault : false,
3793     tabId : false,
3794     tagtype : 'a',
3795     disabled : false,
3796     
3797     was_active : false,
3798     
3799     getAutoCreate : function(){
3800          
3801         var cfg = {
3802             tag: 'li',
3803             cls: 'nav-item'
3804             
3805         }
3806         if (this.active) {
3807             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3808         }
3809         if (this.disabled) {
3810             cfg.cls += ' disabled';
3811         }
3812         
3813         if (this.href || this.html || this.glyphicon || this.icon) {
3814             cfg.cn = [
3815                 {
3816                     tag: this.tagtype,
3817                     href : this.href || "#",
3818                     html: this.html || ''
3819                 }
3820             ];
3821             
3822             if (this.icon) {
3823                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3824             }
3825
3826             if(this.glyphicon) {
3827                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3828             }
3829             
3830             if (this.menu) {
3831                 
3832                 cfg.cn[0].html += " <span class='caret'></span>";
3833              
3834             }
3835             
3836             if (this.badge !== '') {
3837                  
3838                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3839             }
3840         }
3841         
3842         
3843         
3844         return cfg;
3845     },
3846     initEvents: function() 
3847     {
3848         if (typeof (this.menu) != 'undefined') {
3849             this.menu.parentType = this.xtype;
3850             this.menu.triggerEl = this.el;
3851             this.menu = this.addxtype(Roo.apply({}, this.menu));
3852         }
3853         
3854         this.el.select('a',true).on('click', this.onClick, this);
3855         
3856         if(this.tagtype == 'span'){
3857             this.el.select('span',true).on('click', this.onClick, this);
3858         }
3859        
3860         // at this point parent should be available..
3861         this.parent().register(this);
3862     },
3863     
3864     onClick : function(e)
3865     {
3866         if(this.preventDefault || this.href == '#'){
3867             e.preventDefault();
3868         }
3869         
3870         if (this.disabled) {
3871             return;
3872         }
3873         
3874         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3875         if (tg && tg.transition) {
3876             Roo.log("waiting for the transitionend");
3877             return;
3878         }
3879         
3880         Roo.log("fire event clicked");
3881         if(this.fireEvent('click', this, e) === false){
3882             return;
3883         };
3884         
3885         if(this.tagtype == 'span'){
3886             return;
3887         }
3888         
3889         var p = this.parent();
3890         if (['tabs','pills'].indexOf(p.type)!==-1) {
3891             if (typeof(p.setActiveItem) !== 'undefined') {
3892                 p.setActiveItem(this);
3893             }
3894         }
3895         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3896         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3897             // remove the collapsed menu expand...
3898             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3899         }
3900         
3901     },
3902     
3903     isActive: function () {
3904         return this.active
3905     },
3906     setActive : function(state, fire, is_was_active)
3907     {
3908         if (this.active && !state & this.navId) {
3909             this.was_active = true;
3910             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3911             if (nv) {
3912                 nv.clearWasActive(this);
3913             }
3914             
3915         }
3916         this.active = state;
3917         
3918         if (!state ) {
3919             this.el.removeClass('active');
3920         } else if (!this.el.hasClass('active')) {
3921             this.el.addClass('active');
3922         }
3923         if (fire) {
3924             this.fireEvent('changed', this, state);
3925         }
3926         
3927         // show a panel if it's registered and related..
3928         
3929         if (!this.navId || !this.tabId || !state || is_was_active) {
3930             return;
3931         }
3932         
3933         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3934         if (!tg) {
3935             return;
3936         }
3937         var pan = tg.getPanelByName(this.tabId);
3938         if (!pan) {
3939             return;
3940         }
3941         // if we can not flip to new panel - go back to old nav highlight..
3942         if (false == tg.showPanel(pan)) {
3943             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3944             if (nv) {
3945                 var onav = nv.getWasActive();
3946                 if (onav) {
3947                     onav.setActive(true, false, true);
3948                 }
3949             }
3950             
3951         }
3952         
3953         
3954         
3955     },
3956      // this should not be here...
3957     setDisabled : function(state)
3958     {
3959         this.disabled = state;
3960         if (!state ) {
3961             this.el.removeClass('disabled');
3962         } else if (!this.el.hasClass('disabled')) {
3963             this.el.addClass('disabled');
3964         }
3965         
3966     },
3967     
3968     /**
3969      * Fetch the element to display the tooltip on.
3970      * @return {Roo.Element} defaults to this.el
3971      */
3972     tooltipEl : function()
3973     {
3974         return this.el.select('' + this.tagtype + '', true).first();
3975     }
3976 });
3977  
3978
3979  /*
3980  * - LGPL
3981  *
3982  * sidebar item
3983  *
3984  *  li
3985  *    <span> icon </span>
3986  *    <span> text </span>
3987  *    <span>badge </span>
3988  */
3989
3990 /**
3991  * @class Roo.bootstrap.NavSidebarItem
3992  * @extends Roo.bootstrap.NavItem
3993  * Bootstrap Navbar.NavSidebarItem class
3994  * @constructor
3995  * Create a new Navbar Button
3996  * @param {Object} config The config object
3997  */
3998 Roo.bootstrap.NavSidebarItem = function(config){
3999     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4000     this.addEvents({
4001         // raw events
4002         /**
4003          * @event click
4004          * The raw click event for the entire grid.
4005          * @param {Roo.EventObject} e
4006          */
4007         "click" : true,
4008          /**
4009             * @event changed
4010             * Fires when the active item active state changes
4011             * @param {Roo.bootstrap.NavSidebarItem} this
4012             * @param {boolean} state the new state
4013              
4014          */
4015         'changed': true
4016     });
4017    
4018 };
4019
4020 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4021     
4022     
4023     getAutoCreate : function(){
4024         
4025         
4026         var a = {
4027                 tag: 'a',
4028                 href : this.href || '#',
4029                 cls: '',
4030                 html : '',
4031                 cn : []
4032         };
4033         var cfg = {
4034             tag: 'li',
4035             cls: '',
4036             cn: [ a ]
4037         }
4038         var span = {
4039             tag: 'span',
4040             html : this.html || ''
4041         }
4042         
4043         
4044         if (this.active) {
4045             cfg.cls += ' active';
4046         }
4047         
4048         // left icon..
4049         if (this.glyphicon || this.icon) {
4050             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4051             a.cn.push({ tag : 'i', cls : c }) ;
4052         }
4053         // html..
4054         a.cn.push(span);
4055         // then badge..
4056         if (this.badge !== '') {
4057             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4058         }
4059         // fi
4060         if (this.menu) {
4061             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4062             a.cls += 'dropdown-toggle treeview' ;
4063             
4064         }
4065         
4066         
4067         
4068         return cfg;
4069          
4070            
4071     }
4072    
4073      
4074  
4075 });
4076  
4077
4078  /*
4079  * - LGPL
4080  *
4081  * row
4082  * 
4083  */
4084
4085 /**
4086  * @class Roo.bootstrap.Row
4087  * @extends Roo.bootstrap.Component
4088  * Bootstrap Row class (contains columns...)
4089  * 
4090  * @constructor
4091  * Create a new Row
4092  * @param {Object} config The config object
4093  */
4094
4095 Roo.bootstrap.Row = function(config){
4096     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4097 };
4098
4099 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4100     
4101     getAutoCreate : function(){
4102        return {
4103             cls: 'row clearfix'
4104        };
4105     }
4106     
4107     
4108 });
4109
4110  
4111
4112  /*
4113  * - LGPL
4114  *
4115  * element
4116  * 
4117  */
4118
4119 /**
4120  * @class Roo.bootstrap.Element
4121  * @extends Roo.bootstrap.Component
4122  * Bootstrap Element class
4123  * @cfg {String} html contents of the element
4124  * @cfg {String} tag tag of the element
4125  * @cfg {String} cls class of the element
4126  * 
4127  * @constructor
4128  * Create a new Element
4129  * @param {Object} config The config object
4130  */
4131
4132 Roo.bootstrap.Element = function(config){
4133     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4134 };
4135
4136 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4137     
4138     tag: 'div',
4139     cls: '',
4140     html: '',
4141      
4142     
4143     getAutoCreate : function(){
4144         
4145         var cfg = {
4146             tag: this.tag,
4147             cls: this.cls,
4148             html: this.html
4149         }
4150         
4151         
4152         
4153         return cfg;
4154     }
4155    
4156 });
4157
4158  
4159
4160  /*
4161  * - LGPL
4162  *
4163  * pagination
4164  * 
4165  */
4166
4167 /**
4168  * @class Roo.bootstrap.Pagination
4169  * @extends Roo.bootstrap.Component
4170  * Bootstrap Pagination class
4171  * @cfg {String} size xs | sm | md | lg
4172  * @cfg {Boolean} inverse false | true
4173  * 
4174  * @constructor
4175  * Create a new Pagination
4176  * @param {Object} config The config object
4177  */
4178
4179 Roo.bootstrap.Pagination = function(config){
4180     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4181 };
4182
4183 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4184     
4185     cls: false,
4186     size: false,
4187     inverse: false,
4188     
4189     getAutoCreate : function(){
4190         var cfg = {
4191             tag: 'ul',
4192                 cls: 'pagination'
4193         };
4194         if (this.inverse) {
4195             cfg.cls += ' inverse';
4196         }
4197         if (this.html) {
4198             cfg.html=this.html;
4199         }
4200         if (this.cls) {
4201             cfg.cls += " " + this.cls;
4202         }
4203         return cfg;
4204     }
4205    
4206 });
4207
4208  
4209
4210  /*
4211  * - LGPL
4212  *
4213  * Pagination item
4214  * 
4215  */
4216
4217
4218 /**
4219  * @class Roo.bootstrap.PaginationItem
4220  * @extends Roo.bootstrap.Component
4221  * Bootstrap PaginationItem class
4222  * @cfg {String} html text
4223  * @cfg {String} href the link
4224  * @cfg {Boolean} preventDefault (true | false) default true
4225  * @cfg {Boolean} active (true | false) default false
4226  * @cfg {Boolean} disabled default false
4227  * 
4228  * 
4229  * @constructor
4230  * Create a new PaginationItem
4231  * @param {Object} config The config object
4232  */
4233
4234
4235 Roo.bootstrap.PaginationItem = function(config){
4236     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4237     this.addEvents({
4238         // raw events
4239         /**
4240          * @event click
4241          * The raw click event for the entire grid.
4242          * @param {Roo.EventObject} e
4243          */
4244         "click" : true
4245     });
4246 };
4247
4248 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4249     
4250     href : false,
4251     html : false,
4252     preventDefault: true,
4253     active : false,
4254     cls : false,
4255     disabled: false,
4256     
4257     getAutoCreate : function(){
4258         var cfg= {
4259             tag: 'li',
4260             cn: [
4261                 {
4262                     tag : 'a',
4263                     href : this.href ? this.href : '#',
4264                     html : this.html ? this.html : ''
4265                 }
4266             ]
4267         };
4268         
4269         if(this.cls){
4270             cfg.cls = this.cls;
4271         }
4272         
4273         if(this.disabled){
4274             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4275         }
4276         
4277         if(this.active){
4278             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4279         }
4280         
4281         return cfg;
4282     },
4283     
4284     initEvents: function() {
4285         
4286         this.el.on('click', this.onClick, this);
4287         
4288     },
4289     onClick : function(e)
4290     {
4291         Roo.log('PaginationItem on click ');
4292         if(this.preventDefault){
4293             e.preventDefault();
4294         }
4295         
4296         if(this.disabled){
4297             return;
4298         }
4299         
4300         this.fireEvent('click', this, e);
4301     }
4302    
4303 });
4304
4305  
4306
4307  /*
4308  * - LGPL
4309  *
4310  * slider
4311  * 
4312  */
4313
4314
4315 /**
4316  * @class Roo.bootstrap.Slider
4317  * @extends Roo.bootstrap.Component
4318  * Bootstrap Slider class
4319  *    
4320  * @constructor
4321  * Create a new Slider
4322  * @param {Object} config The config object
4323  */
4324
4325 Roo.bootstrap.Slider = function(config){
4326     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4327 };
4328
4329 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4330     
4331     getAutoCreate : function(){
4332         
4333         var cfg = {
4334             tag: 'div',
4335             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4336             cn: [
4337                 {
4338                     tag: 'a',
4339                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4340                 }
4341             ]
4342         }
4343         
4344         return cfg;
4345     }
4346    
4347 });
4348
4349  /*
4350  * Based on:
4351  * Ext JS Library 1.1.1
4352  * Copyright(c) 2006-2007, Ext JS, LLC.
4353  *
4354  * Originally Released Under LGPL - original licence link has changed is not relivant.
4355  *
4356  * Fork - LGPL
4357  * <script type="text/javascript">
4358  */
4359  
4360
4361 /**
4362  * @class Roo.grid.ColumnModel
4363  * @extends Roo.util.Observable
4364  * This is the default implementation of a ColumnModel used by the Grid. It defines
4365  * the columns in the grid.
4366  * <br>Usage:<br>
4367  <pre><code>
4368  var colModel = new Roo.grid.ColumnModel([
4369         {header: "Ticker", width: 60, sortable: true, locked: true},
4370         {header: "Company Name", width: 150, sortable: true},
4371         {header: "Market Cap.", width: 100, sortable: true},
4372         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4373         {header: "Employees", width: 100, sortable: true, resizable: false}
4374  ]);
4375  </code></pre>
4376  * <p>
4377  
4378  * The config options listed for this class are options which may appear in each
4379  * individual column definition.
4380  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4381  * @constructor
4382  * @param {Object} config An Array of column config objects. See this class's
4383  * config objects for details.
4384 */
4385 Roo.grid.ColumnModel = function(config){
4386         /**
4387      * The config passed into the constructor
4388      */
4389     this.config = config;
4390     this.lookup = {};
4391
4392     // if no id, create one
4393     // if the column does not have a dataIndex mapping,
4394     // map it to the order it is in the config
4395     for(var i = 0, len = config.length; i < len; i++){
4396         var c = config[i];
4397         if(typeof c.dataIndex == "undefined"){
4398             c.dataIndex = i;
4399         }
4400         if(typeof c.renderer == "string"){
4401             c.renderer = Roo.util.Format[c.renderer];
4402         }
4403         if(typeof c.id == "undefined"){
4404             c.id = Roo.id();
4405         }
4406         if(c.editor && c.editor.xtype){
4407             c.editor  = Roo.factory(c.editor, Roo.grid);
4408         }
4409         if(c.editor && c.editor.isFormField){
4410             c.editor = new Roo.grid.GridEditor(c.editor);
4411         }
4412         this.lookup[c.id] = c;
4413     }
4414
4415     /**
4416      * The width of columns which have no width specified (defaults to 100)
4417      * @type Number
4418      */
4419     this.defaultWidth = 100;
4420
4421     /**
4422      * Default sortable of columns which have no sortable specified (defaults to false)
4423      * @type Boolean
4424      */
4425     this.defaultSortable = false;
4426
4427     this.addEvents({
4428         /**
4429              * @event widthchange
4430              * Fires when the width of a column changes.
4431              * @param {ColumnModel} this
4432              * @param {Number} columnIndex The column index
4433              * @param {Number} newWidth The new width
4434              */
4435             "widthchange": true,
4436         /**
4437              * @event headerchange
4438              * Fires when the text of a header changes.
4439              * @param {ColumnModel} this
4440              * @param {Number} columnIndex The column index
4441              * @param {Number} newText The new header text
4442              */
4443             "headerchange": true,
4444         /**
4445              * @event hiddenchange
4446              * Fires when a column is hidden or "unhidden".
4447              * @param {ColumnModel} this
4448              * @param {Number} columnIndex The column index
4449              * @param {Boolean} hidden true if hidden, false otherwise
4450              */
4451             "hiddenchange": true,
4452             /**
4453          * @event columnmoved
4454          * Fires when a column is moved.
4455          * @param {ColumnModel} this
4456          * @param {Number} oldIndex
4457          * @param {Number} newIndex
4458          */
4459         "columnmoved" : true,
4460         /**
4461          * @event columlockchange
4462          * Fires when a column's locked state is changed
4463          * @param {ColumnModel} this
4464          * @param {Number} colIndex
4465          * @param {Boolean} locked true if locked
4466          */
4467         "columnlockchange" : true
4468     });
4469     Roo.grid.ColumnModel.superclass.constructor.call(this);
4470 };
4471 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4472     /**
4473      * @cfg {String} header The header text to display in the Grid view.
4474      */
4475     /**
4476      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4477      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4478      * specified, the column's index is used as an index into the Record's data Array.
4479      */
4480     /**
4481      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4482      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4483      */
4484     /**
4485      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4486      * Defaults to the value of the {@link #defaultSortable} property.
4487      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4488      */
4489     /**
4490      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4491      */
4492     /**
4493      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4494      */
4495     /**
4496      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4497      */
4498     /**
4499      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4500      */
4501     /**
4502      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4503      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4504      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4505      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4506      */
4507        /**
4508      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4509      */
4510     /**
4511      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4512      */
4513     /**
4514      * @cfg {String} cursor (Optional)
4515      */
4516     /**
4517      * @cfg {String} tooltip (Optional)
4518      */
4519     /**
4520      * Returns the id of the column at the specified index.
4521      * @param {Number} index The column index
4522      * @return {String} the id
4523      */
4524     getColumnId : function(index){
4525         return this.config[index].id;
4526     },
4527
4528     /**
4529      * Returns the column for a specified id.
4530      * @param {String} id The column id
4531      * @return {Object} the column
4532      */
4533     getColumnById : function(id){
4534         return this.lookup[id];
4535     },
4536
4537     
4538     /**
4539      * Returns the column for a specified dataIndex.
4540      * @param {String} dataIndex The column dataIndex
4541      * @return {Object|Boolean} the column or false if not found
4542      */
4543     getColumnByDataIndex: function(dataIndex){
4544         var index = this.findColumnIndex(dataIndex);
4545         return index > -1 ? this.config[index] : false;
4546     },
4547     
4548     /**
4549      * Returns the index for a specified column id.
4550      * @param {String} id The column id
4551      * @return {Number} the index, or -1 if not found
4552      */
4553     getIndexById : function(id){
4554         for(var i = 0, len = this.config.length; i < len; i++){
4555             if(this.config[i].id == id){
4556                 return i;
4557             }
4558         }
4559         return -1;
4560     },
4561     
4562     /**
4563      * Returns the index for a specified column dataIndex.
4564      * @param {String} dataIndex The column dataIndex
4565      * @return {Number} the index, or -1 if not found
4566      */
4567     
4568     findColumnIndex : function(dataIndex){
4569         for(var i = 0, len = this.config.length; i < len; i++){
4570             if(this.config[i].dataIndex == dataIndex){
4571                 return i;
4572             }
4573         }
4574         return -1;
4575     },
4576     
4577     
4578     moveColumn : function(oldIndex, newIndex){
4579         var c = this.config[oldIndex];
4580         this.config.splice(oldIndex, 1);
4581         this.config.splice(newIndex, 0, c);
4582         this.dataMap = null;
4583         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4584     },
4585
4586     isLocked : function(colIndex){
4587         return this.config[colIndex].locked === true;
4588     },
4589
4590     setLocked : function(colIndex, value, suppressEvent){
4591         if(this.isLocked(colIndex) == value){
4592             return;
4593         }
4594         this.config[colIndex].locked = value;
4595         if(!suppressEvent){
4596             this.fireEvent("columnlockchange", this, colIndex, value);
4597         }
4598     },
4599
4600     getTotalLockedWidth : function(){
4601         var totalWidth = 0;
4602         for(var i = 0; i < this.config.length; i++){
4603             if(this.isLocked(i) && !this.isHidden(i)){
4604                 this.totalWidth += this.getColumnWidth(i);
4605             }
4606         }
4607         return totalWidth;
4608     },
4609
4610     getLockedCount : function(){
4611         for(var i = 0, len = this.config.length; i < len; i++){
4612             if(!this.isLocked(i)){
4613                 return i;
4614             }
4615         }
4616     },
4617
4618     /**
4619      * Returns the number of columns.
4620      * @return {Number}
4621      */
4622     getColumnCount : function(visibleOnly){
4623         if(visibleOnly === true){
4624             var c = 0;
4625             for(var i = 0, len = this.config.length; i < len; i++){
4626                 if(!this.isHidden(i)){
4627                     c++;
4628                 }
4629             }
4630             return c;
4631         }
4632         return this.config.length;
4633     },
4634
4635     /**
4636      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4637      * @param {Function} fn
4638      * @param {Object} scope (optional)
4639      * @return {Array} result
4640      */
4641     getColumnsBy : function(fn, scope){
4642         var r = [];
4643         for(var i = 0, len = this.config.length; i < len; i++){
4644             var c = this.config[i];
4645             if(fn.call(scope||this, c, i) === true){
4646                 r[r.length] = c;
4647             }
4648         }
4649         return r;
4650     },
4651
4652     /**
4653      * Returns true if the specified column is sortable.
4654      * @param {Number} col The column index
4655      * @return {Boolean}
4656      */
4657     isSortable : function(col){
4658         if(typeof this.config[col].sortable == "undefined"){
4659             return this.defaultSortable;
4660         }
4661         return this.config[col].sortable;
4662     },
4663
4664     /**
4665      * Returns the rendering (formatting) function defined for the column.
4666      * @param {Number} col The column index.
4667      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4668      */
4669     getRenderer : function(col){
4670         if(!this.config[col].renderer){
4671             return Roo.grid.ColumnModel.defaultRenderer;
4672         }
4673         return this.config[col].renderer;
4674     },
4675
4676     /**
4677      * Sets the rendering (formatting) function for a column.
4678      * @param {Number} col The column index
4679      * @param {Function} fn The function to use to process the cell's raw data
4680      * to return HTML markup for the grid view. The render function is called with
4681      * the following parameters:<ul>
4682      * <li>Data value.</li>
4683      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4684      * <li>css A CSS style string to apply to the table cell.</li>
4685      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4686      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4687      * <li>Row index</li>
4688      * <li>Column index</li>
4689      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4690      */
4691     setRenderer : function(col, fn){
4692         this.config[col].renderer = fn;
4693     },
4694
4695     /**
4696      * Returns the width for the specified column.
4697      * @param {Number} col The column index
4698      * @return {Number}
4699      */
4700     getColumnWidth : function(col){
4701         return this.config[col].width * 1 || this.defaultWidth;
4702     },
4703
4704     /**
4705      * Sets the width for a column.
4706      * @param {Number} col The column index
4707      * @param {Number} width The new width
4708      */
4709     setColumnWidth : function(col, width, suppressEvent){
4710         this.config[col].width = width;
4711         this.totalWidth = null;
4712         if(!suppressEvent){
4713              this.fireEvent("widthchange", this, col, width);
4714         }
4715     },
4716
4717     /**
4718      * Returns the total width of all columns.
4719      * @param {Boolean} includeHidden True to include hidden column widths
4720      * @return {Number}
4721      */
4722     getTotalWidth : function(includeHidden){
4723         if(!this.totalWidth){
4724             this.totalWidth = 0;
4725             for(var i = 0, len = this.config.length; i < len; i++){
4726                 if(includeHidden || !this.isHidden(i)){
4727                     this.totalWidth += this.getColumnWidth(i);
4728                 }
4729             }
4730         }
4731         return this.totalWidth;
4732     },
4733
4734     /**
4735      * Returns the header for the specified column.
4736      * @param {Number} col The column index
4737      * @return {String}
4738      */
4739     getColumnHeader : function(col){
4740         return this.config[col].header;
4741     },
4742
4743     /**
4744      * Sets the header for a column.
4745      * @param {Number} col The column index
4746      * @param {String} header The new header
4747      */
4748     setColumnHeader : function(col, header){
4749         this.config[col].header = header;
4750         this.fireEvent("headerchange", this, col, header);
4751     },
4752
4753     /**
4754      * Returns the tooltip for the specified column.
4755      * @param {Number} col The column index
4756      * @return {String}
4757      */
4758     getColumnTooltip : function(col){
4759             return this.config[col].tooltip;
4760     },
4761     /**
4762      * Sets the tooltip for a column.
4763      * @param {Number} col The column index
4764      * @param {String} tooltip The new tooltip
4765      */
4766     setColumnTooltip : function(col, tooltip){
4767             this.config[col].tooltip = tooltip;
4768     },
4769
4770     /**
4771      * Returns the dataIndex for the specified column.
4772      * @param {Number} col The column index
4773      * @return {Number}
4774      */
4775     getDataIndex : function(col){
4776         return this.config[col].dataIndex;
4777     },
4778
4779     /**
4780      * Sets the dataIndex for a column.
4781      * @param {Number} col The column index
4782      * @param {Number} dataIndex The new dataIndex
4783      */
4784     setDataIndex : function(col, dataIndex){
4785         this.config[col].dataIndex = dataIndex;
4786     },
4787
4788     
4789     
4790     /**
4791      * Returns true if the cell is editable.
4792      * @param {Number} colIndex The column index
4793      * @param {Number} rowIndex The row index
4794      * @return {Boolean}
4795      */
4796     isCellEditable : function(colIndex, rowIndex){
4797         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4798     },
4799
4800     /**
4801      * Returns the editor defined for the cell/column.
4802      * return false or null to disable editing.
4803      * @param {Number} colIndex The column index
4804      * @param {Number} rowIndex The row index
4805      * @return {Object}
4806      */
4807     getCellEditor : function(colIndex, rowIndex){
4808         return this.config[colIndex].editor;
4809     },
4810
4811     /**
4812      * Sets if a column is editable.
4813      * @param {Number} col The column index
4814      * @param {Boolean} editable True if the column is editable
4815      */
4816     setEditable : function(col, editable){
4817         this.config[col].editable = editable;
4818     },
4819
4820
4821     /**
4822      * Returns true if the column is hidden.
4823      * @param {Number} colIndex The column index
4824      * @return {Boolean}
4825      */
4826     isHidden : function(colIndex){
4827         return this.config[colIndex].hidden;
4828     },
4829
4830
4831     /**
4832      * Returns true if the column width cannot be changed
4833      */
4834     isFixed : function(colIndex){
4835         return this.config[colIndex].fixed;
4836     },
4837
4838     /**
4839      * Returns true if the column can be resized
4840      * @return {Boolean}
4841      */
4842     isResizable : function(colIndex){
4843         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4844     },
4845     /**
4846      * Sets if a column is hidden.
4847      * @param {Number} colIndex The column index
4848      * @param {Boolean} hidden True if the column is hidden
4849      */
4850     setHidden : function(colIndex, hidden){
4851         this.config[colIndex].hidden = hidden;
4852         this.totalWidth = null;
4853         this.fireEvent("hiddenchange", this, colIndex, hidden);
4854     },
4855
4856     /**
4857      * Sets the editor for a column.
4858      * @param {Number} col The column index
4859      * @param {Object} editor The editor object
4860      */
4861     setEditor : function(col, editor){
4862         this.config[col].editor = editor;
4863     }
4864 });
4865
4866 Roo.grid.ColumnModel.defaultRenderer = function(value){
4867         if(typeof value == "string" && value.length < 1){
4868             return "&#160;";
4869         }
4870         return value;
4871 };
4872
4873 // Alias for backwards compatibility
4874 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4875 /*
4876  * Based on:
4877  * Ext JS Library 1.1.1
4878  * Copyright(c) 2006-2007, Ext JS, LLC.
4879  *
4880  * Originally Released Under LGPL - original licence link has changed is not relivant.
4881  *
4882  * Fork - LGPL
4883  * <script type="text/javascript">
4884  */
4885  
4886 /**
4887  * @class Roo.LoadMask
4888  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4889  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4890  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4891  * element's UpdateManager load indicator and will be destroyed after the initial load.
4892  * @constructor
4893  * Create a new LoadMask
4894  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4895  * @param {Object} config The config object
4896  */
4897 Roo.LoadMask = function(el, config){
4898     this.el = Roo.get(el);
4899     Roo.apply(this, config);
4900     if(this.store){
4901         this.store.on('beforeload', this.onBeforeLoad, this);
4902         this.store.on('load', this.onLoad, this);
4903         this.store.on('loadexception', this.onLoadException, this);
4904         this.removeMask = false;
4905     }else{
4906         var um = this.el.getUpdateManager();
4907         um.showLoadIndicator = false; // disable the default indicator
4908         um.on('beforeupdate', this.onBeforeLoad, this);
4909         um.on('update', this.onLoad, this);
4910         um.on('failure', this.onLoad, this);
4911         this.removeMask = true;
4912     }
4913 };
4914
4915 Roo.LoadMask.prototype = {
4916     /**
4917      * @cfg {Boolean} removeMask
4918      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4919      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4920      */
4921     /**
4922      * @cfg {String} msg
4923      * The text to display in a centered loading message box (defaults to 'Loading...')
4924      */
4925     msg : 'Loading...',
4926     /**
4927      * @cfg {String} msgCls
4928      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4929      */
4930     msgCls : 'x-mask-loading',
4931
4932     /**
4933      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4934      * @type Boolean
4935      */
4936     disabled: false,
4937
4938     /**
4939      * Disables the mask to prevent it from being displayed
4940      */
4941     disable : function(){
4942        this.disabled = true;
4943     },
4944
4945     /**
4946      * Enables the mask so that it can be displayed
4947      */
4948     enable : function(){
4949         this.disabled = false;
4950     },
4951     
4952     onLoadException : function()
4953     {
4954         Roo.log(arguments);
4955         
4956         if (typeof(arguments[3]) != 'undefined') {
4957             Roo.MessageBox.alert("Error loading",arguments[3]);
4958         } 
4959         /*
4960         try {
4961             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4962                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4963             }   
4964         } catch(e) {
4965             
4966         }
4967         */
4968     
4969         
4970         
4971         this.el.unmask(this.removeMask);
4972     },
4973     // private
4974     onLoad : function()
4975     {
4976         this.el.unmask(this.removeMask);
4977     },
4978
4979     // private
4980     onBeforeLoad : function(){
4981         if(!this.disabled){
4982             this.el.mask(this.msg, this.msgCls);
4983         }
4984     },
4985
4986     // private
4987     destroy : function(){
4988         if(this.store){
4989             this.store.un('beforeload', this.onBeforeLoad, this);
4990             this.store.un('load', this.onLoad, this);
4991             this.store.un('loadexception', this.onLoadException, this);
4992         }else{
4993             var um = this.el.getUpdateManager();
4994             um.un('beforeupdate', this.onBeforeLoad, this);
4995             um.un('update', this.onLoad, this);
4996             um.un('failure', this.onLoad, this);
4997         }
4998     }
4999 };/*
5000  * - LGPL
5001  *
5002  * table
5003  * 
5004  */
5005
5006 /**
5007  * @class Roo.bootstrap.Table
5008  * @extends Roo.bootstrap.Component
5009  * Bootstrap Table class
5010  * @cfg {String} cls table class
5011  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5012  * @cfg {String} bgcolor Specifies the background color for a table
5013  * @cfg {Number} border Specifies whether the table cells should have borders or not
5014  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5015  * @cfg {Number} cellspacing Specifies the space between cells
5016  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5017  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5018  * @cfg {String} sortable Specifies that the table should be sortable
5019  * @cfg {String} summary Specifies a summary of the content of a table
5020  * @cfg {Number} width Specifies the width of a table
5021  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5022  * 
5023  * @cfg {boolean} striped Should the rows be alternative striped
5024  * @cfg {boolean} bordered Add borders to the table
5025  * @cfg {boolean} hover Add hover highlighting
5026  * @cfg {boolean} condensed Format condensed
5027  * @cfg {boolean} responsive Format condensed
5028  * @cfg {Boolean} loadMask (true|false) default false
5029  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5030  * @cfg {Boolean} thead (true|false) generate thead, default true
5031  * @cfg {Boolean} RowSelection (true|false) default false
5032  * @cfg {Boolean} CellSelection (true|false) default false
5033  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5034  
5035  * 
5036  * @constructor
5037  * Create a new Table
5038  * @param {Object} config The config object
5039  */
5040
5041 Roo.bootstrap.Table = function(config){
5042     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5043     
5044     if (this.sm) {
5045         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5046         this.sm = this.selModel;
5047         this.sm.xmodule = this.xmodule || false;
5048     }
5049     if (this.cm && typeof(this.cm.config) == 'undefined') {
5050         this.colModel = new Roo.grid.ColumnModel(this.cm);
5051         this.cm = this.colModel;
5052         this.cm.xmodule = this.xmodule || false;
5053     }
5054     if (this.store) {
5055         this.store= Roo.factory(this.store, Roo.data);
5056         this.ds = this.store;
5057         this.ds.xmodule = this.xmodule || false;
5058          
5059     }
5060     if (this.footer && this.store) {
5061         this.footer.dataSource = this.ds;
5062         this.footer = Roo.factory(this.footer);
5063     }
5064     
5065     /** @private */
5066     this.addEvents({
5067         /**
5068          * @event cellclick
5069          * Fires when a cell is clicked
5070          * @param {Roo.bootstrap.Table} this
5071          * @param {Roo.Element} el
5072          * @param {Number} rowIndex
5073          * @param {Number} columnIndex
5074          * @param {Roo.EventObject} e
5075          */
5076         "cellclick" : true,
5077         /**
5078          * @event celldblclick
5079          * Fires when a cell is double clicked
5080          * @param {Roo.bootstrap.Table} this
5081          * @param {Roo.Element} el
5082          * @param {Number} rowIndex
5083          * @param {Number} columnIndex
5084          * @param {Roo.EventObject} e
5085          */
5086         "celldblclick" : true,
5087         /**
5088          * @event rowclick
5089          * Fires when a row is clicked
5090          * @param {Roo.bootstrap.Table} this
5091          * @param {Roo.Element} el
5092          * @param {Number} rowIndex
5093          * @param {Roo.EventObject} e
5094          */
5095         "rowclick" : true,
5096         /**
5097          * @event rowdblclick
5098          * Fires when a row is double clicked
5099          * @param {Roo.bootstrap.Table} this
5100          * @param {Roo.Element} el
5101          * @param {Number} rowIndex
5102          * @param {Roo.EventObject} e
5103          */
5104         "rowdblclick" : true,
5105         /**
5106          * @event mouseover
5107          * Fires when a mouseover occur
5108          * @param {Roo.bootstrap.Table} this
5109          * @param {Roo.Element} el
5110          * @param {Number} rowIndex
5111          * @param {Number} columnIndex
5112          * @param {Roo.EventObject} e
5113          */
5114         "mouseover" : true,
5115         /**
5116          * @event mouseout
5117          * Fires when a mouseout occur
5118          * @param {Roo.bootstrap.Table} this
5119          * @param {Roo.Element} el
5120          * @param {Number} rowIndex
5121          * @param {Number} columnIndex
5122          * @param {Roo.EventObject} e
5123          */
5124         "mouseout" : true,
5125         /**
5126          * @event rowclass
5127          * Fires when a row is rendered, so you can change add a style to it.
5128          * @param {Roo.bootstrap.Table} this
5129          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5130          */
5131         'rowclass' : true,
5132           /**
5133          * @event rowsrendered
5134          * Fires when all the  rows have been rendered
5135          * @param {Roo.bootstrap.Table} this
5136          */
5137         'rowsrendered' : true
5138         
5139     });
5140 };
5141
5142 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5143     
5144     cls: false,
5145     align: false,
5146     bgcolor: false,
5147     border: false,
5148     cellpadding: false,
5149     cellspacing: false,
5150     frame: false,
5151     rules: false,
5152     sortable: false,
5153     summary: false,
5154     width: false,
5155     striped : false,
5156     bordered: false,
5157     hover:  false,
5158     condensed : false,
5159     responsive : false,
5160     sm : false,
5161     cm : false,
5162     store : false,
5163     loadMask : false,
5164     tfoot : true,
5165     thead : true,
5166     RowSelection : false,
5167     CellSelection : false,
5168     layout : false,
5169     
5170     // Roo.Element - the tbody
5171     mainBody: false, 
5172     
5173     getAutoCreate : function(){
5174         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5175         
5176         cfg = {
5177             tag: 'table',
5178             cls : 'table',
5179             cn : []
5180         }
5181             
5182         if (this.striped) {
5183             cfg.cls += ' table-striped';
5184         }
5185         
5186         if (this.hover) {
5187             cfg.cls += ' table-hover';
5188         }
5189         if (this.bordered) {
5190             cfg.cls += ' table-bordered';
5191         }
5192         if (this.condensed) {
5193             cfg.cls += ' table-condensed';
5194         }
5195         if (this.responsive) {
5196             cfg.cls += ' table-responsive';
5197         }
5198         
5199         if (this.cls) {
5200             cfg.cls+=  ' ' +this.cls;
5201         }
5202         
5203         // this lot should be simplifed...
5204         
5205         if (this.align) {
5206             cfg.align=this.align;
5207         }
5208         if (this.bgcolor) {
5209             cfg.bgcolor=this.bgcolor;
5210         }
5211         if (this.border) {
5212             cfg.border=this.border;
5213         }
5214         if (this.cellpadding) {
5215             cfg.cellpadding=this.cellpadding;
5216         }
5217         if (this.cellspacing) {
5218             cfg.cellspacing=this.cellspacing;
5219         }
5220         if (this.frame) {
5221             cfg.frame=this.frame;
5222         }
5223         if (this.rules) {
5224             cfg.rules=this.rules;
5225         }
5226         if (this.sortable) {
5227             cfg.sortable=this.sortable;
5228         }
5229         if (this.summary) {
5230             cfg.summary=this.summary;
5231         }
5232         if (this.width) {
5233             cfg.width=this.width;
5234         }
5235         if (this.layout) {
5236             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5237         }
5238         
5239         if(this.store || this.cm){
5240             if(this.thead){
5241                 cfg.cn.push(this.renderHeader());
5242             }
5243             
5244             cfg.cn.push(this.renderBody());
5245             
5246             if(this.tfoot){
5247                 cfg.cn.push(this.renderFooter());
5248             }
5249             
5250             cfg.cls+=  ' TableGrid';
5251         }
5252         
5253         return { cn : [ cfg ] };
5254     },
5255     
5256     initEvents : function()
5257     {   
5258         if(!this.store || !this.cm){
5259             return;
5260         }
5261         
5262         //Roo.log('initEvents with ds!!!!');
5263         
5264         this.mainBody = this.el.select('tbody', true).first();
5265         
5266         
5267         var _this = this;
5268         
5269         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5270             e.on('click', _this.sort, _this);
5271         });
5272         
5273         this.el.on("click", this.onClick, this);
5274         this.el.on("dblclick", this.onDblClick, this);
5275         
5276         // why is this done????? = it breaks dialogs??
5277         //this.parent().el.setStyle('position', 'relative');
5278         
5279         
5280         if (this.footer) {
5281             this.footer.parentId = this.id;
5282             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5283         }
5284         
5285         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5286         
5287         this.store.on('load', this.onLoad, this);
5288         this.store.on('beforeload', this.onBeforeLoad, this);
5289         this.store.on('update', this.onUpdate, this);
5290         this.store.on('add', this.onAdd, this);
5291         
5292     },
5293     
5294     onMouseover : function(e, el)
5295     {
5296         var cell = Roo.get(el);
5297         
5298         if(!cell){
5299             return;
5300         }
5301         
5302         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5303             cell = cell.findParent('td', false, true);
5304         }
5305         
5306         var row = cell.findParent('tr', false, true);
5307         var cellIndex = cell.dom.cellIndex;
5308         var rowIndex = row.dom.rowIndex - 1; // start from 0
5309         
5310         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5311         
5312     },
5313     
5314     onMouseout : function(e, el)
5315     {
5316         var cell = Roo.get(el);
5317         
5318         if(!cell){
5319             return;
5320         }
5321         
5322         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5323             cell = cell.findParent('td', false, true);
5324         }
5325         
5326         var row = cell.findParent('tr', false, true);
5327         var cellIndex = cell.dom.cellIndex;
5328         var rowIndex = row.dom.rowIndex - 1; // start from 0
5329         
5330         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5331         
5332     },
5333     
5334     onClick : function(e, el)
5335     {
5336         var cell = Roo.get(el);
5337         
5338         if(!cell || (!this.CellSelection && !this.RowSelection)){
5339             return;
5340         }
5341         
5342         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5343             cell = cell.findParent('td', false, true);
5344         }
5345         
5346         if(!cell || typeof(cell) == 'undefined'){
5347             return;
5348         }
5349         
5350         var row = cell.findParent('tr', false, true);
5351         
5352         if(!row || typeof(row) == 'undefined'){
5353             return;
5354         }
5355         
5356         var cellIndex = cell.dom.cellIndex;
5357         var rowIndex = this.getRowIndex(row);
5358         
5359         if(this.CellSelection){
5360             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5361         }
5362         
5363         if(this.RowSelection){
5364             this.fireEvent('rowclick', this, row, rowIndex, e);
5365         }
5366         
5367         
5368     },
5369     
5370     onDblClick : function(e,el)
5371     {
5372         var cell = Roo.get(el);
5373         
5374         if(!cell || (!this.CellSelection && !this.RowSelection)){
5375             return;
5376         }
5377         
5378         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5379             cell = cell.findParent('td', false, true);
5380         }
5381         
5382         if(!cell || typeof(cell) == 'undefined'){
5383             return;
5384         }
5385         
5386         var row = cell.findParent('tr', false, true);
5387         
5388         if(!row || typeof(row) == 'undefined'){
5389             return;
5390         }
5391         
5392         var cellIndex = cell.dom.cellIndex;
5393         var rowIndex = this.getRowIndex(row);
5394         
5395         if(this.CellSelection){
5396             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5397         }
5398         
5399         if(this.RowSelection){
5400             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5401         }
5402     },
5403     
5404     sort : function(e,el)
5405     {
5406         var col = Roo.get(el);
5407         
5408         if(!col.hasClass('sortable')){
5409             return;
5410         }
5411         
5412         var sort = col.attr('sort');
5413         var dir = 'ASC';
5414         
5415         if(col.hasClass('glyphicon-arrow-up')){
5416             dir = 'DESC';
5417         }
5418         
5419         this.store.sortInfo = {field : sort, direction : dir};
5420         
5421         if (this.footer) {
5422             Roo.log("calling footer first");
5423             this.footer.onClick('first');
5424         } else {
5425         
5426             this.store.load({ params : { start : 0 } });
5427         }
5428     },
5429     
5430     renderHeader : function()
5431     {
5432         var header = {
5433             tag: 'thead',
5434             cn : []
5435         };
5436         
5437         var cm = this.cm;
5438         
5439         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5440             
5441             var config = cm.config[i];
5442                     
5443             var c = {
5444                 tag: 'th',
5445                 style : '',
5446                 html: cm.getColumnHeader(i)
5447             };
5448             
5449             if(typeof(config.tooltip) != 'undefined'){
5450                 c.tooltip = config.tooltip;
5451             }
5452             
5453             if(typeof(config.colspan) != 'undefined'){
5454                 c.colspan = config.colspan;
5455             }
5456             
5457             if(typeof(config.hidden) != 'undefined' && config.hidden){
5458                 c.style += ' display:none;';
5459             }
5460             
5461             if(typeof(config.dataIndex) != 'undefined'){
5462                 c.sort = config.dataIndex;
5463             }
5464             
5465             if(typeof(config.sortable) != 'undefined' && config.sortable){
5466                 c.cls = 'sortable';
5467             }
5468             
5469             if(typeof(config.align) != 'undefined' && config.align.length){
5470                 c.style += ' text-align:' + config.align + ';';
5471             }
5472             
5473             if(typeof(config.width) != 'undefined'){
5474                 c.style += ' width:' + config.width + 'px;';
5475             }
5476             
5477             header.cn.push(c)
5478         }
5479         
5480         return header;
5481     },
5482     
5483     renderBody : function()
5484     {
5485         var body = {
5486             tag: 'tbody',
5487             cn : [
5488                 {
5489                     tag: 'tr',
5490                     cn : [
5491                         {
5492                             tag : 'td',
5493                             colspan :  this.cm.getColumnCount()
5494                         }
5495                     ]
5496                 }
5497             ]
5498         };
5499         
5500         return body;
5501     },
5502     
5503     renderFooter : function()
5504     {
5505         var footer = {
5506             tag: 'tfoot',
5507             cn : [
5508                 {
5509                     tag: 'tr',
5510                     cn : [
5511                         {
5512                             tag : 'td',
5513                             colspan :  this.cm.getColumnCount()
5514                         }
5515                     ]
5516                 }
5517             ]
5518         };
5519         
5520         return footer;
5521     },
5522     
5523     
5524     
5525     onLoad : function()
5526     {
5527         Roo.log('ds onload');
5528         this.clear();
5529         
5530         var _this = this;
5531         var cm = this.cm;
5532         var ds = this.store;
5533         
5534         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5535             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5536             
5537             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5538                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5539             }
5540             
5541             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5542                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5543             }
5544         });
5545         
5546         var tbody =  this.mainBody;
5547               
5548         if(ds.getCount() > 0){
5549             ds.data.each(function(d,rowIndex){
5550                 var row =  this.renderRow(cm, ds, rowIndex);
5551                 
5552                 tbody.createChild(row);
5553                 
5554                 var _this = this;
5555                 
5556                 if(row.cellObjects.length){
5557                     Roo.each(row.cellObjects, function(r){
5558                         _this.renderCellObject(r);
5559                     })
5560                 }
5561                 
5562             }, this);
5563         }
5564         
5565         Roo.each(this.el.select('tbody td', true).elements, function(e){
5566             e.on('mouseover', _this.onMouseover, _this);
5567         });
5568         
5569         Roo.each(this.el.select('tbody td', true).elements, function(e){
5570             e.on('mouseout', _this.onMouseout, _this);
5571         });
5572         this.fireEvent('rowsrendered', this);
5573         //if(this.loadMask){
5574         //    this.maskEl.hide();
5575         //}
5576     },
5577     
5578     
5579     onUpdate : function(ds,record)
5580     {
5581         this.refreshRow(record);
5582     },
5583     
5584     onRemove : function(ds, record, index, isUpdate){
5585         if(isUpdate !== true){
5586             this.fireEvent("beforerowremoved", this, index, record);
5587         }
5588         var bt = this.mainBody.dom;
5589         
5590         var rows = this.el.select('tbody > tr', true).elements;
5591         
5592         if(typeof(rows[index]) != 'undefined'){
5593             bt.removeChild(rows[index].dom);
5594         }
5595         
5596 //        if(bt.rows[index]){
5597 //            bt.removeChild(bt.rows[index]);
5598 //        }
5599         
5600         if(isUpdate !== true){
5601             //this.stripeRows(index);
5602             //this.syncRowHeights(index, index);
5603             //this.layout();
5604             this.fireEvent("rowremoved", this, index, record);
5605         }
5606     },
5607     
5608     onAdd : function(ds, records, rowIndex)
5609     {
5610         //Roo.log('on Add called');
5611         // - note this does not handle multiple adding very well..
5612         var bt = this.mainBody.dom;
5613         for (var i =0 ; i < records.length;i++) {
5614             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5615             //Roo.log(records[i]);
5616             //Roo.log(this.store.getAt(rowIndex+i));
5617             this.insertRow(this.store, rowIndex + i, false);
5618             return;
5619         }
5620         
5621     },
5622     
5623     
5624     refreshRow : function(record){
5625         var ds = this.store, index;
5626         if(typeof record == 'number'){
5627             index = record;
5628             record = ds.getAt(index);
5629         }else{
5630             index = ds.indexOf(record);
5631         }
5632         this.insertRow(ds, index, true);
5633         this.onRemove(ds, record, index+1, true);
5634         //this.syncRowHeights(index, index);
5635         //this.layout();
5636         this.fireEvent("rowupdated", this, index, record);
5637     },
5638     
5639     insertRow : function(dm, rowIndex, isUpdate){
5640         
5641         if(!isUpdate){
5642             this.fireEvent("beforerowsinserted", this, rowIndex);
5643         }
5644             //var s = this.getScrollState();
5645         var row = this.renderRow(this.cm, this.store, rowIndex);
5646         // insert before rowIndex..
5647         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5648         
5649         var _this = this;
5650                 
5651         if(row.cellObjects.length){
5652             Roo.each(row.cellObjects, function(r){
5653                 _this.renderCellObject(r);
5654             })
5655         }
5656             
5657         if(!isUpdate){
5658             this.fireEvent("rowsinserted", this, rowIndex);
5659             //this.syncRowHeights(firstRow, lastRow);
5660             //this.stripeRows(firstRow);
5661             //this.layout();
5662         }
5663         
5664     },
5665     
5666     
5667     getRowDom : function(rowIndex)
5668     {
5669         var rows = this.el.select('tbody > tr', true).elements;
5670         
5671         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5672         
5673     },
5674     // returns the object tree for a tr..
5675   
5676     
5677     renderRow : function(cm, ds, rowIndex) 
5678     {
5679         
5680         var d = ds.getAt(rowIndex);
5681         
5682         var row = {
5683             tag : 'tr',
5684             cn : []
5685         };
5686             
5687         var cellObjects = [];
5688         
5689         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5690             var config = cm.config[i];
5691             
5692             var renderer = cm.getRenderer(i);
5693             var value = '';
5694             var id = false;
5695             
5696             if(typeof(renderer) !== 'undefined'){
5697                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5698             }
5699             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5700             // and are rendered into the cells after the row is rendered - using the id for the element.
5701             
5702             if(typeof(value) === 'object'){
5703                 id = Roo.id();
5704                 cellObjects.push({
5705                     container : id,
5706                     cfg : value 
5707                 })
5708             }
5709             
5710             var rowcfg = {
5711                 record: d,
5712                 rowIndex : rowIndex,
5713                 colIndex : i,
5714                 rowClass : ''
5715             }
5716
5717             this.fireEvent('rowclass', this, rowcfg);
5718             
5719             var td = {
5720                 tag: 'td',
5721                 cls : rowcfg.rowClass,
5722                 style: '',
5723                 html: (typeof(value) === 'object') ? '' : value
5724             };
5725             
5726             if (id) {
5727                 td.id = id;
5728             }
5729             
5730             if(typeof(config.colspan) != 'undefined'){
5731                 td.colspan = config.colspan;
5732             }
5733             
5734             if(typeof(config.hidden) != 'undefined' && config.hidden){
5735                 td.style += ' display:none;';
5736             }
5737             
5738             if(typeof(config.align) != 'undefined' && config.align.length){
5739                 td.style += ' text-align:' + config.align + ';';
5740             }
5741             
5742             if(typeof(config.width) != 'undefined'){
5743                 td.style += ' width:' +  config.width + 'px;';
5744             }
5745             
5746             if(typeof(config.cursor) != 'undefined'){
5747                 td.style += ' cursor:' +  config.cursor + ';';
5748             }
5749              
5750             row.cn.push(td);
5751            
5752         }
5753         
5754         row.cellObjects = cellObjects;
5755         
5756         return row;
5757           
5758     },
5759     
5760     
5761     
5762     onBeforeLoad : function()
5763     {
5764         //Roo.log('ds onBeforeLoad');
5765         
5766         //this.clear();
5767         
5768         //if(this.loadMask){
5769         //    this.maskEl.show();
5770         //}
5771     },
5772      /**
5773      * Remove all rows
5774      */
5775     clear : function()
5776     {
5777         this.el.select('tbody', true).first().dom.innerHTML = '';
5778     },
5779     /**
5780      * Show or hide a row.
5781      * @param {Number} rowIndex to show or hide
5782      * @param {Boolean} state hide
5783      */
5784     setRowVisibility : function(rowIndex, state)
5785     {
5786         var bt = this.mainBody.dom;
5787         
5788         var rows = this.el.select('tbody > tr', true).elements;
5789         
5790         if(typeof(rows[rowIndex]) == 'undefined'){
5791             return;
5792         }
5793         rows[rowIndex].dom.style.display = state ? '' : 'none';
5794     },
5795     
5796     
5797     getSelectionModel : function(){
5798         if(!this.selModel){
5799             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5800         }
5801         return this.selModel;
5802     },
5803     /*
5804      * Render the Roo.bootstrap object from renderder
5805      */
5806     renderCellObject : function(r)
5807     {
5808         var _this = this;
5809         
5810         var t = r.cfg.render(r.container);
5811         
5812         if(r.cfg.cn){
5813             Roo.each(r.cfg.cn, function(c){
5814                 var child = {
5815                     container: t.getChildContainer(),
5816                     cfg: c
5817                 }
5818                 _this.renderCellObject(child);
5819             })
5820         }
5821     },
5822     
5823     getRowIndex : function(row)
5824     {
5825         var rowIndex = -1;
5826         
5827         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5828             if(el != row){
5829                 return;
5830             }
5831             
5832             rowIndex = index;
5833         });
5834         
5835         return rowIndex;
5836     }
5837    
5838 });
5839
5840  
5841
5842  /*
5843  * - LGPL
5844  *
5845  * table cell
5846  * 
5847  */
5848
5849 /**
5850  * @class Roo.bootstrap.TableCell
5851  * @extends Roo.bootstrap.Component
5852  * Bootstrap TableCell class
5853  * @cfg {String} html cell contain text
5854  * @cfg {String} cls cell class
5855  * @cfg {String} tag cell tag (td|th) default td
5856  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5857  * @cfg {String} align Aligns the content in a cell
5858  * @cfg {String} axis Categorizes cells
5859  * @cfg {String} bgcolor Specifies the background color of a cell
5860  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5861  * @cfg {Number} colspan Specifies the number of columns a cell should span
5862  * @cfg {String} headers Specifies one or more header cells a cell is related to
5863  * @cfg {Number} height Sets the height of a cell
5864  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5865  * @cfg {Number} rowspan Sets the number of rows a cell should span
5866  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5867  * @cfg {String} valign Vertical aligns the content in a cell
5868  * @cfg {Number} width Specifies the width of a cell
5869  * 
5870  * @constructor
5871  * Create a new TableCell
5872  * @param {Object} config The config object
5873  */
5874
5875 Roo.bootstrap.TableCell = function(config){
5876     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5877 };
5878
5879 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5880     
5881     html: false,
5882     cls: false,
5883     tag: false,
5884     abbr: false,
5885     align: false,
5886     axis: false,
5887     bgcolor: false,
5888     charoff: false,
5889     colspan: false,
5890     headers: false,
5891     height: false,
5892     nowrap: false,
5893     rowspan: false,
5894     scope: false,
5895     valign: false,
5896     width: false,
5897     
5898     
5899     getAutoCreate : function(){
5900         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5901         
5902         cfg = {
5903             tag: 'td'
5904         }
5905         
5906         if(this.tag){
5907             cfg.tag = this.tag;
5908         }
5909         
5910         if (this.html) {
5911             cfg.html=this.html
5912         }
5913         if (this.cls) {
5914             cfg.cls=this.cls
5915         }
5916         if (this.abbr) {
5917             cfg.abbr=this.abbr
5918         }
5919         if (this.align) {
5920             cfg.align=this.align
5921         }
5922         if (this.axis) {
5923             cfg.axis=this.axis
5924         }
5925         if (this.bgcolor) {
5926             cfg.bgcolor=this.bgcolor
5927         }
5928         if (this.charoff) {
5929             cfg.charoff=this.charoff
5930         }
5931         if (this.colspan) {
5932             cfg.colspan=this.colspan
5933         }
5934         if (this.headers) {
5935             cfg.headers=this.headers
5936         }
5937         if (this.height) {
5938             cfg.height=this.height
5939         }
5940         if (this.nowrap) {
5941             cfg.nowrap=this.nowrap
5942         }
5943         if (this.rowspan) {
5944             cfg.rowspan=this.rowspan
5945         }
5946         if (this.scope) {
5947             cfg.scope=this.scope
5948         }
5949         if (this.valign) {
5950             cfg.valign=this.valign
5951         }
5952         if (this.width) {
5953             cfg.width=this.width
5954         }
5955         
5956         
5957         return cfg;
5958     }
5959    
5960 });
5961
5962  
5963
5964  /*
5965  * - LGPL
5966  *
5967  * table row
5968  * 
5969  */
5970
5971 /**
5972  * @class Roo.bootstrap.TableRow
5973  * @extends Roo.bootstrap.Component
5974  * Bootstrap TableRow class
5975  * @cfg {String} cls row class
5976  * @cfg {String} align Aligns the content in a table row
5977  * @cfg {String} bgcolor Specifies a background color for a table row
5978  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5979  * @cfg {String} valign Vertical aligns the content in a table row
5980  * 
5981  * @constructor
5982  * Create a new TableRow
5983  * @param {Object} config The config object
5984  */
5985
5986 Roo.bootstrap.TableRow = function(config){
5987     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5988 };
5989
5990 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5991     
5992     cls: false,
5993     align: false,
5994     bgcolor: false,
5995     charoff: false,
5996     valign: false,
5997     
5998     getAutoCreate : function(){
5999         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6000         
6001         cfg = {
6002             tag: 'tr'
6003         }
6004             
6005         if(this.cls){
6006             cfg.cls = this.cls;
6007         }
6008         if(this.align){
6009             cfg.align = this.align;
6010         }
6011         if(this.bgcolor){
6012             cfg.bgcolor = this.bgcolor;
6013         }
6014         if(this.charoff){
6015             cfg.charoff = this.charoff;
6016         }
6017         if(this.valign){
6018             cfg.valign = this.valign;
6019         }
6020         
6021         return cfg;
6022     }
6023    
6024 });
6025
6026  
6027
6028  /*
6029  * - LGPL
6030  *
6031  * table body
6032  * 
6033  */
6034
6035 /**
6036  * @class Roo.bootstrap.TableBody
6037  * @extends Roo.bootstrap.Component
6038  * Bootstrap TableBody class
6039  * @cfg {String} cls element class
6040  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6041  * @cfg {String} align Aligns the content inside the element
6042  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6043  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6044  * 
6045  * @constructor
6046  * Create a new TableBody
6047  * @param {Object} config The config object
6048  */
6049
6050 Roo.bootstrap.TableBody = function(config){
6051     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6052 };
6053
6054 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
6055     
6056     cls: false,
6057     tag: false,
6058     align: false,
6059     charoff: false,
6060     valign: false,
6061     
6062     getAutoCreate : function(){
6063         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6064         
6065         cfg = {
6066             tag: 'tbody'
6067         }
6068             
6069         if (this.cls) {
6070             cfg.cls=this.cls
6071         }
6072         if(this.tag){
6073             cfg.tag = this.tag;
6074         }
6075         
6076         if(this.align){
6077             cfg.align = this.align;
6078         }
6079         if(this.charoff){
6080             cfg.charoff = this.charoff;
6081         }
6082         if(this.valign){
6083             cfg.valign = this.valign;
6084         }
6085         
6086         return cfg;
6087     }
6088     
6089     
6090 //    initEvents : function()
6091 //    {
6092 //        
6093 //        if(!this.store){
6094 //            return;
6095 //        }
6096 //        
6097 //        this.store = Roo.factory(this.store, Roo.data);
6098 //        this.store.on('load', this.onLoad, this);
6099 //        
6100 //        this.store.load();
6101 //        
6102 //    },
6103 //    
6104 //    onLoad: function () 
6105 //    {   
6106 //        this.fireEvent('load', this);
6107 //    }
6108 //    
6109 //   
6110 });
6111
6112  
6113
6114  /*
6115  * Based on:
6116  * Ext JS Library 1.1.1
6117  * Copyright(c) 2006-2007, Ext JS, LLC.
6118  *
6119  * Originally Released Under LGPL - original licence link has changed is not relivant.
6120  *
6121  * Fork - LGPL
6122  * <script type="text/javascript">
6123  */
6124
6125 // as we use this in bootstrap.
6126 Roo.namespace('Roo.form');
6127  /**
6128  * @class Roo.form.Action
6129  * Internal Class used to handle form actions
6130  * @constructor
6131  * @param {Roo.form.BasicForm} el The form element or its id
6132  * @param {Object} config Configuration options
6133  */
6134
6135  
6136  
6137 // define the action interface
6138 Roo.form.Action = function(form, options){
6139     this.form = form;
6140     this.options = options || {};
6141 };
6142 /**
6143  * Client Validation Failed
6144  * @const 
6145  */
6146 Roo.form.Action.CLIENT_INVALID = 'client';
6147 /**
6148  * Server Validation Failed
6149  * @const 
6150  */
6151 Roo.form.Action.SERVER_INVALID = 'server';
6152  /**
6153  * Connect to Server Failed
6154  * @const 
6155  */
6156 Roo.form.Action.CONNECT_FAILURE = 'connect';
6157 /**
6158  * Reading Data from Server Failed
6159  * @const 
6160  */
6161 Roo.form.Action.LOAD_FAILURE = 'load';
6162
6163 Roo.form.Action.prototype = {
6164     type : 'default',
6165     failureType : undefined,
6166     response : undefined,
6167     result : undefined,
6168
6169     // interface method
6170     run : function(options){
6171
6172     },
6173
6174     // interface method
6175     success : function(response){
6176
6177     },
6178
6179     // interface method
6180     handleResponse : function(response){
6181
6182     },
6183
6184     // default connection failure
6185     failure : function(response){
6186         
6187         this.response = response;
6188         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6189         this.form.afterAction(this, false);
6190     },
6191
6192     processResponse : function(response){
6193         this.response = response;
6194         if(!response.responseText){
6195             return true;
6196         }
6197         this.result = this.handleResponse(response);
6198         return this.result;
6199     },
6200
6201     // utility functions used internally
6202     getUrl : function(appendParams){
6203         var url = this.options.url || this.form.url || this.form.el.dom.action;
6204         if(appendParams){
6205             var p = this.getParams();
6206             if(p){
6207                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6208             }
6209         }
6210         return url;
6211     },
6212
6213     getMethod : function(){
6214         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6215     },
6216
6217     getParams : function(){
6218         var bp = this.form.baseParams;
6219         var p = this.options.params;
6220         if(p){
6221             if(typeof p == "object"){
6222                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6223             }else if(typeof p == 'string' && bp){
6224                 p += '&' + Roo.urlEncode(bp);
6225             }
6226         }else if(bp){
6227             p = Roo.urlEncode(bp);
6228         }
6229         return p;
6230     },
6231
6232     createCallback : function(){
6233         return {
6234             success: this.success,
6235             failure: this.failure,
6236             scope: this,
6237             timeout: (this.form.timeout*1000),
6238             upload: this.form.fileUpload ? this.success : undefined
6239         };
6240     }
6241 };
6242
6243 Roo.form.Action.Submit = function(form, options){
6244     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6245 };
6246
6247 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6248     type : 'submit',
6249
6250     haveProgress : false,
6251     uploadComplete : false,
6252     
6253     // uploadProgress indicator.
6254     uploadProgress : function()
6255     {
6256         if (!this.form.progressUrl) {
6257             return;
6258         }
6259         
6260         if (!this.haveProgress) {
6261             Roo.MessageBox.progress("Uploading", "Uploading");
6262         }
6263         if (this.uploadComplete) {
6264            Roo.MessageBox.hide();
6265            return;
6266         }
6267         
6268         this.haveProgress = true;
6269    
6270         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6271         
6272         var c = new Roo.data.Connection();
6273         c.request({
6274             url : this.form.progressUrl,
6275             params: {
6276                 id : uid
6277             },
6278             method: 'GET',
6279             success : function(req){
6280                //console.log(data);
6281                 var rdata = false;
6282                 var edata;
6283                 try  {
6284                    rdata = Roo.decode(req.responseText)
6285                 } catch (e) {
6286                     Roo.log("Invalid data from server..");
6287                     Roo.log(edata);
6288                     return;
6289                 }
6290                 if (!rdata || !rdata.success) {
6291                     Roo.log(rdata);
6292                     Roo.MessageBox.alert(Roo.encode(rdata));
6293                     return;
6294                 }
6295                 var data = rdata.data;
6296                 
6297                 if (this.uploadComplete) {
6298                    Roo.MessageBox.hide();
6299                    return;
6300                 }
6301                    
6302                 if (data){
6303                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6304                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6305                     );
6306                 }
6307                 this.uploadProgress.defer(2000,this);
6308             },
6309        
6310             failure: function(data) {
6311                 Roo.log('progress url failed ');
6312                 Roo.log(data);
6313             },
6314             scope : this
6315         });
6316            
6317     },
6318     
6319     
6320     run : function()
6321     {
6322         // run get Values on the form, so it syncs any secondary forms.
6323         this.form.getValues();
6324         
6325         var o = this.options;
6326         var method = this.getMethod();
6327         var isPost = method == 'POST';
6328         if(o.clientValidation === false || this.form.isValid()){
6329             
6330             if (this.form.progressUrl) {
6331                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6332                     (new Date() * 1) + '' + Math.random());
6333                     
6334             } 
6335             
6336             
6337             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6338                 form:this.form.el.dom,
6339                 url:this.getUrl(!isPost),
6340                 method: method,
6341                 params:isPost ? this.getParams() : null,
6342                 isUpload: this.form.fileUpload
6343             }));
6344             
6345             this.uploadProgress();
6346
6347         }else if (o.clientValidation !== false){ // client validation failed
6348             this.failureType = Roo.form.Action.CLIENT_INVALID;
6349             this.form.afterAction(this, false);
6350         }
6351     },
6352
6353     success : function(response)
6354     {
6355         this.uploadComplete= true;
6356         if (this.haveProgress) {
6357             Roo.MessageBox.hide();
6358         }
6359         
6360         
6361         var result = this.processResponse(response);
6362         if(result === true || result.success){
6363             this.form.afterAction(this, true);
6364             return;
6365         }
6366         if(result.errors){
6367             this.form.markInvalid(result.errors);
6368             this.failureType = Roo.form.Action.SERVER_INVALID;
6369         }
6370         this.form.afterAction(this, false);
6371     },
6372     failure : function(response)
6373     {
6374         this.uploadComplete= true;
6375         if (this.haveProgress) {
6376             Roo.MessageBox.hide();
6377         }
6378         
6379         this.response = response;
6380         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6381         this.form.afterAction(this, false);
6382     },
6383     
6384     handleResponse : function(response){
6385         if(this.form.errorReader){
6386             var rs = this.form.errorReader.read(response);
6387             var errors = [];
6388             if(rs.records){
6389                 for(var i = 0, len = rs.records.length; i < len; i++) {
6390                     var r = rs.records[i];
6391                     errors[i] = r.data;
6392                 }
6393             }
6394             if(errors.length < 1){
6395                 errors = null;
6396             }
6397             return {
6398                 success : rs.success,
6399                 errors : errors
6400             };
6401         }
6402         var ret = false;
6403         try {
6404             ret = Roo.decode(response.responseText);
6405         } catch (e) {
6406             ret = {
6407                 success: false,
6408                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6409                 errors : []
6410             };
6411         }
6412         return ret;
6413         
6414     }
6415 });
6416
6417
6418 Roo.form.Action.Load = function(form, options){
6419     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6420     this.reader = this.form.reader;
6421 };
6422
6423 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6424     type : 'load',
6425
6426     run : function(){
6427         
6428         Roo.Ajax.request(Roo.apply(
6429                 this.createCallback(), {
6430                     method:this.getMethod(),
6431                     url:this.getUrl(false),
6432                     params:this.getParams()
6433         }));
6434     },
6435
6436     success : function(response){
6437         
6438         var result = this.processResponse(response);
6439         if(result === true || !result.success || !result.data){
6440             this.failureType = Roo.form.Action.LOAD_FAILURE;
6441             this.form.afterAction(this, false);
6442             return;
6443         }
6444         this.form.clearInvalid();
6445         this.form.setValues(result.data);
6446         this.form.afterAction(this, true);
6447     },
6448
6449     handleResponse : function(response){
6450         if(this.form.reader){
6451             var rs = this.form.reader.read(response);
6452             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6453             return {
6454                 success : rs.success,
6455                 data : data
6456             };
6457         }
6458         return Roo.decode(response.responseText);
6459     }
6460 });
6461
6462 Roo.form.Action.ACTION_TYPES = {
6463     'load' : Roo.form.Action.Load,
6464     'submit' : Roo.form.Action.Submit
6465 };/*
6466  * - LGPL
6467  *
6468  * form
6469  * 
6470  */
6471
6472 /**
6473  * @class Roo.bootstrap.Form
6474  * @extends Roo.bootstrap.Component
6475  * Bootstrap Form class
6476  * @cfg {String} method  GET | POST (default POST)
6477  * @cfg {String} labelAlign top | left (default top)
6478  * @cfg {String} align left  | right - for navbars
6479  * @cfg {Boolean} loadMask load mask when submit (default true)
6480
6481  * 
6482  * @constructor
6483  * Create a new Form
6484  * @param {Object} config The config object
6485  */
6486
6487
6488 Roo.bootstrap.Form = function(config){
6489     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6490     this.addEvents({
6491         /**
6492          * @event clientvalidation
6493          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6494          * @param {Form} this
6495          * @param {Boolean} valid true if the form has passed client-side validation
6496          */
6497         clientvalidation: true,
6498         /**
6499          * @event beforeaction
6500          * Fires before any action is performed. Return false to cancel the action.
6501          * @param {Form} this
6502          * @param {Action} action The action to be performed
6503          */
6504         beforeaction: true,
6505         /**
6506          * @event actionfailed
6507          * Fires when an action fails.
6508          * @param {Form} this
6509          * @param {Action} action The action that failed
6510          */
6511         actionfailed : true,
6512         /**
6513          * @event actioncomplete
6514          * Fires when an action is completed.
6515          * @param {Form} this
6516          * @param {Action} action The action that completed
6517          */
6518         actioncomplete : true
6519     });
6520     
6521 };
6522
6523 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6524       
6525      /**
6526      * @cfg {String} method
6527      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6528      */
6529     method : 'POST',
6530     /**
6531      * @cfg {String} url
6532      * The URL to use for form actions if one isn't supplied in the action options.
6533      */
6534     /**
6535      * @cfg {Boolean} fileUpload
6536      * Set to true if this form is a file upload.
6537      */
6538      
6539     /**
6540      * @cfg {Object} baseParams
6541      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6542      */
6543       
6544     /**
6545      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6546      */
6547     timeout: 30,
6548     /**
6549      * @cfg {Sting} align (left|right) for navbar forms
6550      */
6551     align : 'left',
6552
6553     // private
6554     activeAction : null,
6555  
6556     /**
6557      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6558      * element by passing it or its id or mask the form itself by passing in true.
6559      * @type Mixed
6560      */
6561     waitMsgTarget : false,
6562     
6563     loadMask : true,
6564     
6565     getAutoCreate : function(){
6566         
6567         var cfg = {
6568             tag: 'form',
6569             method : this.method || 'POST',
6570             id : this.id || Roo.id(),
6571             cls : ''
6572         }
6573         if (this.parent().xtype.match(/^Nav/)) {
6574             cfg.cls = 'navbar-form navbar-' + this.align;
6575             
6576         }
6577         
6578         if (this.labelAlign == 'left' ) {
6579             cfg.cls += ' form-horizontal';
6580         }
6581         
6582         
6583         return cfg;
6584     },
6585     initEvents : function()
6586     {
6587         this.el.on('submit', this.onSubmit, this);
6588         // this was added as random key presses on the form where triggering form submit.
6589         this.el.on('keypress', function(e) {
6590             if (e.getCharCode() != 13) {
6591                 return true;
6592             }
6593             // we might need to allow it for textareas.. and some other items.
6594             // check e.getTarget().
6595             
6596             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6597                 return true;
6598             }
6599         
6600             Roo.log("keypress blocked");
6601             
6602             e.preventDefault();
6603             return false;
6604         });
6605         
6606     },
6607     // private
6608     onSubmit : function(e){
6609         e.stopEvent();
6610     },
6611     
6612      /**
6613      * Returns true if client-side validation on the form is successful.
6614      * @return Boolean
6615      */
6616     isValid : function(){
6617         var items = this.getItems();
6618         var valid = true;
6619         items.each(function(f){
6620            if(!f.validate()){
6621                valid = false;
6622                
6623            }
6624         });
6625         return valid;
6626     },
6627     /**
6628      * Returns true if any fields in this form have changed since their original load.
6629      * @return Boolean
6630      */
6631     isDirty : function(){
6632         var dirty = false;
6633         var items = this.getItems();
6634         items.each(function(f){
6635            if(f.isDirty()){
6636                dirty = true;
6637                return false;
6638            }
6639            return true;
6640         });
6641         return dirty;
6642     },
6643      /**
6644      * Performs a predefined action (submit or load) or custom actions you define on this form.
6645      * @param {String} actionName The name of the action type
6646      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6647      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6648      * accept other config options):
6649      * <pre>
6650 Property          Type             Description
6651 ----------------  ---------------  ----------------------------------------------------------------------------------
6652 url               String           The url for the action (defaults to the form's url)
6653 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6654 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6655 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6656                                    validate the form on the client (defaults to false)
6657      * </pre>
6658      * @return {BasicForm} this
6659      */
6660     doAction : function(action, options){
6661         if(typeof action == 'string'){
6662             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6663         }
6664         if(this.fireEvent('beforeaction', this, action) !== false){
6665             this.beforeAction(action);
6666             action.run.defer(100, action);
6667         }
6668         return this;
6669     },
6670     
6671     // private
6672     beforeAction : function(action){
6673         var o = action.options;
6674         
6675         if(this.loadMask){
6676             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6677         }
6678         // not really supported yet.. ??
6679         
6680         //if(this.waitMsgTarget === true){
6681         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6682         //}else if(this.waitMsgTarget){
6683         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6684         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6685         //}else {
6686         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6687        // }
6688          
6689     },
6690
6691     // private
6692     afterAction : function(action, success){
6693         this.activeAction = null;
6694         var o = action.options;
6695         
6696         //if(this.waitMsgTarget === true){
6697             this.el.unmask();
6698         //}else if(this.waitMsgTarget){
6699         //    this.waitMsgTarget.unmask();
6700         //}else{
6701         //    Roo.MessageBox.updateProgress(1);
6702         //    Roo.MessageBox.hide();
6703        // }
6704         // 
6705         if(success){
6706             if(o.reset){
6707                 this.reset();
6708             }
6709             Roo.callback(o.success, o.scope, [this, action]);
6710             this.fireEvent('actioncomplete', this, action);
6711             
6712         }else{
6713             
6714             // failure condition..
6715             // we have a scenario where updates need confirming.
6716             // eg. if a locking scenario exists..
6717             // we look for { errors : { needs_confirm : true }} in the response.
6718             if (
6719                 (typeof(action.result) != 'undefined')  &&
6720                 (typeof(action.result.errors) != 'undefined')  &&
6721                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6722            ){
6723                 var _t = this;
6724                 Roo.log("not supported yet");
6725                  /*
6726                 
6727                 Roo.MessageBox.confirm(
6728                     "Change requires confirmation",
6729                     action.result.errorMsg,
6730                     function(r) {
6731                         if (r != 'yes') {
6732                             return;
6733                         }
6734                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6735                     }
6736                     
6737                 );
6738                 */
6739                 
6740                 
6741                 return;
6742             }
6743             
6744             Roo.callback(o.failure, o.scope, [this, action]);
6745             // show an error message if no failed handler is set..
6746             if (!this.hasListener('actionfailed')) {
6747                 Roo.log("need to add dialog support");
6748                 /*
6749                 Roo.MessageBox.alert("Error",
6750                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6751                         action.result.errorMsg :
6752                         "Saving Failed, please check your entries or try again"
6753                 );
6754                 */
6755             }
6756             
6757             this.fireEvent('actionfailed', this, action);
6758         }
6759         
6760     },
6761     /**
6762      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6763      * @param {String} id The value to search for
6764      * @return Field
6765      */
6766     findField : function(id){
6767         var items = this.getItems();
6768         var field = items.get(id);
6769         if(!field){
6770              items.each(function(f){
6771                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6772                     field = f;
6773                     return false;
6774                 }
6775                 return true;
6776             });
6777         }
6778         return field || null;
6779     },
6780      /**
6781      * Mark fields in this form invalid in bulk.
6782      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6783      * @return {BasicForm} this
6784      */
6785     markInvalid : function(errors){
6786         if(errors instanceof Array){
6787             for(var i = 0, len = errors.length; i < len; i++){
6788                 var fieldError = errors[i];
6789                 var f = this.findField(fieldError.id);
6790                 if(f){
6791                     f.markInvalid(fieldError.msg);
6792                 }
6793             }
6794         }else{
6795             var field, id;
6796             for(id in errors){
6797                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6798                     field.markInvalid(errors[id]);
6799                 }
6800             }
6801         }
6802         //Roo.each(this.childForms || [], function (f) {
6803         //    f.markInvalid(errors);
6804         //});
6805         
6806         return this;
6807     },
6808
6809     /**
6810      * Set values for fields in this form in bulk.
6811      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6812      * @return {BasicForm} this
6813      */
6814     setValues : function(values){
6815         if(values instanceof Array){ // array of objects
6816             for(var i = 0, len = values.length; i < len; i++){
6817                 var v = values[i];
6818                 var f = this.findField(v.id);
6819                 if(f){
6820                     f.setValue(v.value);
6821                     if(this.trackResetOnLoad){
6822                         f.originalValue = f.getValue();
6823                     }
6824                 }
6825             }
6826         }else{ // object hash
6827             var field, id;
6828             for(id in values){
6829                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6830                     
6831                     if (field.setFromData && 
6832                         field.valueField && 
6833                         field.displayField &&
6834                         // combos' with local stores can 
6835                         // be queried via setValue()
6836                         // to set their value..
6837                         (field.store && !field.store.isLocal)
6838                         ) {
6839                         // it's a combo
6840                         var sd = { };
6841                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6842                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6843                         field.setFromData(sd);
6844                         
6845                     } else {
6846                         field.setValue(values[id]);
6847                     }
6848                     
6849                     
6850                     if(this.trackResetOnLoad){
6851                         field.originalValue = field.getValue();
6852                     }
6853                 }
6854             }
6855         }
6856          
6857         //Roo.each(this.childForms || [], function (f) {
6858         //    f.setValues(values);
6859         //});
6860                 
6861         return this;
6862     },
6863
6864     /**
6865      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6866      * they are returned as an array.
6867      * @param {Boolean} asString
6868      * @return {Object}
6869      */
6870     getValues : function(asString){
6871         //if (this.childForms) {
6872             // copy values from the child forms
6873         //    Roo.each(this.childForms, function (f) {
6874         //        this.setValues(f.getValues());
6875         //    }, this);
6876         //}
6877         
6878         
6879         
6880         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6881         if(asString === true){
6882             return fs;
6883         }
6884         return Roo.urlDecode(fs);
6885     },
6886     
6887     /**
6888      * Returns the fields in this form as an object with key/value pairs. 
6889      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6890      * @return {Object}
6891      */
6892     getFieldValues : function(with_hidden)
6893     {
6894         var items = this.getItems();
6895         var ret = {};
6896         items.each(function(f){
6897             if (!f.getName()) {
6898                 return;
6899             }
6900             var v = f.getValue();
6901             if (f.inputType =='radio') {
6902                 if (typeof(ret[f.getName()]) == 'undefined') {
6903                     ret[f.getName()] = ''; // empty..
6904                 }
6905                 
6906                 if (!f.el.dom.checked) {
6907                     return;
6908                     
6909                 }
6910                 v = f.el.dom.value;
6911                 
6912             }
6913             
6914             // not sure if this supported any more..
6915             if ((typeof(v) == 'object') && f.getRawValue) {
6916                 v = f.getRawValue() ; // dates..
6917             }
6918             // combo boxes where name != hiddenName...
6919             if (f.name != f.getName()) {
6920                 ret[f.name] = f.getRawValue();
6921             }
6922             ret[f.getName()] = v;
6923         });
6924         
6925         return ret;
6926     },
6927
6928     /**
6929      * Clears all invalid messages in this form.
6930      * @return {BasicForm} this
6931      */
6932     clearInvalid : function(){
6933         var items = this.getItems();
6934         
6935         items.each(function(f){
6936            f.clearInvalid();
6937         });
6938         
6939         
6940         
6941         return this;
6942     },
6943
6944     /**
6945      * Resets this form.
6946      * @return {BasicForm} this
6947      */
6948     reset : function(){
6949         var items = this.getItems();
6950         items.each(function(f){
6951             f.reset();
6952         });
6953         
6954         Roo.each(this.childForms || [], function (f) {
6955             f.reset();
6956         });
6957        
6958         
6959         return this;
6960     },
6961     getItems : function()
6962     {
6963         var r=new Roo.util.MixedCollection(false, function(o){
6964             return o.id || (o.id = Roo.id());
6965         });
6966         var iter = function(el) {
6967             if (el.inputEl) {
6968                 r.add(el);
6969             }
6970             if (!el.items) {
6971                 return;
6972             }
6973             Roo.each(el.items,function(e) {
6974                 iter(e);
6975             });
6976             
6977             
6978         };
6979         
6980         iter(this);
6981         return r;
6982         
6983         
6984         
6985         
6986     }
6987     
6988 });
6989
6990  
6991 /*
6992  * Based on:
6993  * Ext JS Library 1.1.1
6994  * Copyright(c) 2006-2007, Ext JS, LLC.
6995  *
6996  * Originally Released Under LGPL - original licence link has changed is not relivant.
6997  *
6998  * Fork - LGPL
6999  * <script type="text/javascript">
7000  */
7001 /**
7002  * @class Roo.form.VTypes
7003  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7004  * @singleton
7005  */
7006 Roo.form.VTypes = function(){
7007     // closure these in so they are only created once.
7008     var alpha = /^[a-zA-Z_]+$/;
7009     var alphanum = /^[a-zA-Z0-9_]+$/;
7010     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7011     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7012
7013     // All these messages and functions are configurable
7014     return {
7015         /**
7016          * The function used to validate email addresses
7017          * @param {String} value The email address
7018          */
7019         'email' : function(v){
7020             return email.test(v);
7021         },
7022         /**
7023          * The error text to display when the email validation function returns false
7024          * @type String
7025          */
7026         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7027         /**
7028          * The keystroke filter mask to be applied on email input
7029          * @type RegExp
7030          */
7031         'emailMask' : /[a-z0-9_\.\-@]/i,
7032
7033         /**
7034          * The function used to validate URLs
7035          * @param {String} value The URL
7036          */
7037         'url' : function(v){
7038             return url.test(v);
7039         },
7040         /**
7041          * The error text to display when the url validation function returns false
7042          * @type String
7043          */
7044         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7045         
7046         /**
7047          * The function used to validate alpha values
7048          * @param {String} value The value
7049          */
7050         'alpha' : function(v){
7051             return alpha.test(v);
7052         },
7053         /**
7054          * The error text to display when the alpha validation function returns false
7055          * @type String
7056          */
7057         'alphaText' : 'This field should only contain letters and _',
7058         /**
7059          * The keystroke filter mask to be applied on alpha input
7060          * @type RegExp
7061          */
7062         'alphaMask' : /[a-z_]/i,
7063
7064         /**
7065          * The function used to validate alphanumeric values
7066          * @param {String} value The value
7067          */
7068         'alphanum' : function(v){
7069             return alphanum.test(v);
7070         },
7071         /**
7072          * The error text to display when the alphanumeric validation function returns false
7073          * @type String
7074          */
7075         'alphanumText' : 'This field should only contain letters, numbers and _',
7076         /**
7077          * The keystroke filter mask to be applied on alphanumeric input
7078          * @type RegExp
7079          */
7080         'alphanumMask' : /[a-z0-9_]/i
7081     };
7082 }();/*
7083  * - LGPL
7084  *
7085  * Input
7086  * 
7087  */
7088
7089 /**
7090  * @class Roo.bootstrap.Input
7091  * @extends Roo.bootstrap.Component
7092  * Bootstrap Input class
7093  * @cfg {Boolean} disabled is it disabled
7094  * @cfg {String} fieldLabel - the label associated
7095  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7096  * @cfg {String} name name of the input
7097  * @cfg {string} fieldLabel - the label associated
7098  * @cfg {string}  inputType - input / file submit ...
7099  * @cfg {string} placeholder - placeholder to put in text.
7100  * @cfg {string}  before - input group add on before
7101  * @cfg {string} after - input group add on after
7102  * @cfg {string} size - (lg|sm) or leave empty..
7103  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7104  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7105  * @cfg {Number} md colspan out of 12 for computer-sized screens
7106  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7107  * @cfg {string} value default value of the input
7108  * @cfg {Number} labelWidth set the width of label (0-12)
7109  * @cfg {String} labelAlign (top|left)
7110  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7111  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7112
7113  * @cfg {String} align (left|center|right) Default left
7114  * 
7115  * 
7116  * 
7117  * @constructor
7118  * Create a new Input
7119  * @param {Object} config The config object
7120  */
7121
7122 Roo.bootstrap.Input = function(config){
7123     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7124    
7125         this.addEvents({
7126             /**
7127              * @event focus
7128              * Fires when this field receives input focus.
7129              * @param {Roo.form.Field} this
7130              */
7131             focus : true,
7132             /**
7133              * @event blur
7134              * Fires when this field loses input focus.
7135              * @param {Roo.form.Field} this
7136              */
7137             blur : true,
7138             /**
7139              * @event specialkey
7140              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7141              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7142              * @param {Roo.form.Field} this
7143              * @param {Roo.EventObject} e The event object
7144              */
7145             specialkey : true,
7146             /**
7147              * @event change
7148              * Fires just before the field blurs if the field value has changed.
7149              * @param {Roo.form.Field} this
7150              * @param {Mixed} newValue The new value
7151              * @param {Mixed} oldValue The original value
7152              */
7153             change : true,
7154             /**
7155              * @event invalid
7156              * Fires after the field has been marked as invalid.
7157              * @param {Roo.form.Field} this
7158              * @param {String} msg The validation message
7159              */
7160             invalid : true,
7161             /**
7162              * @event valid
7163              * Fires after the field has been validated with no errors.
7164              * @param {Roo.form.Field} this
7165              */
7166             valid : true,
7167              /**
7168              * @event keyup
7169              * Fires after the key up
7170              * @param {Roo.form.Field} this
7171              * @param {Roo.EventObject}  e The event Object
7172              */
7173             keyup : true
7174         });
7175 };
7176
7177 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7178      /**
7179      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7180       automatic validation (defaults to "keyup").
7181      */
7182     validationEvent : "keyup",
7183      /**
7184      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7185      */
7186     validateOnBlur : true,
7187     /**
7188      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7189      */
7190     validationDelay : 250,
7191      /**
7192      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7193      */
7194     focusClass : "x-form-focus",  // not needed???
7195     
7196        
7197     /**
7198      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7199      */
7200     invalidClass : "has-warning",
7201     
7202     /**
7203      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7204      */
7205     validClass : "has-success",
7206     
7207     /**
7208      * @cfg {Boolean} hasFeedback (true|false) default true
7209      */
7210     hasFeedback : true,
7211     
7212     /**
7213      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7214      */
7215     invalidFeedbackClass : "glyphicon-warning-sign",
7216     
7217     /**
7218      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7219      */
7220     validFeedbackClass : "glyphicon-ok",
7221     
7222     /**
7223      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7224      */
7225     selectOnFocus : false,
7226     
7227      /**
7228      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7229      */
7230     maskRe : null,
7231        /**
7232      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7233      */
7234     vtype : null,
7235     
7236       /**
7237      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7238      */
7239     disableKeyFilter : false,
7240     
7241        /**
7242      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7243      */
7244     disabled : false,
7245      /**
7246      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7247      */
7248     allowBlank : true,
7249     /**
7250      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7251      */
7252     blankText : "This field is required",
7253     
7254      /**
7255      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7256      */
7257     minLength : 0,
7258     /**
7259      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7260      */
7261     maxLength : Number.MAX_VALUE,
7262     /**
7263      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7264      */
7265     minLengthText : "The minimum length for this field is {0}",
7266     /**
7267      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7268      */
7269     maxLengthText : "The maximum length for this field is {0}",
7270   
7271     
7272     /**
7273      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7274      * If available, this function will be called only after the basic validators all return true, and will be passed the
7275      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7276      */
7277     validator : null,
7278     /**
7279      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7280      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7281      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7282      */
7283     regex : null,
7284     /**
7285      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7286      */
7287     regexText : "",
7288     
7289     autocomplete: false,
7290     
7291     
7292     fieldLabel : '',
7293     inputType : 'text',
7294     
7295     name : false,
7296     placeholder: false,
7297     before : false,
7298     after : false,
7299     size : false,
7300     hasFocus : false,
7301     preventMark: false,
7302     isFormField : true,
7303     value : '',
7304     labelWidth : 2,
7305     labelAlign : false,
7306     readOnly : false,
7307     align : false,
7308     formatedValue : false,
7309     
7310     parentLabelAlign : function()
7311     {
7312         var parent = this;
7313         while (parent.parent()) {
7314             parent = parent.parent();
7315             if (typeof(parent.labelAlign) !='undefined') {
7316                 return parent.labelAlign;
7317             }
7318         }
7319         return 'left';
7320         
7321     },
7322     
7323     getAutoCreate : function(){
7324         
7325         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7326         
7327         var id = Roo.id();
7328         
7329         var cfg = {};
7330         
7331         if(this.inputType != 'hidden'){
7332             cfg.cls = 'form-group' //input-group
7333         }
7334         
7335         var input =  {
7336             tag: 'input',
7337             id : id,
7338             type : this.inputType,
7339             value : this.value,
7340             cls : 'form-control',
7341             placeholder : this.placeholder || '',
7342             autocomplete : this.autocomplete || 'new-password'
7343         };
7344         
7345         
7346         if(this.align){
7347             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7348         }
7349         
7350         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7351             input.maxLength = this.maxLength;
7352         }
7353         
7354         if (this.disabled) {
7355             input.disabled=true;
7356         }
7357         
7358         if (this.readOnly) {
7359             input.readonly=true;
7360         }
7361         
7362         if (this.name) {
7363             input.name = this.name;
7364         }
7365         if (this.size) {
7366             input.cls += ' input-' + this.size;
7367         }
7368         var settings=this;
7369         ['xs','sm','md','lg'].map(function(size){
7370             if (settings[size]) {
7371                 cfg.cls += ' col-' + size + '-' + settings[size];
7372             }
7373         });
7374         
7375         var inputblock = input;
7376         
7377         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7378             
7379             var feedback = {
7380                 tag: 'span',
7381                 cls: 'glyphicon form-control-feedback'
7382             };
7383
7384             inputblock = {
7385                 cls : 'has-feedback',
7386                 cn :  [
7387                     input,
7388                     feedback
7389                 ] 
7390             };  
7391         }
7392          
7393 //        var inputblock = input;
7394         
7395         if (this.before || this.after) {
7396             
7397             inputblock = {
7398                 cls : 'input-group',
7399                 cn :  [] 
7400             };
7401             
7402             if (this.before && typeof(this.before) == 'string') {
7403                 
7404                 inputblock.cn.push({
7405                     tag :'span',
7406                     cls : 'roo-input-before input-group-addon',
7407                     html : this.before
7408                 });
7409             }
7410             if (this.before && typeof(this.before) == 'object') {
7411                 this.before = Roo.factory(this.before);
7412                 Roo.log(this.before);
7413                 inputblock.cn.push({
7414                     tag :'span',
7415                     cls : 'roo-input-before input-group-' +
7416                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7417                 });
7418             }
7419             
7420             inputblock.cn.push(input);
7421             
7422             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7423                 inputblock.cls += ' has-feedback';
7424                 inputblock.cn.push(feedback);
7425             }
7426             
7427             if (this.after && typeof(this.after) == 'string') {
7428                 inputblock.cn.push({
7429                     tag :'span',
7430                     cls : 'roo-input-after input-group-addon',
7431                     html : this.after
7432                 });
7433             }
7434             if (this.after && typeof(this.after) == 'object') {
7435                 this.after = Roo.factory(this.after);
7436                 Roo.log(this.after);
7437                 inputblock.cn.push({
7438                     tag :'span',
7439                     cls : 'roo-input-after input-group-' +
7440                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7441                 });
7442             }
7443         };
7444         
7445         if (align ==='left' && this.fieldLabel.length) {
7446                 Roo.log("left and has label");
7447                 cfg.cn = [
7448                     
7449                     {
7450                         tag: 'label',
7451                         'for' :  id,
7452                         cls : 'control-label col-sm-' + this.labelWidth,
7453                         html : this.fieldLabel
7454                         
7455                     },
7456                     {
7457                         cls : "col-sm-" + (12 - this.labelWidth), 
7458                         cn: [
7459                             inputblock
7460                         ]
7461                     }
7462                     
7463                 ];
7464         } else if ( this.fieldLabel.length) {
7465                 Roo.log(" label");
7466                  cfg.cn = [
7467                    
7468                     {
7469                         tag: 'label',
7470                         //cls : 'input-group-addon',
7471                         html : this.fieldLabel
7472                         
7473                     },
7474                     
7475                     inputblock
7476                     
7477                 ];
7478
7479         } else {
7480             
7481                 Roo.log(" no label && no align");
7482                 cfg.cn = [
7483                     
7484                         inputblock
7485                     
7486                 ];
7487                 
7488                 
7489         };
7490         Roo.log('input-parentType: ' + this.parentType);
7491         
7492         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7493            cfg.cls += ' navbar-form';
7494            Roo.log(cfg);
7495         }
7496         
7497         return cfg;
7498         
7499     },
7500     /**
7501      * return the real input element.
7502      */
7503     inputEl: function ()
7504     {
7505         return this.el.select('input.form-control',true).first();
7506     },
7507     
7508     tooltipEl : function()
7509     {
7510         return this.inputEl();
7511     },
7512     
7513     setDisabled : function(v)
7514     {
7515         var i  = this.inputEl().dom;
7516         if (!v) {
7517             i.removeAttribute('disabled');
7518             return;
7519             
7520         }
7521         i.setAttribute('disabled','true');
7522     },
7523     initEvents : function()
7524     {
7525           
7526         this.inputEl().on("keydown" , this.fireKey,  this);
7527         this.inputEl().on("focus", this.onFocus,  this);
7528         this.inputEl().on("blur", this.onBlur,  this);
7529         
7530         this.inputEl().relayEvent('keyup', this);
7531
7532         // reference to original value for reset
7533         this.originalValue = this.getValue();
7534         //Roo.form.TextField.superclass.initEvents.call(this);
7535         if(this.validationEvent == 'keyup'){
7536             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7537             this.inputEl().on('keyup', this.filterValidation, this);
7538         }
7539         else if(this.validationEvent !== false){
7540             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7541         }
7542         
7543         if(this.selectOnFocus){
7544             this.on("focus", this.preFocus, this);
7545             
7546         }
7547         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7548             this.inputEl().on("keypress", this.filterKeys, this);
7549         }
7550        /* if(this.grow){
7551             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7552             this.el.on("click", this.autoSize,  this);
7553         }
7554         */
7555         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7556             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7557         }
7558         
7559         if (typeof(this.before) == 'object') {
7560             this.before.render(this.el.select('.roo-input-before',true).first());
7561         }
7562         if (typeof(this.after) == 'object') {
7563             this.after.render(this.el.select('.roo-input-after',true).first());
7564         }
7565         
7566         
7567     },
7568     filterValidation : function(e){
7569         if(!e.isNavKeyPress()){
7570             this.validationTask.delay(this.validationDelay);
7571         }
7572     },
7573      /**
7574      * Validates the field value
7575      * @return {Boolean} True if the value is valid, else false
7576      */
7577     validate : function(){
7578         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7579         if(this.disabled || this.validateValue(this.getRawValue())){
7580             this.markValid();
7581             return true;
7582         }
7583         
7584         this.markInvalid();
7585         return false;
7586     },
7587     
7588     
7589     /**
7590      * Validates a value according to the field's validation rules and marks the field as invalid
7591      * if the validation fails
7592      * @param {Mixed} value The value to validate
7593      * @return {Boolean} True if the value is valid, else false
7594      */
7595     validateValue : function(value){
7596         if(value.length < 1)  { // if it's blank
7597             if(this.allowBlank){
7598                 return true;
7599             }
7600             return false;
7601         }
7602         
7603         if(value.length < this.minLength){
7604             return false;
7605         }
7606         if(value.length > this.maxLength){
7607             return false;
7608         }
7609         if(this.vtype){
7610             var vt = Roo.form.VTypes;
7611             if(!vt[this.vtype](value, this)){
7612                 return false;
7613             }
7614         }
7615         if(typeof this.validator == "function"){
7616             var msg = this.validator(value);
7617             if(msg !== true){
7618                 return false;
7619             }
7620         }
7621         
7622         if(this.regex && !this.regex.test(value)){
7623             return false;
7624         }
7625         
7626         return true;
7627     },
7628
7629     
7630     
7631      // private
7632     fireKey : function(e){
7633         //Roo.log('field ' + e.getKey());
7634         if(e.isNavKeyPress()){
7635             this.fireEvent("specialkey", this, e);
7636         }
7637     },
7638     focus : function (selectText){
7639         if(this.rendered){
7640             this.inputEl().focus();
7641             if(selectText === true){
7642                 this.inputEl().dom.select();
7643             }
7644         }
7645         return this;
7646     } ,
7647     
7648     onFocus : function(){
7649         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7650            // this.el.addClass(this.focusClass);
7651         }
7652         if(!this.hasFocus){
7653             this.hasFocus = true;
7654             this.startValue = this.getValue();
7655             this.fireEvent("focus", this);
7656         }
7657     },
7658     
7659     beforeBlur : Roo.emptyFn,
7660
7661     
7662     // private
7663     onBlur : function(){
7664         this.beforeBlur();
7665         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7666             //this.el.removeClass(this.focusClass);
7667         }
7668         this.hasFocus = false;
7669         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7670             this.validate();
7671         }
7672         var v = this.getValue();
7673         if(String(v) !== String(this.startValue)){
7674             this.fireEvent('change', this, v, this.startValue);
7675         }
7676         this.fireEvent("blur", this);
7677     },
7678     
7679     /**
7680      * Resets the current field value to the originally loaded value and clears any validation messages
7681      */
7682     reset : function(){
7683         this.setValue(this.originalValue);
7684         this.validate();
7685     },
7686      /**
7687      * Returns the name of the field
7688      * @return {Mixed} name The name field
7689      */
7690     getName: function(){
7691         return this.name;
7692     },
7693      /**
7694      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7695      * @return {Mixed} value The field value
7696      */
7697     getValue : function(){
7698         
7699         var v = this.inputEl().getValue();
7700         
7701         return v;
7702     },
7703     /**
7704      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7705      * @return {Mixed} value The field value
7706      */
7707     getRawValue : function(){
7708         var v = this.inputEl().getValue();
7709         
7710         return v;
7711     },
7712     
7713     /**
7714      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7715      * @param {Mixed} value The value to set
7716      */
7717     setRawValue : function(v){
7718         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7719     },
7720     
7721     selectText : function(start, end){
7722         var v = this.getRawValue();
7723         if(v.length > 0){
7724             start = start === undefined ? 0 : start;
7725             end = end === undefined ? v.length : end;
7726             var d = this.inputEl().dom;
7727             if(d.setSelectionRange){
7728                 d.setSelectionRange(start, end);
7729             }else if(d.createTextRange){
7730                 var range = d.createTextRange();
7731                 range.moveStart("character", start);
7732                 range.moveEnd("character", v.length-end);
7733                 range.select();
7734             }
7735         }
7736     },
7737     
7738     /**
7739      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7740      * @param {Mixed} value The value to set
7741      */
7742     setValue : function(v){
7743         this.value = v;
7744         if(this.rendered){
7745             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7746             this.validate();
7747         }
7748     },
7749     
7750     /*
7751     processValue : function(value){
7752         if(this.stripCharsRe){
7753             var newValue = value.replace(this.stripCharsRe, '');
7754             if(newValue !== value){
7755                 this.setRawValue(newValue);
7756                 return newValue;
7757             }
7758         }
7759         return value;
7760     },
7761   */
7762     preFocus : function(){
7763         
7764         if(this.selectOnFocus){
7765             this.inputEl().dom.select();
7766         }
7767     },
7768     filterKeys : function(e){
7769         var k = e.getKey();
7770         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7771             return;
7772         }
7773         var c = e.getCharCode(), cc = String.fromCharCode(c);
7774         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7775             return;
7776         }
7777         if(!this.maskRe.test(cc)){
7778             e.stopEvent();
7779         }
7780     },
7781      /**
7782      * Clear any invalid styles/messages for this field
7783      */
7784     clearInvalid : function(){
7785         
7786         if(!this.el || this.preventMark){ // not rendered
7787             return;
7788         }
7789         this.el.removeClass(this.invalidClass);
7790         
7791         this.fireEvent('valid', this);
7792     },
7793     
7794      /**
7795      * Mark this field as valid
7796      */
7797     markValid : function(){
7798         if(!this.el  || this.preventMark){ // not rendered
7799             return;
7800         }
7801         
7802         this.el.removeClass([this.invalidClass, this.validClass]);
7803         
7804         if(this.disabled || this.allowBlank){
7805             return;
7806         }
7807         
7808         this.el.addClass(this.validClass);
7809         
7810         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7811             
7812             var feedback = this.el.select('.form-control-feedback', true).first();
7813             
7814             if(feedback){
7815                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7816                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7817             }
7818             
7819         }
7820         
7821         this.fireEvent('valid', this);
7822     },
7823     
7824      /**
7825      * Mark this field as invalid
7826      * @param {String} msg The validation message
7827      */
7828     markInvalid : function(msg){
7829         if(!this.el  || this.preventMark){ // not rendered
7830             return;
7831         }
7832         
7833         this.el.removeClass([this.invalidClass, this.validClass]);
7834         
7835         if(this.disabled || this.allowBlank){
7836             return;
7837         }
7838         
7839         this.el.addClass(this.invalidClass);
7840         
7841         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7842             
7843             var feedback = this.el.select('.form-control-feedback', true).first();
7844             
7845             if(feedback){
7846                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7847                 
7848                 if(this.getValue().length){
7849                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7850                 }
7851                 
7852             }
7853             
7854         }
7855         
7856         this.fireEvent('invalid', this, msg);
7857     },
7858     // private
7859     SafariOnKeyDown : function(event)
7860     {
7861         // this is a workaround for a password hang bug on chrome/ webkit.
7862         
7863         var isSelectAll = false;
7864         
7865         if(this.inputEl().dom.selectionEnd > 0){
7866             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7867         }
7868         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7869             event.preventDefault();
7870             this.setValue('');
7871             return;
7872         }
7873         
7874         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7875             
7876             event.preventDefault();
7877             // this is very hacky as keydown always get's upper case.
7878             //
7879             var cc = String.fromCharCode(event.getCharCode());
7880             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7881             
7882         }
7883     },
7884     adjustWidth : function(tag, w){
7885         tag = tag.toLowerCase();
7886         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7887             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7888                 if(tag == 'input'){
7889                     return w + 2;
7890                 }
7891                 if(tag == 'textarea'){
7892                     return w-2;
7893                 }
7894             }else if(Roo.isOpera){
7895                 if(tag == 'input'){
7896                     return w + 2;
7897                 }
7898                 if(tag == 'textarea'){
7899                     return w-2;
7900                 }
7901             }
7902         }
7903         return w;
7904     }
7905     
7906 });
7907
7908  
7909 /*
7910  * - LGPL
7911  *
7912  * Input
7913  * 
7914  */
7915
7916 /**
7917  * @class Roo.bootstrap.TextArea
7918  * @extends Roo.bootstrap.Input
7919  * Bootstrap TextArea class
7920  * @cfg {Number} cols Specifies the visible width of a text area
7921  * @cfg {Number} rows Specifies the visible number of lines in a text area
7922  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7923  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7924  * @cfg {string} html text
7925  * 
7926  * @constructor
7927  * Create a new TextArea
7928  * @param {Object} config The config object
7929  */
7930
7931 Roo.bootstrap.TextArea = function(config){
7932     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7933    
7934 };
7935
7936 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7937      
7938     cols : false,
7939     rows : 5,
7940     readOnly : false,
7941     warp : 'soft',
7942     resize : false,
7943     value: false,
7944     html: false,
7945     
7946     getAutoCreate : function(){
7947         
7948         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7949         
7950         var id = Roo.id();
7951         
7952         var cfg = {};
7953         
7954         var input =  {
7955             tag: 'textarea',
7956             id : id,
7957             warp : this.warp,
7958             rows : this.rows,
7959             value : this.value || '',
7960             html: this.html || '',
7961             cls : 'form-control',
7962             placeholder : this.placeholder || '' 
7963             
7964         };
7965         
7966         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7967             input.maxLength = this.maxLength;
7968         }
7969         
7970         if(this.resize){
7971             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7972         }
7973         
7974         if(this.cols){
7975             input.cols = this.cols;
7976         }
7977         
7978         if (this.readOnly) {
7979             input.readonly = true;
7980         }
7981         
7982         if (this.name) {
7983             input.name = this.name;
7984         }
7985         
7986         if (this.size) {
7987             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7988         }
7989         
7990         var settings=this;
7991         ['xs','sm','md','lg'].map(function(size){
7992             if (settings[size]) {
7993                 cfg.cls += ' col-' + size + '-' + settings[size];
7994             }
7995         });
7996         
7997         var inputblock = input;
7998         
7999         if(this.hasFeedback && !this.allowBlank){
8000             
8001             var feedback = {
8002                 tag: 'span',
8003                 cls: 'glyphicon form-control-feedback'
8004             };
8005
8006             inputblock = {
8007                 cls : 'has-feedback',
8008                 cn :  [
8009                     input,
8010                     feedback
8011                 ] 
8012             };  
8013         }
8014         
8015         
8016         if (this.before || this.after) {
8017             
8018             inputblock = {
8019                 cls : 'input-group',
8020                 cn :  [] 
8021             };
8022             if (this.before) {
8023                 inputblock.cn.push({
8024                     tag :'span',
8025                     cls : 'input-group-addon',
8026                     html : this.before
8027                 });
8028             }
8029             
8030             inputblock.cn.push(input);
8031             
8032             if(this.hasFeedback && !this.allowBlank){
8033                 inputblock.cls += ' has-feedback';
8034                 inputblock.cn.push(feedback);
8035             }
8036             
8037             if (this.after) {
8038                 inputblock.cn.push({
8039                     tag :'span',
8040                     cls : 'input-group-addon',
8041                     html : this.after
8042                 });
8043             }
8044             
8045         }
8046         
8047         if (align ==='left' && this.fieldLabel.length) {
8048                 Roo.log("left and has label");
8049                 cfg.cn = [
8050                     
8051                     {
8052                         tag: 'label',
8053                         'for' :  id,
8054                         cls : 'control-label col-sm-' + this.labelWidth,
8055                         html : this.fieldLabel
8056                         
8057                     },
8058                     {
8059                         cls : "col-sm-" + (12 - this.labelWidth), 
8060                         cn: [
8061                             inputblock
8062                         ]
8063                     }
8064                     
8065                 ];
8066         } else if ( this.fieldLabel.length) {
8067                 Roo.log(" label");
8068                  cfg.cn = [
8069                    
8070                     {
8071                         tag: 'label',
8072                         //cls : 'input-group-addon',
8073                         html : this.fieldLabel
8074                         
8075                     },
8076                     
8077                     inputblock
8078                     
8079                 ];
8080
8081         } else {
8082             
8083                    Roo.log(" no label && no align");
8084                 cfg.cn = [
8085                     
8086                         inputblock
8087                     
8088                 ];
8089                 
8090                 
8091         }
8092         
8093         if (this.disabled) {
8094             input.disabled=true;
8095         }
8096         
8097         return cfg;
8098         
8099     },
8100     /**
8101      * return the real textarea element.
8102      */
8103     inputEl: function ()
8104     {
8105         return this.el.select('textarea.form-control',true).first();
8106     }
8107 });
8108
8109  
8110 /*
8111  * - LGPL
8112  *
8113  * trigger field - base class for combo..
8114  * 
8115  */
8116  
8117 /**
8118  * @class Roo.bootstrap.TriggerField
8119  * @extends Roo.bootstrap.Input
8120  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8121  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8122  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8123  * for which you can provide a custom implementation.  For example:
8124  * <pre><code>
8125 var trigger = new Roo.bootstrap.TriggerField();
8126 trigger.onTriggerClick = myTriggerFn;
8127 trigger.applyTo('my-field');
8128 </code></pre>
8129  *
8130  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8131  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8132  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8133  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8134  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8135
8136  * @constructor
8137  * Create a new TriggerField.
8138  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8139  * to the base TextField)
8140  */
8141 Roo.bootstrap.TriggerField = function(config){
8142     this.mimicing = false;
8143     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8144 };
8145
8146 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8147     /**
8148      * @cfg {String} triggerClass A CSS class to apply to the trigger
8149      */
8150      /**
8151      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8152      */
8153     hideTrigger:false,
8154
8155     /** @cfg {Boolean} grow @hide */
8156     /** @cfg {Number} growMin @hide */
8157     /** @cfg {Number} growMax @hide */
8158
8159     /**
8160      * @hide 
8161      * @method
8162      */
8163     autoSize: Roo.emptyFn,
8164     // private
8165     monitorTab : true,
8166     // private
8167     deferHeight : true,
8168
8169     
8170     actionMode : 'wrap',
8171     
8172     caret : false,
8173     
8174     
8175     getAutoCreate : function(){
8176        
8177         var align = this.labelAlign || this.parentLabelAlign();
8178         
8179         var id = Roo.id();
8180         
8181         var cfg = {
8182             cls: 'form-group' //input-group
8183         };
8184         
8185         
8186         var input =  {
8187             tag: 'input',
8188             id : id,
8189             type : this.inputType,
8190             cls : 'form-control',
8191             autocomplete: 'new-password',
8192             placeholder : this.placeholder || '' 
8193             
8194         };
8195         if (this.name) {
8196             input.name = this.name;
8197         }
8198         if (this.size) {
8199             input.cls += ' input-' + this.size;
8200         }
8201         
8202         if (this.disabled) {
8203             input.disabled=true;
8204         }
8205         
8206         var inputblock = input;
8207         
8208         if(this.hasFeedback && !this.allowBlank){
8209             
8210             var feedback = {
8211                 tag: 'span',
8212                 cls: 'glyphicon form-control-feedback'
8213             };
8214
8215             inputblock = {
8216                 cls : 'has-feedback',
8217                 cn :  [
8218                     input,
8219                     feedback
8220                 ] 
8221             };  
8222         }
8223         
8224         if (this.before || this.after) {
8225             
8226             inputblock = {
8227                 cls : 'input-group',
8228                 cn :  [] 
8229             };
8230             if (this.before) {
8231                 inputblock.cn.push({
8232                     tag :'span',
8233                     cls : 'input-group-addon',
8234                     html : this.before
8235                 });
8236             }
8237             
8238             inputblock.cn.push(input);
8239             
8240             if(this.hasFeedback && !this.allowBlank){
8241                 inputblock.cls += ' has-feedback';
8242                 inputblock.cn.push(feedback);
8243             }
8244             
8245             if (this.after) {
8246                 inputblock.cn.push({
8247                     tag :'span',
8248                     cls : 'input-group-addon',
8249                     html : this.after
8250                 });
8251             }
8252             
8253         };
8254         
8255         var box = {
8256             tag: 'div',
8257             cn: [
8258                 {
8259                     tag: 'input',
8260                     type : 'hidden',
8261                     cls: 'form-hidden-field'
8262                 },
8263                 inputblock
8264             ]
8265             
8266         };
8267         
8268         if(this.multiple){
8269             Roo.log('multiple');
8270             
8271             box = {
8272                 tag: 'div',
8273                 cn: [
8274                     {
8275                         tag: 'input',
8276                         type : 'hidden',
8277                         cls: 'form-hidden-field'
8278                     },
8279                     {
8280                         tag: 'ul',
8281                         cls: 'select2-choices',
8282                         cn:[
8283                             {
8284                                 tag: 'li',
8285                                 cls: 'select2-search-field',
8286                                 cn: [
8287
8288                                     inputblock
8289                                 ]
8290                             }
8291                         ]
8292                     }
8293                 ]
8294             }
8295         };
8296         
8297         var combobox = {
8298             cls: 'select2-container input-group',
8299             cn: [
8300                 box
8301 //                {
8302 //                    tag: 'ul',
8303 //                    cls: 'typeahead typeahead-long dropdown-menu',
8304 //                    style: 'display:none'
8305 //                }
8306             ]
8307         };
8308         
8309         if(!this.multiple && this.showToggleBtn){
8310             
8311             var caret = {
8312                         tag: 'span',
8313                         cls: 'caret'
8314              };
8315             if (this.caret != false) {
8316                 caret = {
8317                      tag: 'i',
8318                      cls: 'fa fa-' + this.caret
8319                 };
8320                 
8321             }
8322             
8323             combobox.cn.push({
8324                 tag :'span',
8325                 cls : 'input-group-addon btn dropdown-toggle',
8326                 cn : [
8327                     caret,
8328                     {
8329                         tag: 'span',
8330                         cls: 'combobox-clear',
8331                         cn  : [
8332                             {
8333                                 tag : 'i',
8334                                 cls: 'icon-remove'
8335                             }
8336                         ]
8337                     }
8338                 ]
8339
8340             })
8341         }
8342         
8343         if(this.multiple){
8344             combobox.cls += ' select2-container-multi';
8345         }
8346         
8347         if (align ==='left' && this.fieldLabel.length) {
8348             
8349                 Roo.log("left and has label");
8350                 cfg.cn = [
8351                     
8352                     {
8353                         tag: 'label',
8354                         'for' :  id,
8355                         cls : 'control-label col-sm-' + this.labelWidth,
8356                         html : this.fieldLabel
8357                         
8358                     },
8359                     {
8360                         cls : "col-sm-" + (12 - this.labelWidth), 
8361                         cn: [
8362                             combobox
8363                         ]
8364                     }
8365                     
8366                 ];
8367         } else if ( this.fieldLabel.length) {
8368                 Roo.log(" label");
8369                  cfg.cn = [
8370                    
8371                     {
8372                         tag: 'label',
8373                         //cls : 'input-group-addon',
8374                         html : this.fieldLabel
8375                         
8376                     },
8377                     
8378                     combobox
8379                     
8380                 ];
8381
8382         } else {
8383             
8384                 Roo.log(" no label && no align");
8385                 cfg = combobox
8386                      
8387                 
8388         }
8389          
8390         var settings=this;
8391         ['xs','sm','md','lg'].map(function(size){
8392             if (settings[size]) {
8393                 cfg.cls += ' col-' + size + '-' + settings[size];
8394             }
8395         });
8396         
8397         return cfg;
8398         
8399     },
8400     
8401     
8402     
8403     // private
8404     onResize : function(w, h){
8405 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8406 //        if(typeof w == 'number'){
8407 //            var x = w - this.trigger.getWidth();
8408 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8409 //            this.trigger.setStyle('left', x+'px');
8410 //        }
8411     },
8412
8413     // private
8414     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8415
8416     // private
8417     getResizeEl : function(){
8418         return this.inputEl();
8419     },
8420
8421     // private
8422     getPositionEl : function(){
8423         return this.inputEl();
8424     },
8425
8426     // private
8427     alignErrorIcon : function(){
8428         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8429     },
8430
8431     // private
8432     initEvents : function(){
8433         
8434         this.createList();
8435         
8436         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8437         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8438         if(!this.multiple && this.showToggleBtn){
8439             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8440             if(this.hideTrigger){
8441                 this.trigger.setDisplayed(false);
8442             }
8443             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8444         }
8445         
8446         if(this.multiple){
8447             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8448         }
8449         
8450         //this.trigger.addClassOnOver('x-form-trigger-over');
8451         //this.trigger.addClassOnClick('x-form-trigger-click');
8452         
8453         //if(!this.width){
8454         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8455         //}
8456     },
8457     
8458     createList : function()
8459     {
8460         this.list = Roo.get(document.body).createChild({
8461             tag: 'ul',
8462             cls: 'typeahead typeahead-long dropdown-menu',
8463             style: 'display:none'
8464         });
8465         
8466         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8467         
8468     },
8469
8470     // private
8471     initTrigger : function(){
8472        
8473     },
8474
8475     // private
8476     onDestroy : function(){
8477         if(this.trigger){
8478             this.trigger.removeAllListeners();
8479           //  this.trigger.remove();
8480         }
8481         //if(this.wrap){
8482         //    this.wrap.remove();
8483         //}
8484         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8485     },
8486
8487     // private
8488     onFocus : function(){
8489         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8490         /*
8491         if(!this.mimicing){
8492             this.wrap.addClass('x-trigger-wrap-focus');
8493             this.mimicing = true;
8494             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8495             if(this.monitorTab){
8496                 this.el.on("keydown", this.checkTab, this);
8497             }
8498         }
8499         */
8500     },
8501
8502     // private
8503     checkTab : function(e){
8504         if(e.getKey() == e.TAB){
8505             this.triggerBlur();
8506         }
8507     },
8508
8509     // private
8510     onBlur : function(){
8511         // do nothing
8512     },
8513
8514     // private
8515     mimicBlur : function(e, t){
8516         /*
8517         if(!this.wrap.contains(t) && this.validateBlur()){
8518             this.triggerBlur();
8519         }
8520         */
8521     },
8522
8523     // private
8524     triggerBlur : function(){
8525         this.mimicing = false;
8526         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8527         if(this.monitorTab){
8528             this.el.un("keydown", this.checkTab, this);
8529         }
8530         //this.wrap.removeClass('x-trigger-wrap-focus');
8531         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8532     },
8533
8534     // private
8535     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8536     validateBlur : function(e, t){
8537         return true;
8538     },
8539
8540     // private
8541     onDisable : function(){
8542         this.inputEl().dom.disabled = true;
8543         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8544         //if(this.wrap){
8545         //    this.wrap.addClass('x-item-disabled');
8546         //}
8547     },
8548
8549     // private
8550     onEnable : function(){
8551         this.inputEl().dom.disabled = false;
8552         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8553         //if(this.wrap){
8554         //    this.el.removeClass('x-item-disabled');
8555         //}
8556     },
8557
8558     // private
8559     onShow : function(){
8560         var ae = this.getActionEl();
8561         
8562         if(ae){
8563             ae.dom.style.display = '';
8564             ae.dom.style.visibility = 'visible';
8565         }
8566     },
8567
8568     // private
8569     
8570     onHide : function(){
8571         var ae = this.getActionEl();
8572         ae.dom.style.display = 'none';
8573     },
8574
8575     /**
8576      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8577      * by an implementing function.
8578      * @method
8579      * @param {EventObject} e
8580      */
8581     onTriggerClick : Roo.emptyFn
8582 });
8583  /*
8584  * Based on:
8585  * Ext JS Library 1.1.1
8586  * Copyright(c) 2006-2007, Ext JS, LLC.
8587  *
8588  * Originally Released Under LGPL - original licence link has changed is not relivant.
8589  *
8590  * Fork - LGPL
8591  * <script type="text/javascript">
8592  */
8593
8594
8595 /**
8596  * @class Roo.data.SortTypes
8597  * @singleton
8598  * Defines the default sorting (casting?) comparison functions used when sorting data.
8599  */
8600 Roo.data.SortTypes = {
8601     /**
8602      * Default sort that does nothing
8603      * @param {Mixed} s The value being converted
8604      * @return {Mixed} The comparison value
8605      */
8606     none : function(s){
8607         return s;
8608     },
8609     
8610     /**
8611      * The regular expression used to strip tags
8612      * @type {RegExp}
8613      * @property
8614      */
8615     stripTagsRE : /<\/?[^>]+>/gi,
8616     
8617     /**
8618      * Strips all HTML tags to sort on text only
8619      * @param {Mixed} s The value being converted
8620      * @return {String} The comparison value
8621      */
8622     asText : function(s){
8623         return String(s).replace(this.stripTagsRE, "");
8624     },
8625     
8626     /**
8627      * Strips all HTML tags to sort on text only - Case insensitive
8628      * @param {Mixed} s The value being converted
8629      * @return {String} The comparison value
8630      */
8631     asUCText : function(s){
8632         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8633     },
8634     
8635     /**
8636      * Case insensitive string
8637      * @param {Mixed} s The value being converted
8638      * @return {String} The comparison value
8639      */
8640     asUCString : function(s) {
8641         return String(s).toUpperCase();
8642     },
8643     
8644     /**
8645      * Date sorting
8646      * @param {Mixed} s The value being converted
8647      * @return {Number} The comparison value
8648      */
8649     asDate : function(s) {
8650         if(!s){
8651             return 0;
8652         }
8653         if(s instanceof Date){
8654             return s.getTime();
8655         }
8656         return Date.parse(String(s));
8657     },
8658     
8659     /**
8660      * Float sorting
8661      * @param {Mixed} s The value being converted
8662      * @return {Float} The comparison value
8663      */
8664     asFloat : function(s) {
8665         var val = parseFloat(String(s).replace(/,/g, ""));
8666         if(isNaN(val)) val = 0;
8667         return val;
8668     },
8669     
8670     /**
8671      * Integer sorting
8672      * @param {Mixed} s The value being converted
8673      * @return {Number} The comparison value
8674      */
8675     asInt : function(s) {
8676         var val = parseInt(String(s).replace(/,/g, ""));
8677         if(isNaN(val)) val = 0;
8678         return val;
8679     }
8680 };/*
8681  * Based on:
8682  * Ext JS Library 1.1.1
8683  * Copyright(c) 2006-2007, Ext JS, LLC.
8684  *
8685  * Originally Released Under LGPL - original licence link has changed is not relivant.
8686  *
8687  * Fork - LGPL
8688  * <script type="text/javascript">
8689  */
8690
8691 /**
8692 * @class Roo.data.Record
8693  * Instances of this class encapsulate both record <em>definition</em> information, and record
8694  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8695  * to access Records cached in an {@link Roo.data.Store} object.<br>
8696  * <p>
8697  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8698  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8699  * objects.<br>
8700  * <p>
8701  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8702  * @constructor
8703  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8704  * {@link #create}. The parameters are the same.
8705  * @param {Array} data An associative Array of data values keyed by the field name.
8706  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8707  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8708  * not specified an integer id is generated.
8709  */
8710 Roo.data.Record = function(data, id){
8711     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8712     this.data = data;
8713 };
8714
8715 /**
8716  * Generate a constructor for a specific record layout.
8717  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8718  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8719  * Each field definition object may contain the following properties: <ul>
8720  * <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,
8721  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8722  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8723  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8724  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8725  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8726  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8727  * this may be omitted.</p></li>
8728  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8729  * <ul><li>auto (Default, implies no conversion)</li>
8730  * <li>string</li>
8731  * <li>int</li>
8732  * <li>float</li>
8733  * <li>boolean</li>
8734  * <li>date</li></ul></p></li>
8735  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8736  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8737  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8738  * by the Reader into an object that will be stored in the Record. It is passed the
8739  * following parameters:<ul>
8740  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8741  * </ul></p></li>
8742  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8743  * </ul>
8744  * <br>usage:<br><pre><code>
8745 var TopicRecord = Roo.data.Record.create(
8746     {name: 'title', mapping: 'topic_title'},
8747     {name: 'author', mapping: 'username'},
8748     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8749     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8750     {name: 'lastPoster', mapping: 'user2'},
8751     {name: 'excerpt', mapping: 'post_text'}
8752 );
8753
8754 var myNewRecord = new TopicRecord({
8755     title: 'Do my job please',
8756     author: 'noobie',
8757     totalPosts: 1,
8758     lastPost: new Date(),
8759     lastPoster: 'Animal',
8760     excerpt: 'No way dude!'
8761 });
8762 myStore.add(myNewRecord);
8763 </code></pre>
8764  * @method create
8765  * @static
8766  */
8767 Roo.data.Record.create = function(o){
8768     var f = function(){
8769         f.superclass.constructor.apply(this, arguments);
8770     };
8771     Roo.extend(f, Roo.data.Record);
8772     var p = f.prototype;
8773     p.fields = new Roo.util.MixedCollection(false, function(field){
8774         return field.name;
8775     });
8776     for(var i = 0, len = o.length; i < len; i++){
8777         p.fields.add(new Roo.data.Field(o[i]));
8778     }
8779     f.getField = function(name){
8780         return p.fields.get(name);  
8781     };
8782     return f;
8783 };
8784
8785 Roo.data.Record.AUTO_ID = 1000;
8786 Roo.data.Record.EDIT = 'edit';
8787 Roo.data.Record.REJECT = 'reject';
8788 Roo.data.Record.COMMIT = 'commit';
8789
8790 Roo.data.Record.prototype = {
8791     /**
8792      * Readonly flag - true if this record has been modified.
8793      * @type Boolean
8794      */
8795     dirty : false,
8796     editing : false,
8797     error: null,
8798     modified: null,
8799
8800     // private
8801     join : function(store){
8802         this.store = store;
8803     },
8804
8805     /**
8806      * Set the named field to the specified value.
8807      * @param {String} name The name of the field to set.
8808      * @param {Object} value The value to set the field to.
8809      */
8810     set : function(name, value){
8811         if(this.data[name] == value){
8812             return;
8813         }
8814         this.dirty = true;
8815         if(!this.modified){
8816             this.modified = {};
8817         }
8818         if(typeof this.modified[name] == 'undefined'){
8819             this.modified[name] = this.data[name];
8820         }
8821         this.data[name] = value;
8822         if(!this.editing && this.store){
8823             this.store.afterEdit(this);
8824         }       
8825     },
8826
8827     /**
8828      * Get the value of the named field.
8829      * @param {String} name The name of the field to get the value of.
8830      * @return {Object} The value of the field.
8831      */
8832     get : function(name){
8833         return this.data[name]; 
8834     },
8835
8836     // private
8837     beginEdit : function(){
8838         this.editing = true;
8839         this.modified = {}; 
8840     },
8841
8842     // private
8843     cancelEdit : function(){
8844         this.editing = false;
8845         delete this.modified;
8846     },
8847
8848     // private
8849     endEdit : function(){
8850         this.editing = false;
8851         if(this.dirty && this.store){
8852             this.store.afterEdit(this);
8853         }
8854     },
8855
8856     /**
8857      * Usually called by the {@link Roo.data.Store} which owns the Record.
8858      * Rejects all changes made to the Record since either creation, or the last commit operation.
8859      * Modified fields are reverted to their original values.
8860      * <p>
8861      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8862      * of reject operations.
8863      */
8864     reject : function(){
8865         var m = this.modified;
8866         for(var n in m){
8867             if(typeof m[n] != "function"){
8868                 this.data[n] = m[n];
8869             }
8870         }
8871         this.dirty = false;
8872         delete this.modified;
8873         this.editing = false;
8874         if(this.store){
8875             this.store.afterReject(this);
8876         }
8877     },
8878
8879     /**
8880      * Usually called by the {@link Roo.data.Store} which owns the Record.
8881      * Commits all changes made to the Record since either creation, or the last commit operation.
8882      * <p>
8883      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8884      * of commit operations.
8885      */
8886     commit : function(){
8887         this.dirty = false;
8888         delete this.modified;
8889         this.editing = false;
8890         if(this.store){
8891             this.store.afterCommit(this);
8892         }
8893     },
8894
8895     // private
8896     hasError : function(){
8897         return this.error != null;
8898     },
8899
8900     // private
8901     clearError : function(){
8902         this.error = null;
8903     },
8904
8905     /**
8906      * Creates a copy of this record.
8907      * @param {String} id (optional) A new record id if you don't want to use this record's id
8908      * @return {Record}
8909      */
8910     copy : function(newId) {
8911         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8912     }
8913 };/*
8914  * Based on:
8915  * Ext JS Library 1.1.1
8916  * Copyright(c) 2006-2007, Ext JS, LLC.
8917  *
8918  * Originally Released Under LGPL - original licence link has changed is not relivant.
8919  *
8920  * Fork - LGPL
8921  * <script type="text/javascript">
8922  */
8923
8924
8925
8926 /**
8927  * @class Roo.data.Store
8928  * @extends Roo.util.Observable
8929  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8930  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8931  * <p>
8932  * 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
8933  * has no knowledge of the format of the data returned by the Proxy.<br>
8934  * <p>
8935  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8936  * instances from the data object. These records are cached and made available through accessor functions.
8937  * @constructor
8938  * Creates a new Store.
8939  * @param {Object} config A config object containing the objects needed for the Store to access data,
8940  * and read the data into Records.
8941  */
8942 Roo.data.Store = function(config){
8943     this.data = new Roo.util.MixedCollection(false);
8944     this.data.getKey = function(o){
8945         return o.id;
8946     };
8947     this.baseParams = {};
8948     // private
8949     this.paramNames = {
8950         "start" : "start",
8951         "limit" : "limit",
8952         "sort" : "sort",
8953         "dir" : "dir",
8954         "multisort" : "_multisort"
8955     };
8956
8957     if(config && config.data){
8958         this.inlineData = config.data;
8959         delete config.data;
8960     }
8961
8962     Roo.apply(this, config);
8963     
8964     if(this.reader){ // reader passed
8965         this.reader = Roo.factory(this.reader, Roo.data);
8966         this.reader.xmodule = this.xmodule || false;
8967         if(!this.recordType){
8968             this.recordType = this.reader.recordType;
8969         }
8970         if(this.reader.onMetaChange){
8971             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8972         }
8973     }
8974
8975     if(this.recordType){
8976         this.fields = this.recordType.prototype.fields;
8977     }
8978     this.modified = [];
8979
8980     this.addEvents({
8981         /**
8982          * @event datachanged
8983          * Fires when the data cache has changed, and a widget which is using this Store
8984          * as a Record cache should refresh its view.
8985          * @param {Store} this
8986          */
8987         datachanged : true,
8988         /**
8989          * @event metachange
8990          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8991          * @param {Store} this
8992          * @param {Object} meta The JSON metadata
8993          */
8994         metachange : true,
8995         /**
8996          * @event add
8997          * Fires when Records have been added to the Store
8998          * @param {Store} this
8999          * @param {Roo.data.Record[]} records The array of Records added
9000          * @param {Number} index The index at which the record(s) were added
9001          */
9002         add : true,
9003         /**
9004          * @event remove
9005          * Fires when a Record has been removed from the Store
9006          * @param {Store} this
9007          * @param {Roo.data.Record} record The Record that was removed
9008          * @param {Number} index The index at which the record was removed
9009          */
9010         remove : true,
9011         /**
9012          * @event update
9013          * Fires when a Record has been updated
9014          * @param {Store} this
9015          * @param {Roo.data.Record} record The Record that was updated
9016          * @param {String} operation The update operation being performed.  Value may be one of:
9017          * <pre><code>
9018  Roo.data.Record.EDIT
9019  Roo.data.Record.REJECT
9020  Roo.data.Record.COMMIT
9021          * </code></pre>
9022          */
9023         update : true,
9024         /**
9025          * @event clear
9026          * Fires when the data cache has been cleared.
9027          * @param {Store} this
9028          */
9029         clear : true,
9030         /**
9031          * @event beforeload
9032          * Fires before a request is made for a new data object.  If the beforeload handler returns false
9033          * the load action will be canceled.
9034          * @param {Store} this
9035          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9036          */
9037         beforeload : true,
9038         /**
9039          * @event beforeloadadd
9040          * Fires after a new set of Records has been loaded.
9041          * @param {Store} this
9042          * @param {Roo.data.Record[]} records The Records that were loaded
9043          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9044          */
9045         beforeloadadd : true,
9046         /**
9047          * @event load
9048          * Fires after a new set of Records has been loaded, before they are added to the store.
9049          * @param {Store} this
9050          * @param {Roo.data.Record[]} records The Records that were loaded
9051          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9052          * @params {Object} return from reader
9053          */
9054         load : true,
9055         /**
9056          * @event loadexception
9057          * Fires if an exception occurs in the Proxy during loading.
9058          * Called with the signature of the Proxy's "loadexception" event.
9059          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9060          * 
9061          * @param {Proxy} 
9062          * @param {Object} return from JsonData.reader() - success, totalRecords, records
9063          * @param {Object} load options 
9064          * @param {Object} jsonData from your request (normally this contains the Exception)
9065          */
9066         loadexception : true
9067     });
9068     
9069     if(this.proxy){
9070         this.proxy = Roo.factory(this.proxy, Roo.data);
9071         this.proxy.xmodule = this.xmodule || false;
9072         this.relayEvents(this.proxy,  ["loadexception"]);
9073     }
9074     this.sortToggle = {};
9075     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9076
9077     Roo.data.Store.superclass.constructor.call(this);
9078
9079     if(this.inlineData){
9080         this.loadData(this.inlineData);
9081         delete this.inlineData;
9082     }
9083 };
9084
9085 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9086      /**
9087     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9088     * without a remote query - used by combo/forms at present.
9089     */
9090     
9091     /**
9092     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9093     */
9094     /**
9095     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9096     */
9097     /**
9098     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9099     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9100     */
9101     /**
9102     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9103     * on any HTTP request
9104     */
9105     /**
9106     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9107     */
9108     /**
9109     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9110     */
9111     multiSort: false,
9112     /**
9113     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9114     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9115     */
9116     remoteSort : false,
9117
9118     /**
9119     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9120      * loaded or when a record is removed. (defaults to false).
9121     */
9122     pruneModifiedRecords : false,
9123
9124     // private
9125     lastOptions : null,
9126
9127     /**
9128      * Add Records to the Store and fires the add event.
9129      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9130      */
9131     add : function(records){
9132         records = [].concat(records);
9133         for(var i = 0, len = records.length; i < len; i++){
9134             records[i].join(this);
9135         }
9136         var index = this.data.length;
9137         this.data.addAll(records);
9138         this.fireEvent("add", this, records, index);
9139     },
9140
9141     /**
9142      * Remove a Record from the Store and fires the remove event.
9143      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9144      */
9145     remove : function(record){
9146         var index = this.data.indexOf(record);
9147         this.data.removeAt(index);
9148         if(this.pruneModifiedRecords){
9149             this.modified.remove(record);
9150         }
9151         this.fireEvent("remove", this, record, index);
9152     },
9153
9154     /**
9155      * Remove all Records from the Store and fires the clear event.
9156      */
9157     removeAll : function(){
9158         this.data.clear();
9159         if(this.pruneModifiedRecords){
9160             this.modified = [];
9161         }
9162         this.fireEvent("clear", this);
9163     },
9164
9165     /**
9166      * Inserts Records to the Store at the given index and fires the add event.
9167      * @param {Number} index The start index at which to insert the passed Records.
9168      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9169      */
9170     insert : function(index, records){
9171         records = [].concat(records);
9172         for(var i = 0, len = records.length; i < len; i++){
9173             this.data.insert(index, records[i]);
9174             records[i].join(this);
9175         }
9176         this.fireEvent("add", this, records, index);
9177     },
9178
9179     /**
9180      * Get the index within the cache of the passed Record.
9181      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9182      * @return {Number} The index of the passed Record. Returns -1 if not found.
9183      */
9184     indexOf : function(record){
9185         return this.data.indexOf(record);
9186     },
9187
9188     /**
9189      * Get the index within the cache of the Record with the passed id.
9190      * @param {String} id The id of the Record to find.
9191      * @return {Number} The index of the Record. Returns -1 if not found.
9192      */
9193     indexOfId : function(id){
9194         return this.data.indexOfKey(id);
9195     },
9196
9197     /**
9198      * Get the Record with the specified id.
9199      * @param {String} id The id of the Record to find.
9200      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9201      */
9202     getById : function(id){
9203         return this.data.key(id);
9204     },
9205
9206     /**
9207      * Get the Record at the specified index.
9208      * @param {Number} index The index of the Record to find.
9209      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9210      */
9211     getAt : function(index){
9212         return this.data.itemAt(index);
9213     },
9214
9215     /**
9216      * Returns a range of Records between specified indices.
9217      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9218      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9219      * @return {Roo.data.Record[]} An array of Records
9220      */
9221     getRange : function(start, end){
9222         return this.data.getRange(start, end);
9223     },
9224
9225     // private
9226     storeOptions : function(o){
9227         o = Roo.apply({}, o);
9228         delete o.callback;
9229         delete o.scope;
9230         this.lastOptions = o;
9231     },
9232
9233     /**
9234      * Loads the Record cache from the configured Proxy using the configured Reader.
9235      * <p>
9236      * If using remote paging, then the first load call must specify the <em>start</em>
9237      * and <em>limit</em> properties in the options.params property to establish the initial
9238      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9239      * <p>
9240      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9241      * and this call will return before the new data has been loaded. Perform any post-processing
9242      * in a callback function, or in a "load" event handler.</strong>
9243      * <p>
9244      * @param {Object} options An object containing properties which control loading options:<ul>
9245      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9246      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9247      * passed the following arguments:<ul>
9248      * <li>r : Roo.data.Record[]</li>
9249      * <li>options: Options object from the load call</li>
9250      * <li>success: Boolean success indicator</li></ul></li>
9251      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9252      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9253      * </ul>
9254      */
9255     load : function(options){
9256         options = options || {};
9257         if(this.fireEvent("beforeload", this, options) !== false){
9258             this.storeOptions(options);
9259             var p = Roo.apply(options.params || {}, this.baseParams);
9260             // if meta was not loaded from remote source.. try requesting it.
9261             if (!this.reader.metaFromRemote) {
9262                 p._requestMeta = 1;
9263             }
9264             if(this.sortInfo && this.remoteSort){
9265                 var pn = this.paramNames;
9266                 p[pn["sort"]] = this.sortInfo.field;
9267                 p[pn["dir"]] = this.sortInfo.direction;
9268             }
9269             if (this.multiSort) {
9270                 var pn = this.paramNames;
9271                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9272             }
9273             
9274             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9275         }
9276     },
9277
9278     /**
9279      * Reloads the Record cache from the configured Proxy using the configured Reader and
9280      * the options from the last load operation performed.
9281      * @param {Object} options (optional) An object containing properties which may override the options
9282      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9283      * the most recently used options are reused).
9284      */
9285     reload : function(options){
9286         this.load(Roo.applyIf(options||{}, this.lastOptions));
9287     },
9288
9289     // private
9290     // Called as a callback by the Reader during a load operation.
9291     loadRecords : function(o, options, success){
9292         if(!o || success === false){
9293             if(success !== false){
9294                 this.fireEvent("load", this, [], options, o);
9295             }
9296             if(options.callback){
9297                 options.callback.call(options.scope || this, [], options, false);
9298             }
9299             return;
9300         }
9301         // if data returned failure - throw an exception.
9302         if (o.success === false) {
9303             // show a message if no listener is registered.
9304             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9305                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9306             }
9307             // loadmask wil be hooked into this..
9308             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9309             return;
9310         }
9311         var r = o.records, t = o.totalRecords || r.length;
9312         
9313         this.fireEvent("beforeloadadd", this, r, options, o);
9314         
9315         if(!options || options.add !== true){
9316             if(this.pruneModifiedRecords){
9317                 this.modified = [];
9318             }
9319             for(var i = 0, len = r.length; i < len; i++){
9320                 r[i].join(this);
9321             }
9322             if(this.snapshot){
9323                 this.data = this.snapshot;
9324                 delete this.snapshot;
9325             }
9326             this.data.clear();
9327             this.data.addAll(r);
9328             this.totalLength = t;
9329             this.applySort();
9330             this.fireEvent("datachanged", this);
9331         }else{
9332             this.totalLength = Math.max(t, this.data.length+r.length);
9333             this.add(r);
9334         }
9335         this.fireEvent("load", this, r, options, o);
9336         if(options.callback){
9337             options.callback.call(options.scope || this, r, options, true);
9338         }
9339     },
9340
9341
9342     /**
9343      * Loads data from a passed data block. A Reader which understands the format of the data
9344      * must have been configured in the constructor.
9345      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9346      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9347      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9348      */
9349     loadData : function(o, append){
9350         var r = this.reader.readRecords(o);
9351         this.loadRecords(r, {add: append}, true);
9352     },
9353
9354     /**
9355      * Gets the number of cached records.
9356      * <p>
9357      * <em>If using paging, this may not be the total size of the dataset. If the data object
9358      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9359      * the data set size</em>
9360      */
9361     getCount : function(){
9362         return this.data.length || 0;
9363     },
9364
9365     /**
9366      * Gets the total number of records in the dataset as returned by the server.
9367      * <p>
9368      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9369      * the dataset size</em>
9370      */
9371     getTotalCount : function(){
9372         return this.totalLength || 0;
9373     },
9374
9375     /**
9376      * Returns the sort state of the Store as an object with two properties:
9377      * <pre><code>
9378  field {String} The name of the field by which the Records are sorted
9379  direction {String} The sort order, "ASC" or "DESC"
9380      * </code></pre>
9381      */
9382     getSortState : function(){
9383         return this.sortInfo;
9384     },
9385
9386     // private
9387     applySort : function(){
9388         if(this.sortInfo && !this.remoteSort){
9389             var s = this.sortInfo, f = s.field;
9390             var st = this.fields.get(f).sortType;
9391             var fn = function(r1, r2){
9392                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9393                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9394             };
9395             this.data.sort(s.direction, fn);
9396             if(this.snapshot && this.snapshot != this.data){
9397                 this.snapshot.sort(s.direction, fn);
9398             }
9399         }
9400     },
9401
9402     /**
9403      * Sets the default sort column and order to be used by the next load operation.
9404      * @param {String} fieldName The name of the field to sort by.
9405      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9406      */
9407     setDefaultSort : function(field, dir){
9408         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9409     },
9410
9411     /**
9412      * Sort the Records.
9413      * If remote sorting is used, the sort is performed on the server, and the cache is
9414      * reloaded. If local sorting is used, the cache is sorted internally.
9415      * @param {String} fieldName The name of the field to sort by.
9416      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9417      */
9418     sort : function(fieldName, dir){
9419         var f = this.fields.get(fieldName);
9420         if(!dir){
9421             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9422             
9423             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9424                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9425             }else{
9426                 dir = f.sortDir;
9427             }
9428         }
9429         this.sortToggle[f.name] = dir;
9430         this.sortInfo = {field: f.name, direction: dir};
9431         if(!this.remoteSort){
9432             this.applySort();
9433             this.fireEvent("datachanged", this);
9434         }else{
9435             this.load(this.lastOptions);
9436         }
9437     },
9438
9439     /**
9440      * Calls the specified function for each of the Records in the cache.
9441      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9442      * Returning <em>false</em> aborts and exits the iteration.
9443      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9444      */
9445     each : function(fn, scope){
9446         this.data.each(fn, scope);
9447     },
9448
9449     /**
9450      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9451      * (e.g., during paging).
9452      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9453      */
9454     getModifiedRecords : function(){
9455         return this.modified;
9456     },
9457
9458     // private
9459     createFilterFn : function(property, value, anyMatch){
9460         if(!value.exec){ // not a regex
9461             value = String(value);
9462             if(value.length == 0){
9463                 return false;
9464             }
9465             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9466         }
9467         return function(r){
9468             return value.test(r.data[property]);
9469         };
9470     },
9471
9472     /**
9473      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9474      * @param {String} property A field on your records
9475      * @param {Number} start The record index to start at (defaults to 0)
9476      * @param {Number} end The last record index to include (defaults to length - 1)
9477      * @return {Number} The sum
9478      */
9479     sum : function(property, start, end){
9480         var rs = this.data.items, v = 0;
9481         start = start || 0;
9482         end = (end || end === 0) ? end : rs.length-1;
9483
9484         for(var i = start; i <= end; i++){
9485             v += (rs[i].data[property] || 0);
9486         }
9487         return v;
9488     },
9489
9490     /**
9491      * Filter the records by a specified property.
9492      * @param {String} field A field on your records
9493      * @param {String/RegExp} value Either a string that the field
9494      * should start with or a RegExp to test against the field
9495      * @param {Boolean} anyMatch True to match any part not just the beginning
9496      */
9497     filter : function(property, value, anyMatch){
9498         var fn = this.createFilterFn(property, value, anyMatch);
9499         return fn ? this.filterBy(fn) : this.clearFilter();
9500     },
9501
9502     /**
9503      * Filter by a function. The specified function will be called with each
9504      * record in this data source. If the function returns true the record is included,
9505      * otherwise it is filtered.
9506      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9507      * @param {Object} scope (optional) The scope of the function (defaults to this)
9508      */
9509     filterBy : function(fn, scope){
9510         this.snapshot = this.snapshot || this.data;
9511         this.data = this.queryBy(fn, scope||this);
9512         this.fireEvent("datachanged", this);
9513     },
9514
9515     /**
9516      * Query the records by a specified property.
9517      * @param {String} field A field on your records
9518      * @param {String/RegExp} value Either a string that the field
9519      * should start with or a RegExp to test against the field
9520      * @param {Boolean} anyMatch True to match any part not just the beginning
9521      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9522      */
9523     query : function(property, value, anyMatch){
9524         var fn = this.createFilterFn(property, value, anyMatch);
9525         return fn ? this.queryBy(fn) : this.data.clone();
9526     },
9527
9528     /**
9529      * Query by a function. The specified function will be called with each
9530      * record in this data source. If the function returns true the record is included
9531      * in the results.
9532      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9533      * @param {Object} scope (optional) The scope of the function (defaults to this)
9534       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9535      **/
9536     queryBy : function(fn, scope){
9537         var data = this.snapshot || this.data;
9538         return data.filterBy(fn, scope||this);
9539     },
9540
9541     /**
9542      * Collects unique values for a particular dataIndex from this store.
9543      * @param {String} dataIndex The property to collect
9544      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9545      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9546      * @return {Array} An array of the unique values
9547      **/
9548     collect : function(dataIndex, allowNull, bypassFilter){
9549         var d = (bypassFilter === true && this.snapshot) ?
9550                 this.snapshot.items : this.data.items;
9551         var v, sv, r = [], l = {};
9552         for(var i = 0, len = d.length; i < len; i++){
9553             v = d[i].data[dataIndex];
9554             sv = String(v);
9555             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9556                 l[sv] = true;
9557                 r[r.length] = v;
9558             }
9559         }
9560         return r;
9561     },
9562
9563     /**
9564      * Revert to a view of the Record cache with no filtering applied.
9565      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9566      */
9567     clearFilter : function(suppressEvent){
9568         if(this.snapshot && this.snapshot != this.data){
9569             this.data = this.snapshot;
9570             delete this.snapshot;
9571             if(suppressEvent !== true){
9572                 this.fireEvent("datachanged", this);
9573             }
9574         }
9575     },
9576
9577     // private
9578     afterEdit : function(record){
9579         if(this.modified.indexOf(record) == -1){
9580             this.modified.push(record);
9581         }
9582         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9583     },
9584     
9585     // private
9586     afterReject : function(record){
9587         this.modified.remove(record);
9588         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9589     },
9590
9591     // private
9592     afterCommit : function(record){
9593         this.modified.remove(record);
9594         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9595     },
9596
9597     /**
9598      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9599      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9600      */
9601     commitChanges : function(){
9602         var m = this.modified.slice(0);
9603         this.modified = [];
9604         for(var i = 0, len = m.length; i < len; i++){
9605             m[i].commit();
9606         }
9607     },
9608
9609     /**
9610      * Cancel outstanding changes on all changed records.
9611      */
9612     rejectChanges : function(){
9613         var m = this.modified.slice(0);
9614         this.modified = [];
9615         for(var i = 0, len = m.length; i < len; i++){
9616             m[i].reject();
9617         }
9618     },
9619
9620     onMetaChange : function(meta, rtype, o){
9621         this.recordType = rtype;
9622         this.fields = rtype.prototype.fields;
9623         delete this.snapshot;
9624         this.sortInfo = meta.sortInfo || this.sortInfo;
9625         this.modified = [];
9626         this.fireEvent('metachange', this, this.reader.meta);
9627     },
9628     
9629     moveIndex : function(data, type)
9630     {
9631         var index = this.indexOf(data);
9632         
9633         var newIndex = index + type;
9634         
9635         this.remove(data);
9636         
9637         this.insert(newIndex, data);
9638         
9639     }
9640 });/*
9641  * Based on:
9642  * Ext JS Library 1.1.1
9643  * Copyright(c) 2006-2007, Ext JS, LLC.
9644  *
9645  * Originally Released Under LGPL - original licence link has changed is not relivant.
9646  *
9647  * Fork - LGPL
9648  * <script type="text/javascript">
9649  */
9650
9651 /**
9652  * @class Roo.data.SimpleStore
9653  * @extends Roo.data.Store
9654  * Small helper class to make creating Stores from Array data easier.
9655  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9656  * @cfg {Array} fields An array of field definition objects, or field name strings.
9657  * @cfg {Array} data The multi-dimensional array of data
9658  * @constructor
9659  * @param {Object} config
9660  */
9661 Roo.data.SimpleStore = function(config){
9662     Roo.data.SimpleStore.superclass.constructor.call(this, {
9663         isLocal : true,
9664         reader: new Roo.data.ArrayReader({
9665                 id: config.id
9666             },
9667             Roo.data.Record.create(config.fields)
9668         ),
9669         proxy : new Roo.data.MemoryProxy(config.data)
9670     });
9671     this.load();
9672 };
9673 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9674  * Based on:
9675  * Ext JS Library 1.1.1
9676  * Copyright(c) 2006-2007, Ext JS, LLC.
9677  *
9678  * Originally Released Under LGPL - original licence link has changed is not relivant.
9679  *
9680  * Fork - LGPL
9681  * <script type="text/javascript">
9682  */
9683
9684 /**
9685 /**
9686  * @extends Roo.data.Store
9687  * @class Roo.data.JsonStore
9688  * Small helper class to make creating Stores for JSON data easier. <br/>
9689 <pre><code>
9690 var store = new Roo.data.JsonStore({
9691     url: 'get-images.php',
9692     root: 'images',
9693     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9694 });
9695 </code></pre>
9696  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9697  * JsonReader and HttpProxy (unless inline data is provided).</b>
9698  * @cfg {Array} fields An array of field definition objects, or field name strings.
9699  * @constructor
9700  * @param {Object} config
9701  */
9702 Roo.data.JsonStore = function(c){
9703     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9704         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9705         reader: new Roo.data.JsonReader(c, c.fields)
9706     }));
9707 };
9708 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9709  * Based on:
9710  * Ext JS Library 1.1.1
9711  * Copyright(c) 2006-2007, Ext JS, LLC.
9712  *
9713  * Originally Released Under LGPL - original licence link has changed is not relivant.
9714  *
9715  * Fork - LGPL
9716  * <script type="text/javascript">
9717  */
9718
9719  
9720 Roo.data.Field = function(config){
9721     if(typeof config == "string"){
9722         config = {name: config};
9723     }
9724     Roo.apply(this, config);
9725     
9726     if(!this.type){
9727         this.type = "auto";
9728     }
9729     
9730     var st = Roo.data.SortTypes;
9731     // named sortTypes are supported, here we look them up
9732     if(typeof this.sortType == "string"){
9733         this.sortType = st[this.sortType];
9734     }
9735     
9736     // set default sortType for strings and dates
9737     if(!this.sortType){
9738         switch(this.type){
9739             case "string":
9740                 this.sortType = st.asUCString;
9741                 break;
9742             case "date":
9743                 this.sortType = st.asDate;
9744                 break;
9745             default:
9746                 this.sortType = st.none;
9747         }
9748     }
9749
9750     // define once
9751     var stripRe = /[\$,%]/g;
9752
9753     // prebuilt conversion function for this field, instead of
9754     // switching every time we're reading a value
9755     if(!this.convert){
9756         var cv, dateFormat = this.dateFormat;
9757         switch(this.type){
9758             case "":
9759             case "auto":
9760             case undefined:
9761                 cv = function(v){ return v; };
9762                 break;
9763             case "string":
9764                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9765                 break;
9766             case "int":
9767                 cv = function(v){
9768                     return v !== undefined && v !== null && v !== '' ?
9769                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9770                     };
9771                 break;
9772             case "float":
9773                 cv = function(v){
9774                     return v !== undefined && v !== null && v !== '' ?
9775                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9776                     };
9777                 break;
9778             case "bool":
9779             case "boolean":
9780                 cv = function(v){ return v === true || v === "true" || v == 1; };
9781                 break;
9782             case "date":
9783                 cv = function(v){
9784                     if(!v){
9785                         return '';
9786                     }
9787                     if(v instanceof Date){
9788                         return v;
9789                     }
9790                     if(dateFormat){
9791                         if(dateFormat == "timestamp"){
9792                             return new Date(v*1000);
9793                         }
9794                         return Date.parseDate(v, dateFormat);
9795                     }
9796                     var parsed = Date.parse(v);
9797                     return parsed ? new Date(parsed) : null;
9798                 };
9799              break;
9800             
9801         }
9802         this.convert = cv;
9803     }
9804 };
9805
9806 Roo.data.Field.prototype = {
9807     dateFormat: null,
9808     defaultValue: "",
9809     mapping: null,
9810     sortType : null,
9811     sortDir : "ASC"
9812 };/*
9813  * Based on:
9814  * Ext JS Library 1.1.1
9815  * Copyright(c) 2006-2007, Ext JS, LLC.
9816  *
9817  * Originally Released Under LGPL - original licence link has changed is not relivant.
9818  *
9819  * Fork - LGPL
9820  * <script type="text/javascript">
9821  */
9822  
9823 // Base class for reading structured data from a data source.  This class is intended to be
9824 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9825
9826 /**
9827  * @class Roo.data.DataReader
9828  * Base class for reading structured data from a data source.  This class is intended to be
9829  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9830  */
9831
9832 Roo.data.DataReader = function(meta, recordType){
9833     
9834     this.meta = meta;
9835     
9836     this.recordType = recordType instanceof Array ? 
9837         Roo.data.Record.create(recordType) : recordType;
9838 };
9839
9840 Roo.data.DataReader.prototype = {
9841      /**
9842      * Create an empty record
9843      * @param {Object} data (optional) - overlay some values
9844      * @return {Roo.data.Record} record created.
9845      */
9846     newRow :  function(d) {
9847         var da =  {};
9848         this.recordType.prototype.fields.each(function(c) {
9849             switch( c.type) {
9850                 case 'int' : da[c.name] = 0; break;
9851                 case 'date' : da[c.name] = new Date(); break;
9852                 case 'float' : da[c.name] = 0.0; break;
9853                 case 'boolean' : da[c.name] = false; break;
9854                 default : da[c.name] = ""; break;
9855             }
9856             
9857         });
9858         return new this.recordType(Roo.apply(da, d));
9859     }
9860     
9861 };/*
9862  * Based on:
9863  * Ext JS Library 1.1.1
9864  * Copyright(c) 2006-2007, Ext JS, LLC.
9865  *
9866  * Originally Released Under LGPL - original licence link has changed is not relivant.
9867  *
9868  * Fork - LGPL
9869  * <script type="text/javascript">
9870  */
9871
9872 /**
9873  * @class Roo.data.DataProxy
9874  * @extends Roo.data.Observable
9875  * This class is an abstract base class for implementations which provide retrieval of
9876  * unformatted data objects.<br>
9877  * <p>
9878  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9879  * (of the appropriate type which knows how to parse the data object) to provide a block of
9880  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9881  * <p>
9882  * Custom implementations must implement the load method as described in
9883  * {@link Roo.data.HttpProxy#load}.
9884  */
9885 Roo.data.DataProxy = function(){
9886     this.addEvents({
9887         /**
9888          * @event beforeload
9889          * Fires before a network request is made to retrieve a data object.
9890          * @param {Object} This DataProxy object.
9891          * @param {Object} params The params parameter to the load function.
9892          */
9893         beforeload : true,
9894         /**
9895          * @event load
9896          * Fires before the load method's callback is called.
9897          * @param {Object} This DataProxy object.
9898          * @param {Object} o The data object.
9899          * @param {Object} arg The callback argument object passed to the load function.
9900          */
9901         load : true,
9902         /**
9903          * @event loadexception
9904          * Fires if an Exception occurs during data retrieval.
9905          * @param {Object} This DataProxy object.
9906          * @param {Object} o The data object.
9907          * @param {Object} arg The callback argument object passed to the load function.
9908          * @param {Object} e The Exception.
9909          */
9910         loadexception : true
9911     });
9912     Roo.data.DataProxy.superclass.constructor.call(this);
9913 };
9914
9915 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9916
9917     /**
9918      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9919      */
9920 /*
9921  * Based on:
9922  * Ext JS Library 1.1.1
9923  * Copyright(c) 2006-2007, Ext JS, LLC.
9924  *
9925  * Originally Released Under LGPL - original licence link has changed is not relivant.
9926  *
9927  * Fork - LGPL
9928  * <script type="text/javascript">
9929  */
9930 /**
9931  * @class Roo.data.MemoryProxy
9932  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9933  * to the Reader when its load method is called.
9934  * @constructor
9935  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9936  */
9937 Roo.data.MemoryProxy = function(data){
9938     if (data.data) {
9939         data = data.data;
9940     }
9941     Roo.data.MemoryProxy.superclass.constructor.call(this);
9942     this.data = data;
9943 };
9944
9945 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9946     /**
9947      * Load data from the requested source (in this case an in-memory
9948      * data object passed to the constructor), read the data object into
9949      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9950      * process that block using the passed callback.
9951      * @param {Object} params This parameter is not used by the MemoryProxy class.
9952      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9953      * object into a block of Roo.data.Records.
9954      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9955      * The function must be passed <ul>
9956      * <li>The Record block object</li>
9957      * <li>The "arg" argument from the load function</li>
9958      * <li>A boolean success indicator</li>
9959      * </ul>
9960      * @param {Object} scope The scope in which to call the callback
9961      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9962      */
9963     load : function(params, reader, callback, scope, arg){
9964         params = params || {};
9965         var result;
9966         try {
9967             result = reader.readRecords(this.data);
9968         }catch(e){
9969             this.fireEvent("loadexception", this, arg, null, e);
9970             callback.call(scope, null, arg, false);
9971             return;
9972         }
9973         callback.call(scope, result, arg, true);
9974     },
9975     
9976     // private
9977     update : function(params, records){
9978         
9979     }
9980 });/*
9981  * Based on:
9982  * Ext JS Library 1.1.1
9983  * Copyright(c) 2006-2007, Ext JS, LLC.
9984  *
9985  * Originally Released Under LGPL - original licence link has changed is not relivant.
9986  *
9987  * Fork - LGPL
9988  * <script type="text/javascript">
9989  */
9990 /**
9991  * @class Roo.data.HttpProxy
9992  * @extends Roo.data.DataProxy
9993  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9994  * configured to reference a certain URL.<br><br>
9995  * <p>
9996  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9997  * from which the running page was served.<br><br>
9998  * <p>
9999  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10000  * <p>
10001  * Be aware that to enable the browser to parse an XML document, the server must set
10002  * the Content-Type header in the HTTP response to "text/xml".
10003  * @constructor
10004  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10005  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
10006  * will be used to make the request.
10007  */
10008 Roo.data.HttpProxy = function(conn){
10009     Roo.data.HttpProxy.superclass.constructor.call(this);
10010     // is conn a conn config or a real conn?
10011     this.conn = conn;
10012     this.useAjax = !conn || !conn.events;
10013   
10014 };
10015
10016 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10017     // thse are take from connection...
10018     
10019     /**
10020      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10021      */
10022     /**
10023      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10024      * extra parameters to each request made by this object. (defaults to undefined)
10025      */
10026     /**
10027      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10028      *  to each request made by this object. (defaults to undefined)
10029      */
10030     /**
10031      * @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)
10032      */
10033     /**
10034      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10035      */
10036      /**
10037      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10038      * @type Boolean
10039      */
10040   
10041
10042     /**
10043      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10044      * @type Boolean
10045      */
10046     /**
10047      * Return the {@link Roo.data.Connection} object being used by this Proxy.
10048      * @return {Connection} The Connection object. This object may be used to subscribe to events on
10049      * a finer-grained basis than the DataProxy events.
10050      */
10051     getConnection : function(){
10052         return this.useAjax ? Roo.Ajax : this.conn;
10053     },
10054
10055     /**
10056      * Load data from the configured {@link Roo.data.Connection}, read the data object into
10057      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10058      * process that block using the passed callback.
10059      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10060      * for the request to the remote server.
10061      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10062      * object into a block of Roo.data.Records.
10063      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10064      * The function must be passed <ul>
10065      * <li>The Record block object</li>
10066      * <li>The "arg" argument from the load function</li>
10067      * <li>A boolean success indicator</li>
10068      * </ul>
10069      * @param {Object} scope The scope in which to call the callback
10070      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10071      */
10072     load : function(params, reader, callback, scope, arg){
10073         if(this.fireEvent("beforeload", this, params) !== false){
10074             var  o = {
10075                 params : params || {},
10076                 request: {
10077                     callback : callback,
10078                     scope : scope,
10079                     arg : arg
10080                 },
10081                 reader: reader,
10082                 callback : this.loadResponse,
10083                 scope: this
10084             };
10085             if(this.useAjax){
10086                 Roo.applyIf(o, this.conn);
10087                 if(this.activeRequest){
10088                     Roo.Ajax.abort(this.activeRequest);
10089                 }
10090                 this.activeRequest = Roo.Ajax.request(o);
10091             }else{
10092                 this.conn.request(o);
10093             }
10094         }else{
10095             callback.call(scope||this, null, arg, false);
10096         }
10097     },
10098
10099     // private
10100     loadResponse : function(o, success, response){
10101         delete this.activeRequest;
10102         if(!success){
10103             this.fireEvent("loadexception", this, o, response);
10104             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10105             return;
10106         }
10107         var result;
10108         try {
10109             result = o.reader.read(response);
10110         }catch(e){
10111             this.fireEvent("loadexception", this, o, response, e);
10112             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10113             return;
10114         }
10115         
10116         this.fireEvent("load", this, o, o.request.arg);
10117         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10118     },
10119
10120     // private
10121     update : function(dataSet){
10122
10123     },
10124
10125     // private
10126     updateResponse : function(dataSet){
10127
10128     }
10129 });/*
10130  * Based on:
10131  * Ext JS Library 1.1.1
10132  * Copyright(c) 2006-2007, Ext JS, LLC.
10133  *
10134  * Originally Released Under LGPL - original licence link has changed is not relivant.
10135  *
10136  * Fork - LGPL
10137  * <script type="text/javascript">
10138  */
10139
10140 /**
10141  * @class Roo.data.ScriptTagProxy
10142  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10143  * other than the originating domain of the running page.<br><br>
10144  * <p>
10145  * <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
10146  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10147  * <p>
10148  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10149  * source code that is used as the source inside a &lt;script> tag.<br><br>
10150  * <p>
10151  * In order for the browser to process the returned data, the server must wrap the data object
10152  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10153  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10154  * depending on whether the callback name was passed:
10155  * <p>
10156  * <pre><code>
10157 boolean scriptTag = false;
10158 String cb = request.getParameter("callback");
10159 if (cb != null) {
10160     scriptTag = true;
10161     response.setContentType("text/javascript");
10162 } else {
10163     response.setContentType("application/x-json");
10164 }
10165 Writer out = response.getWriter();
10166 if (scriptTag) {
10167     out.write(cb + "(");
10168 }
10169 out.print(dataBlock.toJsonString());
10170 if (scriptTag) {
10171     out.write(");");
10172 }
10173 </pre></code>
10174  *
10175  * @constructor
10176  * @param {Object} config A configuration object.
10177  */
10178 Roo.data.ScriptTagProxy = function(config){
10179     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10180     Roo.apply(this, config);
10181     this.head = document.getElementsByTagName("head")[0];
10182 };
10183
10184 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10185
10186 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10187     /**
10188      * @cfg {String} url The URL from which to request the data object.
10189      */
10190     /**
10191      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10192      */
10193     timeout : 30000,
10194     /**
10195      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10196      * the server the name of the callback function set up by the load call to process the returned data object.
10197      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10198      * javascript output which calls this named function passing the data object as its only parameter.
10199      */
10200     callbackParam : "callback",
10201     /**
10202      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10203      * name to the request.
10204      */
10205     nocache : true,
10206
10207     /**
10208      * Load data from the configured URL, read the data object into
10209      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10210      * process that block using the passed callback.
10211      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10212      * for the request to the remote server.
10213      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10214      * object into a block of Roo.data.Records.
10215      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10216      * The function must be passed <ul>
10217      * <li>The Record block object</li>
10218      * <li>The "arg" argument from the load function</li>
10219      * <li>A boolean success indicator</li>
10220      * </ul>
10221      * @param {Object} scope The scope in which to call the callback
10222      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10223      */
10224     load : function(params, reader, callback, scope, arg){
10225         if(this.fireEvent("beforeload", this, params) !== false){
10226
10227             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10228
10229             var url = this.url;
10230             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10231             if(this.nocache){
10232                 url += "&_dc=" + (new Date().getTime());
10233             }
10234             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10235             var trans = {
10236                 id : transId,
10237                 cb : "stcCallback"+transId,
10238                 scriptId : "stcScript"+transId,
10239                 params : params,
10240                 arg : arg,
10241                 url : url,
10242                 callback : callback,
10243                 scope : scope,
10244                 reader : reader
10245             };
10246             var conn = this;
10247
10248             window[trans.cb] = function(o){
10249                 conn.handleResponse(o, trans);
10250             };
10251
10252             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10253
10254             if(this.autoAbort !== false){
10255                 this.abort();
10256             }
10257
10258             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10259
10260             var script = document.createElement("script");
10261             script.setAttribute("src", url);
10262             script.setAttribute("type", "text/javascript");
10263             script.setAttribute("id", trans.scriptId);
10264             this.head.appendChild(script);
10265
10266             this.trans = trans;
10267         }else{
10268             callback.call(scope||this, null, arg, false);
10269         }
10270     },
10271
10272     // private
10273     isLoading : function(){
10274         return this.trans ? true : false;
10275     },
10276
10277     /**
10278      * Abort the current server request.
10279      */
10280     abort : function(){
10281         if(this.isLoading()){
10282             this.destroyTrans(this.trans);
10283         }
10284     },
10285
10286     // private
10287     destroyTrans : function(trans, isLoaded){
10288         this.head.removeChild(document.getElementById(trans.scriptId));
10289         clearTimeout(trans.timeoutId);
10290         if(isLoaded){
10291             window[trans.cb] = undefined;
10292             try{
10293                 delete window[trans.cb];
10294             }catch(e){}
10295         }else{
10296             // if hasn't been loaded, wait for load to remove it to prevent script error
10297             window[trans.cb] = function(){
10298                 window[trans.cb] = undefined;
10299                 try{
10300                     delete window[trans.cb];
10301                 }catch(e){}
10302             };
10303         }
10304     },
10305
10306     // private
10307     handleResponse : function(o, trans){
10308         this.trans = false;
10309         this.destroyTrans(trans, true);
10310         var result;
10311         try {
10312             result = trans.reader.readRecords(o);
10313         }catch(e){
10314             this.fireEvent("loadexception", this, o, trans.arg, e);
10315             trans.callback.call(trans.scope||window, null, trans.arg, false);
10316             return;
10317         }
10318         this.fireEvent("load", this, o, trans.arg);
10319         trans.callback.call(trans.scope||window, result, trans.arg, true);
10320     },
10321
10322     // private
10323     handleFailure : function(trans){
10324         this.trans = false;
10325         this.destroyTrans(trans, false);
10326         this.fireEvent("loadexception", this, null, trans.arg);
10327         trans.callback.call(trans.scope||window, null, trans.arg, false);
10328     }
10329 });/*
10330  * Based on:
10331  * Ext JS Library 1.1.1
10332  * Copyright(c) 2006-2007, Ext JS, LLC.
10333  *
10334  * Originally Released Under LGPL - original licence link has changed is not relivant.
10335  *
10336  * Fork - LGPL
10337  * <script type="text/javascript">
10338  */
10339
10340 /**
10341  * @class Roo.data.JsonReader
10342  * @extends Roo.data.DataReader
10343  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10344  * based on mappings in a provided Roo.data.Record constructor.
10345  * 
10346  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10347  * in the reply previously. 
10348  * 
10349  * <p>
10350  * Example code:
10351  * <pre><code>
10352 var RecordDef = Roo.data.Record.create([
10353     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10354     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10355 ]);
10356 var myReader = new Roo.data.JsonReader({
10357     totalProperty: "results",    // The property which contains the total dataset size (optional)
10358     root: "rows",                // The property which contains an Array of row objects
10359     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10360 }, RecordDef);
10361 </code></pre>
10362  * <p>
10363  * This would consume a JSON file like this:
10364  * <pre><code>
10365 { 'results': 2, 'rows': [
10366     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10367     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10368 }
10369 </code></pre>
10370  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10371  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10372  * paged from the remote server.
10373  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10374  * @cfg {String} root name of the property which contains the Array of row objects.
10375  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10376  * @constructor
10377  * Create a new JsonReader
10378  * @param {Object} meta Metadata configuration options
10379  * @param {Object} recordType Either an Array of field definition objects,
10380  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10381  */
10382 Roo.data.JsonReader = function(meta, recordType){
10383     
10384     meta = meta || {};
10385     // set some defaults:
10386     Roo.applyIf(meta, {
10387         totalProperty: 'total',
10388         successProperty : 'success',
10389         root : 'data',
10390         id : 'id'
10391     });
10392     
10393     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10394 };
10395 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10396     
10397     /**
10398      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10399      * Used by Store query builder to append _requestMeta to params.
10400      * 
10401      */
10402     metaFromRemote : false,
10403     /**
10404      * This method is only used by a DataProxy which has retrieved data from a remote server.
10405      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10406      * @return {Object} data A data block which is used by an Roo.data.Store object as
10407      * a cache of Roo.data.Records.
10408      */
10409     read : function(response){
10410         var json = response.responseText;
10411        
10412         var o = /* eval:var:o */ eval("("+json+")");
10413         if(!o) {
10414             throw {message: "JsonReader.read: Json object not found"};
10415         }
10416         
10417         if(o.metaData){
10418             
10419             delete this.ef;
10420             this.metaFromRemote = true;
10421             this.meta = o.metaData;
10422             this.recordType = Roo.data.Record.create(o.metaData.fields);
10423             this.onMetaChange(this.meta, this.recordType, o);
10424         }
10425         return this.readRecords(o);
10426     },
10427
10428     // private function a store will implement
10429     onMetaChange : function(meta, recordType, o){
10430
10431     },
10432
10433     /**
10434          * @ignore
10435          */
10436     simpleAccess: function(obj, subsc) {
10437         return obj[subsc];
10438     },
10439
10440         /**
10441          * @ignore
10442          */
10443     getJsonAccessor: function(){
10444         var re = /[\[\.]/;
10445         return function(expr) {
10446             try {
10447                 return(re.test(expr))
10448                     ? new Function("obj", "return obj." + expr)
10449                     : function(obj){
10450                         return obj[expr];
10451                     };
10452             } catch(e){}
10453             return Roo.emptyFn;
10454         };
10455     }(),
10456
10457     /**
10458      * Create a data block containing Roo.data.Records from an XML document.
10459      * @param {Object} o An object which contains an Array of row objects in the property specified
10460      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10461      * which contains the total size of the dataset.
10462      * @return {Object} data A data block which is used by an Roo.data.Store object as
10463      * a cache of Roo.data.Records.
10464      */
10465     readRecords : function(o){
10466         /**
10467          * After any data loads, the raw JSON data is available for further custom processing.
10468          * @type Object
10469          */
10470         this.o = o;
10471         var s = this.meta, Record = this.recordType,
10472             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10473
10474 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10475         if (!this.ef) {
10476             if(s.totalProperty) {
10477                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10478                 }
10479                 if(s.successProperty) {
10480                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10481                 }
10482                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10483                 if (s.id) {
10484                         var g = this.getJsonAccessor(s.id);
10485                         this.getId = function(rec) {
10486                                 var r = g(rec);  
10487                                 return (r === undefined || r === "") ? null : r;
10488                         };
10489                 } else {
10490                         this.getId = function(){return null;};
10491                 }
10492             this.ef = [];
10493             for(var jj = 0; jj < fl; jj++){
10494                 f = fi[jj];
10495                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10496                 this.ef[jj] = this.getJsonAccessor(map);
10497             }
10498         }
10499
10500         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10501         if(s.totalProperty){
10502             var vt = parseInt(this.getTotal(o), 10);
10503             if(!isNaN(vt)){
10504                 totalRecords = vt;
10505             }
10506         }
10507         if(s.successProperty){
10508             var vs = this.getSuccess(o);
10509             if(vs === false || vs === 'false'){
10510                 success = false;
10511             }
10512         }
10513         var records = [];
10514         for(var i = 0; i < c; i++){
10515                 var n = root[i];
10516             var values = {};
10517             var id = this.getId(n);
10518             for(var j = 0; j < fl; j++){
10519                 f = fi[j];
10520             var v = this.ef[j](n);
10521             if (!f.convert) {
10522                 Roo.log('missing convert for ' + f.name);
10523                 Roo.log(f);
10524                 continue;
10525             }
10526             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10527             }
10528             var record = new Record(values, id);
10529             record.json = n;
10530             records[i] = record;
10531         }
10532         return {
10533             raw : o,
10534             success : success,
10535             records : records,
10536             totalRecords : totalRecords
10537         };
10538     }
10539 });/*
10540  * Based on:
10541  * Ext JS Library 1.1.1
10542  * Copyright(c) 2006-2007, Ext JS, LLC.
10543  *
10544  * Originally Released Under LGPL - original licence link has changed is not relivant.
10545  *
10546  * Fork - LGPL
10547  * <script type="text/javascript">
10548  */
10549
10550 /**
10551  * @class Roo.data.ArrayReader
10552  * @extends Roo.data.DataReader
10553  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10554  * Each element of that Array represents a row of data fields. The
10555  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10556  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10557  * <p>
10558  * Example code:.
10559  * <pre><code>
10560 var RecordDef = Roo.data.Record.create([
10561     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10562     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10563 ]);
10564 var myReader = new Roo.data.ArrayReader({
10565     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10566 }, RecordDef);
10567 </code></pre>
10568  * <p>
10569  * This would consume an Array like this:
10570  * <pre><code>
10571 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10572   </code></pre>
10573  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10574  * @constructor
10575  * Create a new JsonReader
10576  * @param {Object} meta Metadata configuration options.
10577  * @param {Object} recordType Either an Array of field definition objects
10578  * as specified to {@link Roo.data.Record#create},
10579  * or an {@link Roo.data.Record} object
10580  * created using {@link Roo.data.Record#create}.
10581  */
10582 Roo.data.ArrayReader = function(meta, recordType){
10583     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10584 };
10585
10586 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10587     /**
10588      * Create a data block containing Roo.data.Records from an XML document.
10589      * @param {Object} o An Array of row objects which represents the dataset.
10590      * @return {Object} data A data block which is used by an Roo.data.Store object as
10591      * a cache of Roo.data.Records.
10592      */
10593     readRecords : function(o){
10594         var sid = this.meta ? this.meta.id : null;
10595         var recordType = this.recordType, fields = recordType.prototype.fields;
10596         var records = [];
10597         var root = o;
10598             for(var i = 0; i < root.length; i++){
10599                     var n = root[i];
10600                 var values = {};
10601                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10602                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10603                 var f = fields.items[j];
10604                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10605                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10606                 v = f.convert(v);
10607                 values[f.name] = v;
10608             }
10609                 var record = new recordType(values, id);
10610                 record.json = n;
10611                 records[records.length] = record;
10612             }
10613             return {
10614                 records : records,
10615                 totalRecords : records.length
10616             };
10617     }
10618 });/*
10619  * - LGPL
10620  * * 
10621  */
10622
10623 /**
10624  * @class Roo.bootstrap.ComboBox
10625  * @extends Roo.bootstrap.TriggerField
10626  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10627  * @cfg {Boolean} append (true|false) default false
10628  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10629  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10630  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10631  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10632  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10633  * @constructor
10634  * Create a new ComboBox.
10635  * @param {Object} config Configuration options
10636  */
10637 Roo.bootstrap.ComboBox = function(config){
10638     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10639     this.addEvents({
10640         /**
10641          * @event expand
10642          * Fires when the dropdown list is expanded
10643              * @param {Roo.bootstrap.ComboBox} combo This combo box
10644              */
10645         'expand' : true,
10646         /**
10647          * @event collapse
10648          * Fires when the dropdown list is collapsed
10649              * @param {Roo.bootstrap.ComboBox} combo This combo box
10650              */
10651         'collapse' : true,
10652         /**
10653          * @event beforeselect
10654          * Fires before a list item is selected. Return false to cancel the selection.
10655              * @param {Roo.bootstrap.ComboBox} combo This combo box
10656              * @param {Roo.data.Record} record The data record returned from the underlying store
10657              * @param {Number} index The index of the selected item in the dropdown list
10658              */
10659         'beforeselect' : true,
10660         /**
10661          * @event select
10662          * Fires when a list item is selected
10663              * @param {Roo.bootstrap.ComboBox} combo This combo box
10664              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10665              * @param {Number} index The index of the selected item in the dropdown list
10666              */
10667         'select' : true,
10668         /**
10669          * @event beforequery
10670          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10671          * The event object passed has these properties:
10672              * @param {Roo.bootstrap.ComboBox} combo This combo box
10673              * @param {String} query The query
10674              * @param {Boolean} forceAll true to force "all" query
10675              * @param {Boolean} cancel true to cancel the query
10676              * @param {Object} e The query event object
10677              */
10678         'beforequery': true,
10679          /**
10680          * @event add
10681          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10682              * @param {Roo.bootstrap.ComboBox} combo This combo box
10683              */
10684         'add' : true,
10685         /**
10686          * @event edit
10687          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10688              * @param {Roo.bootstrap.ComboBox} combo This combo box
10689              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10690              */
10691         'edit' : true,
10692         /**
10693          * @event remove
10694          * Fires when the remove value from the combobox array
10695              * @param {Roo.bootstrap.ComboBox} combo This combo box
10696              */
10697         'remove' : true
10698         
10699     });
10700     
10701     this.item = [];
10702     this.tickItems = [];
10703     
10704     this.selectedIndex = -1;
10705     if(this.mode == 'local'){
10706         if(config.queryDelay === undefined){
10707             this.queryDelay = 10;
10708         }
10709         if(config.minChars === undefined){
10710             this.minChars = 0;
10711         }
10712     }
10713 };
10714
10715 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10716      
10717     /**
10718      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10719      * rendering into an Roo.Editor, defaults to false)
10720      */
10721     /**
10722      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10723      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10724      */
10725     /**
10726      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10727      */
10728     /**
10729      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10730      * the dropdown list (defaults to undefined, with no header element)
10731      */
10732
10733      /**
10734      * @cfg {String/Roo.Template} tpl The template to use to render the output
10735      */
10736      
10737      /**
10738      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10739      */
10740     listWidth: undefined,
10741     /**
10742      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10743      * mode = 'remote' or 'text' if mode = 'local')
10744      */
10745     displayField: undefined,
10746     /**
10747      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10748      * mode = 'remote' or 'value' if mode = 'local'). 
10749      * Note: use of a valueField requires the user make a selection
10750      * in order for a value to be mapped.
10751      */
10752     valueField: undefined,
10753     
10754     
10755     /**
10756      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10757      * field's data value (defaults to the underlying DOM element's name)
10758      */
10759     hiddenName: undefined,
10760     /**
10761      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10762      */
10763     listClass: '',
10764     /**
10765      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10766      */
10767     selectedClass: 'active',
10768     
10769     /**
10770      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10771      */
10772     shadow:'sides',
10773     /**
10774      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10775      * anchor positions (defaults to 'tl-bl')
10776      */
10777     listAlign: 'tl-bl?',
10778     /**
10779      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10780      */
10781     maxHeight: 300,
10782     /**
10783      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10784      * query specified by the allQuery config option (defaults to 'query')
10785      */
10786     triggerAction: 'query',
10787     /**
10788      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10789      * (defaults to 4, does not apply if editable = false)
10790      */
10791     minChars : 4,
10792     /**
10793      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10794      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10795      */
10796     typeAhead: false,
10797     /**
10798      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10799      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10800      */
10801     queryDelay: 500,
10802     /**
10803      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10804      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10805      */
10806     pageSize: 0,
10807     /**
10808      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10809      * when editable = true (defaults to false)
10810      */
10811     selectOnFocus:false,
10812     /**
10813      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10814      */
10815     queryParam: 'query',
10816     /**
10817      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10818      * when mode = 'remote' (defaults to 'Loading...')
10819      */
10820     loadingText: 'Loading...',
10821     /**
10822      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10823      */
10824     resizable: false,
10825     /**
10826      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10827      */
10828     handleHeight : 8,
10829     /**
10830      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10831      * traditional select (defaults to true)
10832      */
10833     editable: true,
10834     /**
10835      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10836      */
10837     allQuery: '',
10838     /**
10839      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10840      */
10841     mode: 'remote',
10842     /**
10843      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10844      * listWidth has a higher value)
10845      */
10846     minListWidth : 70,
10847     /**
10848      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10849      * allow the user to set arbitrary text into the field (defaults to false)
10850      */
10851     forceSelection:false,
10852     /**
10853      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10854      * if typeAhead = true (defaults to 250)
10855      */
10856     typeAheadDelay : 250,
10857     /**
10858      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10859      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10860      */
10861     valueNotFoundText : undefined,
10862     /**
10863      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10864      */
10865     blockFocus : false,
10866     
10867     /**
10868      * @cfg {Boolean} disableClear Disable showing of clear button.
10869      */
10870     disableClear : false,
10871     /**
10872      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10873      */
10874     alwaysQuery : false,
10875     
10876     /**
10877      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10878      */
10879     multiple : false,
10880     
10881     /**
10882      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10883      */
10884     invalidClass : "has-warning",
10885     
10886     /**
10887      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10888      */
10889     validClass : "has-success",
10890     
10891     //private
10892     addicon : false,
10893     editicon: false,
10894     
10895     page: 0,
10896     hasQuery: false,
10897     append: false,
10898     loadNext: false,
10899     autoFocus : true,
10900     tickable : false,
10901     btnPosition : 'right',
10902     triggerList : true,
10903     showToggleBtn : true,
10904     // element that contains real text value.. (when hidden is used..)
10905     
10906     getAutoCreate : function()
10907     {
10908         var cfg = false;
10909         
10910         /*
10911          *  Normal ComboBox
10912          */
10913         if(!this.tickable){
10914             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10915             return cfg;
10916         }
10917         
10918         /*
10919          *  ComboBox with tickable selections
10920          */
10921              
10922         var align = this.labelAlign || this.parentLabelAlign();
10923         
10924         cfg = {
10925             cls : 'form-group roo-combobox-tickable' //input-group
10926         };
10927         
10928         
10929         var buttons = {
10930             tag : 'div',
10931             cls : 'tickable-buttons',
10932             cn : [
10933                 {
10934                     tag : 'button',
10935                     type : 'button',
10936                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10937                     html : 'Edit'
10938                 },
10939                 {
10940                     tag : 'button',
10941                     type : 'button',
10942                     name : 'ok',
10943                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10944                     html : 'Done'
10945                 },
10946                 {
10947                     tag : 'button',
10948                     type : 'button',
10949                     name : 'cancel',
10950                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10951                     html : 'Cancel'
10952                 }
10953             ]
10954         };
10955         
10956         var _this = this;
10957         Roo.each(buttons.cn, function(c){
10958             if (_this.size) {
10959                 c.cls += ' btn-' + _this.size;
10960             }
10961
10962             if (_this.disabled) {
10963                 c.disabled = true;
10964             }
10965         });
10966         
10967         var box = {
10968             tag: 'div',
10969             cn: [
10970                 {
10971                     tag: 'input',
10972                     type : 'hidden',
10973                     cls: 'form-hidden-field'
10974                 },
10975                 {
10976                     tag: 'ul',
10977                     cls: 'select2-choices',
10978                     cn:[
10979                         {
10980                             tag: 'li',
10981                             cls: 'select2-search-field',
10982                             cn: [
10983
10984                                 buttons
10985                             ]
10986                         }
10987                     ]
10988                 }
10989             ]
10990         }
10991         
10992         var combobox = {
10993             cls: 'select2-container input-group select2-container-multi',
10994             cn: [
10995                 box
10996 //                {
10997 //                    tag: 'ul',
10998 //                    cls: 'typeahead typeahead-long dropdown-menu',
10999 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
11000 //                }
11001             ]
11002         };
11003         
11004         if(this.hasFeedback && !this.allowBlank){
11005             
11006             var feedback = {
11007                 tag: 'span',
11008                 cls: 'glyphicon form-control-feedback'
11009             };
11010
11011             combobox.cn.push(feedback);
11012         }
11013         
11014         if (align ==='left' && this.fieldLabel.length) {
11015             
11016                 Roo.log("left and has label");
11017                 cfg.cn = [
11018                     
11019                     {
11020                         tag: 'label',
11021                         'for' :  id,
11022                         cls : 'control-label col-sm-' + this.labelWidth,
11023                         html : this.fieldLabel
11024                         
11025                     },
11026                     {
11027                         cls : "col-sm-" + (12 - this.labelWidth), 
11028                         cn: [
11029                             combobox
11030                         ]
11031                     }
11032                     
11033                 ];
11034         } else if ( this.fieldLabel.length) {
11035                 Roo.log(" label");
11036                  cfg.cn = [
11037                    
11038                     {
11039                         tag: 'label',
11040                         //cls : 'input-group-addon',
11041                         html : this.fieldLabel
11042                         
11043                     },
11044                     
11045                     combobox
11046                     
11047                 ];
11048
11049         } else {
11050             
11051                 Roo.log(" no label && no align");
11052                 cfg = combobox
11053                      
11054                 
11055         }
11056          
11057         var settings=this;
11058         ['xs','sm','md','lg'].map(function(size){
11059             if (settings[size]) {
11060                 cfg.cls += ' col-' + size + '-' + settings[size];
11061             }
11062         });
11063         
11064         return cfg;
11065         
11066     },
11067     
11068     // private
11069     initEvents: function()
11070     {
11071         
11072         if (!this.store) {
11073             throw "can not find store for combo";
11074         }
11075         this.store = Roo.factory(this.store, Roo.data);
11076         
11077         if(this.tickable){
11078             this.initTickableEvents();
11079             return;
11080         }
11081         
11082         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11083         
11084         if(this.hiddenName){
11085             
11086             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11087             
11088             this.hiddenField.dom.value =
11089                 this.hiddenValue !== undefined ? this.hiddenValue :
11090                 this.value !== undefined ? this.value : '';
11091
11092             // prevent input submission
11093             this.el.dom.removeAttribute('name');
11094             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11095              
11096              
11097         }
11098         //if(Roo.isGecko){
11099         //    this.el.dom.setAttribute('autocomplete', 'off');
11100         //}
11101         
11102         var cls = 'x-combo-list';
11103         
11104         //this.list = new Roo.Layer({
11105         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11106         //});
11107         
11108         var _this = this;
11109         
11110         (function(){
11111             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11112             _this.list.setWidth(lw);
11113         }).defer(100);
11114         
11115         this.list.on('mouseover', this.onViewOver, this);
11116         this.list.on('mousemove', this.onViewMove, this);
11117         
11118         this.list.on('scroll', this.onViewScroll, this);
11119         
11120         /*
11121         this.list.swallowEvent('mousewheel');
11122         this.assetHeight = 0;
11123
11124         if(this.title){
11125             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11126             this.assetHeight += this.header.getHeight();
11127         }
11128
11129         this.innerList = this.list.createChild({cls:cls+'-inner'});
11130         this.innerList.on('mouseover', this.onViewOver, this);
11131         this.innerList.on('mousemove', this.onViewMove, this);
11132         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11133         
11134         if(this.allowBlank && !this.pageSize && !this.disableClear){
11135             this.footer = this.list.createChild({cls:cls+'-ft'});
11136             this.pageTb = new Roo.Toolbar(this.footer);
11137            
11138         }
11139         if(this.pageSize){
11140             this.footer = this.list.createChild({cls:cls+'-ft'});
11141             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11142                     {pageSize: this.pageSize});
11143             
11144         }
11145         
11146         if (this.pageTb && this.allowBlank && !this.disableClear) {
11147             var _this = this;
11148             this.pageTb.add(new Roo.Toolbar.Fill(), {
11149                 cls: 'x-btn-icon x-btn-clear',
11150                 text: '&#160;',
11151                 handler: function()
11152                 {
11153                     _this.collapse();
11154                     _this.clearValue();
11155                     _this.onSelect(false, -1);
11156                 }
11157             });
11158         }
11159         if (this.footer) {
11160             this.assetHeight += this.footer.getHeight();
11161         }
11162         */
11163             
11164         if(!this.tpl){
11165             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11166         }
11167
11168         this.view = new Roo.View(this.list, this.tpl, {
11169             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11170         });
11171         //this.view.wrapEl.setDisplayed(false);
11172         this.view.on('click', this.onViewClick, this);
11173         
11174         
11175         
11176         this.store.on('beforeload', this.onBeforeLoad, this);
11177         this.store.on('load', this.onLoad, this);
11178         this.store.on('loadexception', this.onLoadException, this);
11179         /*
11180         if(this.resizable){
11181             this.resizer = new Roo.Resizable(this.list,  {
11182                pinned:true, handles:'se'
11183             });
11184             this.resizer.on('resize', function(r, w, h){
11185                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11186                 this.listWidth = w;
11187                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11188                 this.restrictHeight();
11189             }, this);
11190             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11191         }
11192         */
11193         if(!this.editable){
11194             this.editable = true;
11195             this.setEditable(false);
11196         }
11197         
11198         /*
11199         
11200         if (typeof(this.events.add.listeners) != 'undefined') {
11201             
11202             this.addicon = this.wrap.createChild(
11203                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11204        
11205             this.addicon.on('click', function(e) {
11206                 this.fireEvent('add', this);
11207             }, this);
11208         }
11209         if (typeof(this.events.edit.listeners) != 'undefined') {
11210             
11211             this.editicon = this.wrap.createChild(
11212                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11213             if (this.addicon) {
11214                 this.editicon.setStyle('margin-left', '40px');
11215             }
11216             this.editicon.on('click', function(e) {
11217                 
11218                 // we fire even  if inothing is selected..
11219                 this.fireEvent('edit', this, this.lastData );
11220                 
11221             }, this);
11222         }
11223         */
11224         
11225         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11226             "up" : function(e){
11227                 this.inKeyMode = true;
11228                 this.selectPrev();
11229             },
11230
11231             "down" : function(e){
11232                 if(!this.isExpanded()){
11233                     this.onTriggerClick();
11234                 }else{
11235                     this.inKeyMode = true;
11236                     this.selectNext();
11237                 }
11238             },
11239
11240             "enter" : function(e){
11241 //                this.onViewClick();
11242                 //return true;
11243                 this.collapse();
11244                 
11245                 if(this.fireEvent("specialkey", this, e)){
11246                     this.onViewClick(false);
11247                 }
11248                 
11249                 return true;
11250             },
11251
11252             "esc" : function(e){
11253                 this.collapse();
11254             },
11255
11256             "tab" : function(e){
11257                 this.collapse();
11258                 
11259                 if(this.fireEvent("specialkey", this, e)){
11260                     this.onViewClick(false);
11261                 }
11262                 
11263                 return true;
11264             },
11265
11266             scope : this,
11267
11268             doRelay : function(foo, bar, hname){
11269                 if(hname == 'down' || this.scope.isExpanded()){
11270                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11271                 }
11272                 return true;
11273             },
11274
11275             forceKeyDown: true
11276         });
11277         
11278         
11279         this.queryDelay = Math.max(this.queryDelay || 10,
11280                 this.mode == 'local' ? 10 : 250);
11281         
11282         
11283         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11284         
11285         if(this.typeAhead){
11286             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11287         }
11288         if(this.editable !== false){
11289             this.inputEl().on("keyup", this.onKeyUp, this);
11290         }
11291         if(this.forceSelection){
11292             this.inputEl().on('blur', this.doForce, this);
11293         }
11294         
11295         if(this.multiple){
11296             this.choices = this.el.select('ul.select2-choices', true).first();
11297             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11298         }
11299     },
11300     
11301     initTickableEvents: function()
11302     {   
11303         this.createList();
11304         
11305         if(this.hiddenName){
11306             
11307             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11308             
11309             this.hiddenField.dom.value =
11310                 this.hiddenValue !== undefined ? this.hiddenValue :
11311                 this.value !== undefined ? this.value : '';
11312
11313             // prevent input submission
11314             this.el.dom.removeAttribute('name');
11315             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11316              
11317              
11318         }
11319         
11320 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11321         
11322         this.choices = this.el.select('ul.select2-choices', true).first();
11323         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11324         if(this.triggerList){
11325             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11326         }
11327          
11328         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11329         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11330         
11331         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11332         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11333         
11334         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11335         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11336         
11337         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11338         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11339         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11340         
11341         this.okBtn.hide();
11342         this.cancelBtn.hide();
11343         
11344         var _this = this;
11345         
11346         (function(){
11347             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11348             _this.list.setWidth(lw);
11349         }).defer(100);
11350         
11351         this.list.on('mouseover', this.onViewOver, this);
11352         this.list.on('mousemove', this.onViewMove, this);
11353         
11354         this.list.on('scroll', this.onViewScroll, this);
11355         
11356         if(!this.tpl){
11357             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>';
11358         }
11359
11360         this.view = new Roo.View(this.list, this.tpl, {
11361             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11362         });
11363         
11364         //this.view.wrapEl.setDisplayed(false);
11365         this.view.on('click', this.onViewClick, this);
11366         
11367         
11368         
11369         this.store.on('beforeload', this.onBeforeLoad, this);
11370         this.store.on('load', this.onLoad, this);
11371         this.store.on('loadexception', this.onLoadException, this);
11372         
11373 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11374 //            "up" : function(e){
11375 //                this.inKeyMode = true;
11376 //                this.selectPrev();
11377 //            },
11378 //
11379 //            "down" : function(e){
11380 //                if(!this.isExpanded()){
11381 //                    this.onTriggerClick();
11382 //                }else{
11383 //                    this.inKeyMode = true;
11384 //                    this.selectNext();
11385 //                }
11386 //            },
11387 //
11388 //            "enter" : function(e){
11389 ////                this.onViewClick();
11390 //                //return true;
11391 //                this.collapse();
11392 //                
11393 //                if(this.fireEvent("specialkey", this, e)){
11394 //                    this.onViewClick(false);
11395 //                }
11396 //                
11397 //                return true;
11398 //            },
11399 //
11400 //            "esc" : function(e){
11401 //                this.collapse();
11402 //            },
11403 //
11404 //            "tab" : function(e){
11405 //                this.collapse();
11406 //                
11407 //                if(this.fireEvent("specialkey", this, e)){
11408 //                    this.onViewClick(false);
11409 //                }
11410 //                
11411 //                return true;
11412 //            },
11413 //
11414 //            scope : this,
11415 //
11416 //            doRelay : function(foo, bar, hname){
11417 //                if(hname == 'down' || this.scope.isExpanded()){
11418 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11419 //                }
11420 //                return true;
11421 //            },
11422 //
11423 //            forceKeyDown: true
11424 //        });
11425         
11426         
11427         this.queryDelay = Math.max(this.queryDelay || 10,
11428                 this.mode == 'local' ? 10 : 250);
11429         
11430         
11431         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11432         
11433         if(this.typeAhead){
11434             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11435         }
11436         
11437     },
11438
11439     onDestroy : function(){
11440         if(this.view){
11441             this.view.setStore(null);
11442             this.view.el.removeAllListeners();
11443             this.view.el.remove();
11444             this.view.purgeListeners();
11445         }
11446         if(this.list){
11447             this.list.dom.innerHTML  = '';
11448         }
11449         
11450         if(this.store){
11451             this.store.un('beforeload', this.onBeforeLoad, this);
11452             this.store.un('load', this.onLoad, this);
11453             this.store.un('loadexception', this.onLoadException, this);
11454         }
11455         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11456     },
11457
11458     // private
11459     fireKey : function(e){
11460         if(e.isNavKeyPress() && !this.list.isVisible()){
11461             this.fireEvent("specialkey", this, e);
11462         }
11463     },
11464
11465     // private
11466     onResize: function(w, h){
11467 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11468 //        
11469 //        if(typeof w != 'number'){
11470 //            // we do not handle it!?!?
11471 //            return;
11472 //        }
11473 //        var tw = this.trigger.getWidth();
11474 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11475 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11476 //        var x = w - tw;
11477 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11478 //            
11479 //        //this.trigger.setStyle('left', x+'px');
11480 //        
11481 //        if(this.list && this.listWidth === undefined){
11482 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11483 //            this.list.setWidth(lw);
11484 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11485 //        }
11486         
11487     
11488         
11489     },
11490
11491     /**
11492      * Allow or prevent the user from directly editing the field text.  If false is passed,
11493      * the user will only be able to select from the items defined in the dropdown list.  This method
11494      * is the runtime equivalent of setting the 'editable' config option at config time.
11495      * @param {Boolean} value True to allow the user to directly edit the field text
11496      */
11497     setEditable : function(value){
11498         if(value == this.editable){
11499             return;
11500         }
11501         this.editable = value;
11502         if(!value){
11503             this.inputEl().dom.setAttribute('readOnly', true);
11504             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11505             this.inputEl().addClass('x-combo-noedit');
11506         }else{
11507             this.inputEl().dom.setAttribute('readOnly', false);
11508             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11509             this.inputEl().removeClass('x-combo-noedit');
11510         }
11511     },
11512
11513     // private
11514     
11515     onBeforeLoad : function(combo,opts){
11516         if(!this.hasFocus){
11517             return;
11518         }
11519          if (!opts.add) {
11520             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11521          }
11522         this.restrictHeight();
11523         this.selectedIndex = -1;
11524     },
11525
11526     // private
11527     onLoad : function(){
11528         
11529         this.hasQuery = false;
11530         
11531         if(!this.hasFocus){
11532             return;
11533         }
11534         
11535         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11536             this.loading.hide();
11537         }
11538         
11539         if(this.store.getCount() > 0){
11540             this.expand();
11541 //            this.restrictHeight();
11542             if(this.lastQuery == this.allQuery){
11543                 if(this.editable && !this.tickable){
11544                     this.inputEl().dom.select();
11545                 }
11546                 
11547                 if(
11548                     !this.selectByValue(this.value, true) &&
11549                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11550                     this.store.lastOptions.add != true)
11551                 ){
11552                     this.select(0, true);
11553                 }
11554             }else{
11555                 if(this.autoFocus){
11556                     this.selectNext();
11557                 }
11558                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11559                     this.taTask.delay(this.typeAheadDelay);
11560                 }
11561             }
11562         }else{
11563             this.onEmptyResults();
11564         }
11565         
11566         //this.el.focus();
11567     },
11568     // private
11569     onLoadException : function()
11570     {
11571         this.hasQuery = false;
11572         
11573         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11574             this.loading.hide();
11575         }
11576         
11577         this.collapse();
11578         Roo.log(this.store.reader.jsonData);
11579         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11580             // fixme
11581             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11582         }
11583         
11584         
11585     },
11586     // private
11587     onTypeAhead : function(){
11588         if(this.store.getCount() > 0){
11589             var r = this.store.getAt(0);
11590             var newValue = r.data[this.displayField];
11591             var len = newValue.length;
11592             var selStart = this.getRawValue().length;
11593             
11594             if(selStart != len){
11595                 this.setRawValue(newValue);
11596                 this.selectText(selStart, newValue.length);
11597             }
11598         }
11599     },
11600
11601     // private
11602     onSelect : function(record, index){
11603         
11604         if(this.fireEvent('beforeselect', this, record, index) !== false){
11605         
11606             this.setFromData(index > -1 ? record.data : false);
11607             
11608             this.collapse();
11609             this.fireEvent('select', this, record, index);
11610         }
11611     },
11612
11613     /**
11614      * Returns the currently selected field value or empty string if no value is set.
11615      * @return {String} value The selected value
11616      */
11617     getValue : function(){
11618         
11619         if(this.multiple){
11620             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11621         }
11622         
11623         if(this.valueField){
11624             return typeof this.value != 'undefined' ? this.value : '';
11625         }else{
11626             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11627         }
11628     },
11629
11630     /**
11631      * Clears any text/value currently set in the field
11632      */
11633     clearValue : function(){
11634         if(this.hiddenField){
11635             this.hiddenField.dom.value = '';
11636         }
11637         this.value = '';
11638         this.setRawValue('');
11639         this.lastSelectionText = '';
11640         this.lastData = false;
11641         
11642     },
11643
11644     /**
11645      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11646      * will be displayed in the field.  If the value does not match the data value of an existing item,
11647      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11648      * Otherwise the field will be blank (although the value will still be set).
11649      * @param {String} value The value to match
11650      */
11651     setValue : function(v){
11652         if(this.multiple){
11653             this.syncValue();
11654             return;
11655         }
11656         
11657         var text = v;
11658         if(this.valueField){
11659             var r = this.findRecord(this.valueField, v);
11660             if(r){
11661                 text = r.data[this.displayField];
11662             }else if(this.valueNotFoundText !== undefined){
11663                 text = this.valueNotFoundText;
11664             }
11665         }
11666         this.lastSelectionText = text;
11667         if(this.hiddenField){
11668             this.hiddenField.dom.value = v;
11669         }
11670         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11671         this.value = v;
11672     },
11673     /**
11674      * @property {Object} the last set data for the element
11675      */
11676     
11677     lastData : false,
11678     /**
11679      * Sets the value of the field based on a object which is related to the record format for the store.
11680      * @param {Object} value the value to set as. or false on reset?
11681      */
11682     setFromData : function(o){
11683         
11684         if(this.multiple){
11685             this.addItem(o);
11686             return;
11687         }
11688             
11689         var dv = ''; // display value
11690         var vv = ''; // value value..
11691         this.lastData = o;
11692         if (this.displayField) {
11693             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11694         } else {
11695             // this is an error condition!!!
11696             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11697         }
11698         
11699         if(this.valueField){
11700             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11701         }
11702         
11703         if(this.hiddenField){
11704             this.hiddenField.dom.value = vv;
11705             
11706             this.lastSelectionText = dv;
11707             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11708             this.value = vv;
11709             return;
11710         }
11711         // no hidden field.. - we store the value in 'value', but still display
11712         // display field!!!!
11713         this.lastSelectionText = dv;
11714         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11715         this.value = vv;
11716         
11717         
11718     },
11719     // private
11720     reset : function(){
11721         // overridden so that last data is reset..
11722         this.setValue(this.originalValue);
11723         this.clearInvalid();
11724         this.lastData = false;
11725         if (this.view) {
11726             this.view.clearSelections();
11727         }
11728     },
11729     // private
11730     findRecord : function(prop, value){
11731         var record;
11732         if(this.store.getCount() > 0){
11733             this.store.each(function(r){
11734                 if(r.data[prop] == value){
11735                     record = r;
11736                     return false;
11737                 }
11738                 return true;
11739             });
11740         }
11741         return record;
11742     },
11743     
11744     getName: function()
11745     {
11746         // returns hidden if it's set..
11747         if (!this.rendered) {return ''};
11748         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11749         
11750     },
11751     // private
11752     onViewMove : function(e, t){
11753         this.inKeyMode = false;
11754     },
11755
11756     // private
11757     onViewOver : function(e, t){
11758         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11759             return;
11760         }
11761         var item = this.view.findItemFromChild(t);
11762         
11763         if(item){
11764             var index = this.view.indexOf(item);
11765             this.select(index, false);
11766         }
11767     },
11768
11769     // private
11770     onViewClick : function(view, doFocus, el, e)
11771     {
11772         var index = this.view.getSelectedIndexes()[0];
11773         
11774         var r = this.store.getAt(index);
11775         
11776         if(this.tickable){
11777             
11778             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11779                 return;
11780             }
11781             
11782             var rm = false;
11783             var _this = this;
11784             
11785             Roo.each(this.tickItems, function(v,k){
11786                 
11787                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11788                     _this.tickItems.splice(k, 1);
11789                     rm = true;
11790                     return;
11791                 }
11792             });
11793             
11794             if(rm){
11795                 return;
11796             }
11797             
11798             this.tickItems.push(r.data);
11799             return;
11800         }
11801         
11802         if(r){
11803             this.onSelect(r, index);
11804         }
11805         if(doFocus !== false && !this.blockFocus){
11806             this.inputEl().focus();
11807         }
11808     },
11809
11810     // private
11811     restrictHeight : function(){
11812         //this.innerList.dom.style.height = '';
11813         //var inner = this.innerList.dom;
11814         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11815         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11816         //this.list.beginUpdate();
11817         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11818         this.list.alignTo(this.inputEl(), this.listAlign);
11819         this.list.alignTo(this.inputEl(), this.listAlign);
11820         //this.list.endUpdate();
11821     },
11822
11823     // private
11824     onEmptyResults : function(){
11825         this.collapse();
11826     },
11827
11828     /**
11829      * Returns true if the dropdown list is expanded, else false.
11830      */
11831     isExpanded : function(){
11832         return this.list.isVisible();
11833     },
11834
11835     /**
11836      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11837      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11838      * @param {String} value The data value of the item to select
11839      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11840      * selected item if it is not currently in view (defaults to true)
11841      * @return {Boolean} True if the value matched an item in the list, else false
11842      */
11843     selectByValue : function(v, scrollIntoView){
11844         if(v !== undefined && v !== null){
11845             var r = this.findRecord(this.valueField || this.displayField, v);
11846             if(r){
11847                 this.select(this.store.indexOf(r), scrollIntoView);
11848                 return true;
11849             }
11850         }
11851         return false;
11852     },
11853
11854     /**
11855      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11856      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11857      * @param {Number} index The zero-based index of the list item to select
11858      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11859      * selected item if it is not currently in view (defaults to true)
11860      */
11861     select : function(index, scrollIntoView){
11862         this.selectedIndex = index;
11863         this.view.select(index);
11864         if(scrollIntoView !== false){
11865             var el = this.view.getNode(index);
11866             if(el && !this.multiple && !this.tickable){
11867                 this.list.scrollChildIntoView(el, false);
11868             }
11869         }
11870     },
11871
11872     // private
11873     selectNext : function(){
11874         var ct = this.store.getCount();
11875         if(ct > 0){
11876             if(this.selectedIndex == -1){
11877                 this.select(0);
11878             }else if(this.selectedIndex < ct-1){
11879                 this.select(this.selectedIndex+1);
11880             }
11881         }
11882     },
11883
11884     // private
11885     selectPrev : function(){
11886         var ct = this.store.getCount();
11887         if(ct > 0){
11888             if(this.selectedIndex == -1){
11889                 this.select(0);
11890             }else if(this.selectedIndex != 0){
11891                 this.select(this.selectedIndex-1);
11892             }
11893         }
11894     },
11895
11896     // private
11897     onKeyUp : function(e){
11898         if(this.editable !== false && !e.isSpecialKey()){
11899             this.lastKey = e.getKey();
11900             this.dqTask.delay(this.queryDelay);
11901         }
11902     },
11903
11904     // private
11905     validateBlur : function(){
11906         return !this.list || !this.list.isVisible();   
11907     },
11908
11909     // private
11910     initQuery : function(){
11911         this.doQuery(this.getRawValue());
11912     },
11913
11914     // private
11915     doForce : function(){
11916         if(this.inputEl().dom.value.length > 0){
11917             this.inputEl().dom.value =
11918                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11919              
11920         }
11921     },
11922
11923     /**
11924      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11925      * query allowing the query action to be canceled if needed.
11926      * @param {String} query The SQL query to execute
11927      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11928      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11929      * saved in the current store (defaults to false)
11930      */
11931     doQuery : function(q, forceAll){
11932         
11933         if(q === undefined || q === null){
11934             q = '';
11935         }
11936         var qe = {
11937             query: q,
11938             forceAll: forceAll,
11939             combo: this,
11940             cancel:false
11941         };
11942         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11943             return false;
11944         }
11945         q = qe.query;
11946         
11947         forceAll = qe.forceAll;
11948         if(forceAll === true || (q.length >= this.minChars)){
11949             
11950             this.hasQuery = true;
11951             
11952             if(this.lastQuery != q || this.alwaysQuery){
11953                 this.lastQuery = q;
11954                 if(this.mode == 'local'){
11955                     this.selectedIndex = -1;
11956                     if(forceAll){
11957                         this.store.clearFilter();
11958                     }else{
11959                         this.store.filter(this.displayField, q);
11960                     }
11961                     this.onLoad();
11962                 }else{
11963                     this.store.baseParams[this.queryParam] = q;
11964                     
11965                     var options = {params : this.getParams(q)};
11966                     
11967                     if(this.loadNext){
11968                         options.add = true;
11969                         options.params.start = this.page * this.pageSize;
11970                     }
11971                     
11972                     this.store.load(options);
11973                     /*
11974                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11975                      *  we should expand the list on onLoad
11976                      *  so command out it
11977                      */
11978 //                    this.expand();
11979                 }
11980             }else{
11981                 this.selectedIndex = -1;
11982                 this.onLoad();   
11983             }
11984         }
11985         
11986         this.loadNext = false;
11987     },
11988
11989     // private
11990     getParams : function(q){
11991         var p = {};
11992         //p[this.queryParam] = q;
11993         
11994         if(this.pageSize){
11995             p.start = 0;
11996             p.limit = this.pageSize;
11997         }
11998         return p;
11999     },
12000
12001     /**
12002      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12003      */
12004     collapse : function(){
12005         if(!this.isExpanded()){
12006             return;
12007         }
12008         
12009         this.list.hide();
12010         
12011         if(this.tickable){
12012             this.hasFocus = false;
12013             this.okBtn.hide();
12014             this.cancelBtn.hide();
12015             this.trigger.show();
12016         }
12017         
12018         Roo.get(document).un('mousedown', this.collapseIf, this);
12019         Roo.get(document).un('mousewheel', this.collapseIf, this);
12020         if (!this.editable) {
12021             Roo.get(document).un('keydown', this.listKeyPress, this);
12022         }
12023         this.fireEvent('collapse', this);
12024     },
12025
12026     // private
12027     collapseIf : function(e){
12028         var in_combo  = e.within(this.el);
12029         var in_list =  e.within(this.list);
12030         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12031         
12032         if (in_combo || in_list || is_list) {
12033             //e.stopPropagation();
12034             return;
12035         }
12036         
12037         if(this.tickable){
12038             this.onTickableFooterButtonClick(e, false, false);
12039         }
12040
12041         this.collapse();
12042         
12043     },
12044
12045     /**
12046      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12047      */
12048     expand : function(){
12049        
12050         if(this.isExpanded() || !this.hasFocus){
12051             return;
12052         }
12053         
12054         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12055         this.list.setWidth(lw);
12056         
12057         
12058          Roo.log('expand');
12059         
12060         this.list.show();
12061         
12062         this.restrictHeight();
12063         
12064         if(this.tickable){
12065             
12066             this.tickItems = Roo.apply([], this.item);
12067             
12068             this.okBtn.show();
12069             this.cancelBtn.show();
12070             this.trigger.hide();
12071             
12072         }
12073         
12074         Roo.get(document).on('mousedown', this.collapseIf, this);
12075         Roo.get(document).on('mousewheel', this.collapseIf, this);
12076         if (!this.editable) {
12077             Roo.get(document).on('keydown', this.listKeyPress, this);
12078         }
12079         
12080         this.fireEvent('expand', this);
12081     },
12082
12083     // private
12084     // Implements the default empty TriggerField.onTriggerClick function
12085     onTriggerClick : function(e)
12086     {
12087         Roo.log('trigger click');
12088         
12089         if(this.disabled || !this.triggerList){
12090             return;
12091         }
12092         
12093         this.page = 0;
12094         this.loadNext = false;
12095         
12096         if(this.isExpanded()){
12097             this.collapse();
12098             if (!this.blockFocus) {
12099                 this.inputEl().focus();
12100             }
12101             
12102         }else {
12103             this.hasFocus = true;
12104             if(this.triggerAction == 'all') {
12105                 this.doQuery(this.allQuery, true);
12106             } else {
12107                 this.doQuery(this.getRawValue());
12108             }
12109             if (!this.blockFocus) {
12110                 this.inputEl().focus();
12111             }
12112         }
12113     },
12114     
12115     onTickableTriggerClick : function(e)
12116     {
12117         if(this.disabled){
12118             return;
12119         }
12120         
12121         this.page = 0;
12122         this.loadNext = false;
12123         this.hasFocus = true;
12124         
12125         if(this.triggerAction == 'all') {
12126             this.doQuery(this.allQuery, true);
12127         } else {
12128             this.doQuery(this.getRawValue());
12129         }
12130     },
12131     
12132     onSearchFieldClick : function(e)
12133     {
12134         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12135             this.onTickableFooterButtonClick(e, false, false);
12136             return;
12137         }
12138         
12139         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12140             return;
12141         }
12142         
12143         this.page = 0;
12144         this.loadNext = false;
12145         this.hasFocus = true;
12146         
12147         if(this.triggerAction == 'all') {
12148             this.doQuery(this.allQuery, true);
12149         } else {
12150             this.doQuery(this.getRawValue());
12151         }
12152     },
12153     
12154     listKeyPress : function(e)
12155     {
12156         //Roo.log('listkeypress');
12157         // scroll to first matching element based on key pres..
12158         if (e.isSpecialKey()) {
12159             return false;
12160         }
12161         var k = String.fromCharCode(e.getKey()).toUpperCase();
12162         //Roo.log(k);
12163         var match  = false;
12164         var csel = this.view.getSelectedNodes();
12165         var cselitem = false;
12166         if (csel.length) {
12167             var ix = this.view.indexOf(csel[0]);
12168             cselitem  = this.store.getAt(ix);
12169             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12170                 cselitem = false;
12171             }
12172             
12173         }
12174         
12175         this.store.each(function(v) { 
12176             if (cselitem) {
12177                 // start at existing selection.
12178                 if (cselitem.id == v.id) {
12179                     cselitem = false;
12180                 }
12181                 return true;
12182             }
12183                 
12184             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12185                 match = this.store.indexOf(v);
12186                 return false;
12187             }
12188             return true;
12189         }, this);
12190         
12191         if (match === false) {
12192             return true; // no more action?
12193         }
12194         // scroll to?
12195         this.view.select(match);
12196         var sn = Roo.get(this.view.getSelectedNodes()[0])
12197         sn.scrollIntoView(sn.dom.parentNode, false);
12198     },
12199     
12200     onViewScroll : function(e, t){
12201         
12202         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){
12203             return;
12204         }
12205         
12206         this.hasQuery = true;
12207         
12208         this.loading = this.list.select('.loading', true).first();
12209         
12210         if(this.loading === null){
12211             this.list.createChild({
12212                 tag: 'div',
12213                 cls: 'loading select2-more-results select2-active',
12214                 html: 'Loading more results...'
12215             })
12216             
12217             this.loading = this.list.select('.loading', true).first();
12218             
12219             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12220             
12221             this.loading.hide();
12222         }
12223         
12224         this.loading.show();
12225         
12226         var _combo = this;
12227         
12228         this.page++;
12229         this.loadNext = true;
12230         
12231         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12232         
12233         return;
12234     },
12235     
12236     addItem : function(o)
12237     {   
12238         var dv = ''; // display value
12239         
12240         if (this.displayField) {
12241             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12242         } else {
12243             // this is an error condition!!!
12244             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12245         }
12246         
12247         if(!dv.length){
12248             return;
12249         }
12250         
12251         var choice = this.choices.createChild({
12252             tag: 'li',
12253             cls: 'select2-search-choice',
12254             cn: [
12255                 {
12256                     tag: 'div',
12257                     html: dv
12258                 },
12259                 {
12260                     tag: 'a',
12261                     href: '#',
12262                     cls: 'select2-search-choice-close',
12263                     tabindex: '-1'
12264                 }
12265             ]
12266             
12267         }, this.searchField);
12268         
12269         var close = choice.select('a.select2-search-choice-close', true).first()
12270         
12271         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12272         
12273         this.item.push(o);
12274         
12275         this.lastData = o;
12276         
12277         this.syncValue();
12278         
12279         this.inputEl().dom.value = '';
12280         
12281         this.validate();
12282     },
12283     
12284     onRemoveItem : function(e, _self, o)
12285     {
12286         e.preventDefault();
12287         
12288         this.lastItem = Roo.apply([], this.item);
12289         
12290         var index = this.item.indexOf(o.data) * 1;
12291         
12292         if( index < 0){
12293             Roo.log('not this item?!');
12294             return;
12295         }
12296         
12297         this.item.splice(index, 1);
12298         o.item.remove();
12299         
12300         this.syncValue();
12301         
12302         this.fireEvent('remove', this, e);
12303         
12304         this.validate();
12305         
12306     },
12307     
12308     syncValue : function()
12309     {
12310         if(!this.item.length){
12311             this.clearValue();
12312             return;
12313         }
12314             
12315         var value = [];
12316         var _this = this;
12317         Roo.each(this.item, function(i){
12318             if(_this.valueField){
12319                 value.push(i[_this.valueField]);
12320                 return;
12321             }
12322
12323             value.push(i);
12324         });
12325
12326         this.value = value.join(',');
12327
12328         if(this.hiddenField){
12329             this.hiddenField.dom.value = this.value;
12330         }
12331     },
12332     
12333     clearItem : function()
12334     {
12335         if(!this.multiple){
12336             return;
12337         }
12338         
12339         this.item = [];
12340         
12341         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12342            c.remove();
12343         });
12344         
12345         this.syncValue();
12346         
12347         this.validate();
12348     },
12349     
12350     inputEl: function ()
12351     {
12352         if(this.tickable){
12353             return this.searchField;
12354         }
12355         return this.el.select('input.form-control',true).first();
12356     },
12357     
12358     
12359     onTickableFooterButtonClick : function(e, btn, el)
12360     {
12361         e.preventDefault();
12362         
12363         this.lastItem = Roo.apply([], this.item);
12364         
12365         if(btn && btn.name == 'cancel'){
12366             this.tickItems = Roo.apply([], this.item);
12367             this.collapse();
12368             return;
12369         }
12370         
12371         this.clearItem();
12372         
12373         var _this = this;
12374         
12375         Roo.each(this.tickItems, function(o){
12376             _this.addItem(o);
12377         });
12378         
12379         this.collapse();
12380         
12381     },
12382     
12383     validate : function()
12384     {
12385         var v = this.getRawValue();
12386         
12387         if(this.multiple){
12388             v = this.getValue();
12389         }
12390         
12391         if(this.disabled || this.allowBlank || v.length){
12392             this.markValid();
12393             return true;
12394         }
12395         
12396         this.markInvalid();
12397         return false;
12398     }
12399     
12400     
12401
12402     /** 
12403     * @cfg {Boolean} grow 
12404     * @hide 
12405     */
12406     /** 
12407     * @cfg {Number} growMin 
12408     * @hide 
12409     */
12410     /** 
12411     * @cfg {Number} growMax 
12412     * @hide 
12413     */
12414     /**
12415      * @hide
12416      * @method autoSize
12417      */
12418 });
12419 /*
12420  * Based on:
12421  * Ext JS Library 1.1.1
12422  * Copyright(c) 2006-2007, Ext JS, LLC.
12423  *
12424  * Originally Released Under LGPL - original licence link has changed is not relivant.
12425  *
12426  * Fork - LGPL
12427  * <script type="text/javascript">
12428  */
12429
12430 /**
12431  * @class Roo.View
12432  * @extends Roo.util.Observable
12433  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12434  * This class also supports single and multi selection modes. <br>
12435  * Create a data model bound view:
12436  <pre><code>
12437  var store = new Roo.data.Store(...);
12438
12439  var view = new Roo.View({
12440     el : "my-element",
12441     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12442  
12443     singleSelect: true,
12444     selectedClass: "ydataview-selected",
12445     store: store
12446  });
12447
12448  // listen for node click?
12449  view.on("click", function(vw, index, node, e){
12450  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12451  });
12452
12453  // load XML data
12454  dataModel.load("foobar.xml");
12455  </code></pre>
12456  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12457  * <br><br>
12458  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12459  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12460  * 
12461  * Note: old style constructor is still suported (container, template, config)
12462  * 
12463  * @constructor
12464  * Create a new View
12465  * @param {Object} config The config object
12466  * 
12467  */
12468 Roo.View = function(config, depreciated_tpl, depreciated_config){
12469     
12470     this.parent = false;
12471     
12472     if (typeof(depreciated_tpl) == 'undefined') {
12473         // new way.. - universal constructor.
12474         Roo.apply(this, config);
12475         this.el  = Roo.get(this.el);
12476     } else {
12477         // old format..
12478         this.el  = Roo.get(config);
12479         this.tpl = depreciated_tpl;
12480         Roo.apply(this, depreciated_config);
12481     }
12482     this.wrapEl  = this.el.wrap().wrap();
12483     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12484     
12485     
12486     if(typeof(this.tpl) == "string"){
12487         this.tpl = new Roo.Template(this.tpl);
12488     } else {
12489         // support xtype ctors..
12490         this.tpl = new Roo.factory(this.tpl, Roo);
12491     }
12492     
12493     
12494     this.tpl.compile();
12495     
12496     /** @private */
12497     this.addEvents({
12498         /**
12499          * @event beforeclick
12500          * Fires before a click is processed. Returns false to cancel the default action.
12501          * @param {Roo.View} this
12502          * @param {Number} index The index of the target node
12503          * @param {HTMLElement} node The target node
12504          * @param {Roo.EventObject} e The raw event object
12505          */
12506             "beforeclick" : true,
12507         /**
12508          * @event click
12509          * Fires when a template node is clicked.
12510          * @param {Roo.View} this
12511          * @param {Number} index The index of the target node
12512          * @param {HTMLElement} node The target node
12513          * @param {Roo.EventObject} e The raw event object
12514          */
12515             "click" : true,
12516         /**
12517          * @event dblclick
12518          * Fires when a template node is double clicked.
12519          * @param {Roo.View} this
12520          * @param {Number} index The index of the target node
12521          * @param {HTMLElement} node The target node
12522          * @param {Roo.EventObject} e The raw event object
12523          */
12524             "dblclick" : true,
12525         /**
12526          * @event contextmenu
12527          * Fires when a template node is right clicked.
12528          * @param {Roo.View} this
12529          * @param {Number} index The index of the target node
12530          * @param {HTMLElement} node The target node
12531          * @param {Roo.EventObject} e The raw event object
12532          */
12533             "contextmenu" : true,
12534         /**
12535          * @event selectionchange
12536          * Fires when the selected nodes change.
12537          * @param {Roo.View} this
12538          * @param {Array} selections Array of the selected nodes
12539          */
12540             "selectionchange" : true,
12541     
12542         /**
12543          * @event beforeselect
12544          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12545          * @param {Roo.View} this
12546          * @param {HTMLElement} node The node to be selected
12547          * @param {Array} selections Array of currently selected nodes
12548          */
12549             "beforeselect" : true,
12550         /**
12551          * @event preparedata
12552          * Fires on every row to render, to allow you to change the data.
12553          * @param {Roo.View} this
12554          * @param {Object} data to be rendered (change this)
12555          */
12556           "preparedata" : true
12557           
12558           
12559         });
12560
12561
12562
12563     this.el.on({
12564         "click": this.onClick,
12565         "dblclick": this.onDblClick,
12566         "contextmenu": this.onContextMenu,
12567         scope:this
12568     });
12569
12570     this.selections = [];
12571     this.nodes = [];
12572     this.cmp = new Roo.CompositeElementLite([]);
12573     if(this.store){
12574         this.store = Roo.factory(this.store, Roo.data);
12575         this.setStore(this.store, true);
12576     }
12577     
12578     if ( this.footer && this.footer.xtype) {
12579            
12580          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12581         
12582         this.footer.dataSource = this.store
12583         this.footer.container = fctr;
12584         this.footer = Roo.factory(this.footer, Roo);
12585         fctr.insertFirst(this.el);
12586         
12587         // this is a bit insane - as the paging toolbar seems to detach the el..
12588 //        dom.parentNode.parentNode.parentNode
12589          // they get detached?
12590     }
12591     
12592     
12593     Roo.View.superclass.constructor.call(this);
12594     
12595     
12596 };
12597
12598 Roo.extend(Roo.View, Roo.util.Observable, {
12599     
12600      /**
12601      * @cfg {Roo.data.Store} store Data store to load data from.
12602      */
12603     store : false,
12604     
12605     /**
12606      * @cfg {String|Roo.Element} el The container element.
12607      */
12608     el : '',
12609     
12610     /**
12611      * @cfg {String|Roo.Template} tpl The template used by this View 
12612      */
12613     tpl : false,
12614     /**
12615      * @cfg {String} dataName the named area of the template to use as the data area
12616      *                          Works with domtemplates roo-name="name"
12617      */
12618     dataName: false,
12619     /**
12620      * @cfg {String} selectedClass The css class to add to selected nodes
12621      */
12622     selectedClass : "x-view-selected",
12623      /**
12624      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12625      */
12626     emptyText : "",
12627     
12628     /**
12629      * @cfg {String} text to display on mask (default Loading)
12630      */
12631     mask : false,
12632     /**
12633      * @cfg {Boolean} multiSelect Allow multiple selection
12634      */
12635     multiSelect : false,
12636     /**
12637      * @cfg {Boolean} singleSelect Allow single selection
12638      */
12639     singleSelect:  false,
12640     
12641     /**
12642      * @cfg {Boolean} toggleSelect - selecting 
12643      */
12644     toggleSelect : false,
12645     
12646     /**
12647      * @cfg {Boolean} tickable - selecting 
12648      */
12649     tickable : false,
12650     
12651     /**
12652      * Returns the element this view is bound to.
12653      * @return {Roo.Element}
12654      */
12655     getEl : function(){
12656         return this.wrapEl;
12657     },
12658     
12659     
12660
12661     /**
12662      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12663      */
12664     refresh : function(){
12665         //Roo.log('refresh');
12666         var t = this.tpl;
12667         
12668         // if we are using something like 'domtemplate', then
12669         // the what gets used is:
12670         // t.applySubtemplate(NAME, data, wrapping data..)
12671         // the outer template then get' applied with
12672         //     the store 'extra data'
12673         // and the body get's added to the
12674         //      roo-name="data" node?
12675         //      <span class='roo-tpl-{name}'></span> ?????
12676         
12677         
12678         
12679         this.clearSelections();
12680         this.el.update("");
12681         var html = [];
12682         var records = this.store.getRange();
12683         if(records.length < 1) {
12684             
12685             // is this valid??  = should it render a template??
12686             
12687             this.el.update(this.emptyText);
12688             return;
12689         }
12690         var el = this.el;
12691         if (this.dataName) {
12692             this.el.update(t.apply(this.store.meta)); //????
12693             el = this.el.child('.roo-tpl-' + this.dataName);
12694         }
12695         
12696         for(var i = 0, len = records.length; i < len; i++){
12697             var data = this.prepareData(records[i].data, i, records[i]);
12698             this.fireEvent("preparedata", this, data, i, records[i]);
12699             
12700             var d = Roo.apply({}, data);
12701             
12702             if(this.tickable){
12703                 Roo.apply(d, {'roo-id' : Roo.id()});
12704                 
12705                 var _this = this;
12706             
12707                 Roo.each(this.parent.item, function(item){
12708                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12709                         return;
12710                     }
12711                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12712                 });
12713             }
12714             
12715             html[html.length] = Roo.util.Format.trim(
12716                 this.dataName ?
12717                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12718                     t.apply(d)
12719             );
12720         }
12721         
12722         
12723         
12724         el.update(html.join(""));
12725         this.nodes = el.dom.childNodes;
12726         this.updateIndexes(0);
12727     },
12728     
12729
12730     /**
12731      * Function to override to reformat the data that is sent to
12732      * the template for each node.
12733      * DEPRICATED - use the preparedata event handler.
12734      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12735      * a JSON object for an UpdateManager bound view).
12736      */
12737     prepareData : function(data, index, record)
12738     {
12739         this.fireEvent("preparedata", this, data, index, record);
12740         return data;
12741     },
12742
12743     onUpdate : function(ds, record){
12744         // Roo.log('on update');   
12745         this.clearSelections();
12746         var index = this.store.indexOf(record);
12747         var n = this.nodes[index];
12748         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12749         n.parentNode.removeChild(n);
12750         this.updateIndexes(index, index);
12751     },
12752
12753     
12754     
12755 // --------- FIXME     
12756     onAdd : function(ds, records, index)
12757     {
12758         //Roo.log(['on Add', ds, records, index] );        
12759         this.clearSelections();
12760         if(this.nodes.length == 0){
12761             this.refresh();
12762             return;
12763         }
12764         var n = this.nodes[index];
12765         for(var i = 0, len = records.length; i < len; i++){
12766             var d = this.prepareData(records[i].data, i, records[i]);
12767             if(n){
12768                 this.tpl.insertBefore(n, d);
12769             }else{
12770                 
12771                 this.tpl.append(this.el, d);
12772             }
12773         }
12774         this.updateIndexes(index);
12775     },
12776
12777     onRemove : function(ds, record, index){
12778        // Roo.log('onRemove');
12779         this.clearSelections();
12780         var el = this.dataName  ?
12781             this.el.child('.roo-tpl-' + this.dataName) :
12782             this.el; 
12783         
12784         el.dom.removeChild(this.nodes[index]);
12785         this.updateIndexes(index);
12786     },
12787
12788     /**
12789      * Refresh an individual node.
12790      * @param {Number} index
12791      */
12792     refreshNode : function(index){
12793         this.onUpdate(this.store, this.store.getAt(index));
12794     },
12795
12796     updateIndexes : function(startIndex, endIndex){
12797         var ns = this.nodes;
12798         startIndex = startIndex || 0;
12799         endIndex = endIndex || ns.length - 1;
12800         for(var i = startIndex; i <= endIndex; i++){
12801             ns[i].nodeIndex = i;
12802         }
12803     },
12804
12805     /**
12806      * Changes the data store this view uses and refresh the view.
12807      * @param {Store} store
12808      */
12809     setStore : function(store, initial){
12810         if(!initial && this.store){
12811             this.store.un("datachanged", this.refresh);
12812             this.store.un("add", this.onAdd);
12813             this.store.un("remove", this.onRemove);
12814             this.store.un("update", this.onUpdate);
12815             this.store.un("clear", this.refresh);
12816             this.store.un("beforeload", this.onBeforeLoad);
12817             this.store.un("load", this.onLoad);
12818             this.store.un("loadexception", this.onLoad);
12819         }
12820         if(store){
12821           
12822             store.on("datachanged", this.refresh, this);
12823             store.on("add", this.onAdd, this);
12824             store.on("remove", this.onRemove, this);
12825             store.on("update", this.onUpdate, this);
12826             store.on("clear", this.refresh, this);
12827             store.on("beforeload", this.onBeforeLoad, this);
12828             store.on("load", this.onLoad, this);
12829             store.on("loadexception", this.onLoad, this);
12830         }
12831         
12832         if(store){
12833             this.refresh();
12834         }
12835     },
12836     /**
12837      * onbeforeLoad - masks the loading area.
12838      *
12839      */
12840     onBeforeLoad : function(store,opts)
12841     {
12842          //Roo.log('onBeforeLoad');   
12843         if (!opts.add) {
12844             this.el.update("");
12845         }
12846         this.el.mask(this.mask ? this.mask : "Loading" ); 
12847     },
12848     onLoad : function ()
12849     {
12850         this.el.unmask();
12851     },
12852     
12853
12854     /**
12855      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12856      * @param {HTMLElement} node
12857      * @return {HTMLElement} The template node
12858      */
12859     findItemFromChild : function(node){
12860         var el = this.dataName  ?
12861             this.el.child('.roo-tpl-' + this.dataName,true) :
12862             this.el.dom; 
12863         
12864         if(!node || node.parentNode == el){
12865                     return node;
12866             }
12867             var p = node.parentNode;
12868             while(p && p != el){
12869             if(p.parentNode == el){
12870                 return p;
12871             }
12872             p = p.parentNode;
12873         }
12874             return null;
12875     },
12876
12877     /** @ignore */
12878     onClick : function(e){
12879         var item = this.findItemFromChild(e.getTarget());
12880         if(item){
12881             var index = this.indexOf(item);
12882             if(this.onItemClick(item, index, e) !== false){
12883                 this.fireEvent("click", this, index, item, e);
12884             }
12885         }else{
12886             this.clearSelections();
12887         }
12888     },
12889
12890     /** @ignore */
12891     onContextMenu : function(e){
12892         var item = this.findItemFromChild(e.getTarget());
12893         if(item){
12894             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12895         }
12896     },
12897
12898     /** @ignore */
12899     onDblClick : function(e){
12900         var item = this.findItemFromChild(e.getTarget());
12901         if(item){
12902             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12903         }
12904     },
12905
12906     onItemClick : function(item, index, e)
12907     {
12908         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12909             return false;
12910         }
12911         if (this.toggleSelect) {
12912             var m = this.isSelected(item) ? 'unselect' : 'select';
12913             //Roo.log(m);
12914             var _t = this;
12915             _t[m](item, true, false);
12916             return true;
12917         }
12918         if(this.multiSelect || this.singleSelect){
12919             if(this.multiSelect && e.shiftKey && this.lastSelection){
12920                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12921             }else{
12922                 this.select(item, this.multiSelect && e.ctrlKey);
12923                 this.lastSelection = item;
12924             }
12925             
12926             if(!this.tickable){
12927                 e.preventDefault();
12928             }
12929             
12930         }
12931         return true;
12932     },
12933
12934     /**
12935      * Get the number of selected nodes.
12936      * @return {Number}
12937      */
12938     getSelectionCount : function(){
12939         return this.selections.length;
12940     },
12941
12942     /**
12943      * Get the currently selected nodes.
12944      * @return {Array} An array of HTMLElements
12945      */
12946     getSelectedNodes : function(){
12947         return this.selections;
12948     },
12949
12950     /**
12951      * Get the indexes of the selected nodes.
12952      * @return {Array}
12953      */
12954     getSelectedIndexes : function(){
12955         var indexes = [], s = this.selections;
12956         for(var i = 0, len = s.length; i < len; i++){
12957             indexes.push(s[i].nodeIndex);
12958         }
12959         return indexes;
12960     },
12961
12962     /**
12963      * Clear all selections
12964      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12965      */
12966     clearSelections : function(suppressEvent){
12967         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12968             this.cmp.elements = this.selections;
12969             this.cmp.removeClass(this.selectedClass);
12970             this.selections = [];
12971             if(!suppressEvent){
12972                 this.fireEvent("selectionchange", this, this.selections);
12973             }
12974         }
12975     },
12976
12977     /**
12978      * Returns true if the passed node is selected
12979      * @param {HTMLElement/Number} node The node or node index
12980      * @return {Boolean}
12981      */
12982     isSelected : function(node){
12983         var s = this.selections;
12984         if(s.length < 1){
12985             return false;
12986         }
12987         node = this.getNode(node);
12988         return s.indexOf(node) !== -1;
12989     },
12990
12991     /**
12992      * Selects nodes.
12993      * @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
12994      * @param {Boolean} keepExisting (optional) true to keep existing selections
12995      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12996      */
12997     select : function(nodeInfo, keepExisting, suppressEvent){
12998         if(nodeInfo instanceof Array){
12999             if(!keepExisting){
13000                 this.clearSelections(true);
13001             }
13002             for(var i = 0, len = nodeInfo.length; i < len; i++){
13003                 this.select(nodeInfo[i], true, true);
13004             }
13005             return;
13006         } 
13007         var node = this.getNode(nodeInfo);
13008         if(!node || this.isSelected(node)){
13009             return; // already selected.
13010         }
13011         if(!keepExisting){
13012             this.clearSelections(true);
13013         }
13014         
13015         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13016             Roo.fly(node).addClass(this.selectedClass);
13017             this.selections.push(node);
13018             if(!suppressEvent){
13019                 this.fireEvent("selectionchange", this, this.selections);
13020             }
13021         }
13022         
13023         
13024     },
13025       /**
13026      * Unselects nodes.
13027      * @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
13028      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13029      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13030      */
13031     unselect : function(nodeInfo, keepExisting, suppressEvent)
13032     {
13033         if(nodeInfo instanceof Array){
13034             Roo.each(this.selections, function(s) {
13035                 this.unselect(s, nodeInfo);
13036             }, this);
13037             return;
13038         }
13039         var node = this.getNode(nodeInfo);
13040         if(!node || !this.isSelected(node)){
13041             //Roo.log("not selected");
13042             return; // not selected.
13043         }
13044         // fireevent???
13045         var ns = [];
13046         Roo.each(this.selections, function(s) {
13047             if (s == node ) {
13048                 Roo.fly(node).removeClass(this.selectedClass);
13049
13050                 return;
13051             }
13052             ns.push(s);
13053         },this);
13054         
13055         this.selections= ns;
13056         this.fireEvent("selectionchange", this, this.selections);
13057     },
13058
13059     /**
13060      * Gets a template node.
13061      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13062      * @return {HTMLElement} The node or null if it wasn't found
13063      */
13064     getNode : function(nodeInfo){
13065         if(typeof nodeInfo == "string"){
13066             return document.getElementById(nodeInfo);
13067         }else if(typeof nodeInfo == "number"){
13068             return this.nodes[nodeInfo];
13069         }
13070         return nodeInfo;
13071     },
13072
13073     /**
13074      * Gets a range template nodes.
13075      * @param {Number} startIndex
13076      * @param {Number} endIndex
13077      * @return {Array} An array of nodes
13078      */
13079     getNodes : function(start, end){
13080         var ns = this.nodes;
13081         start = start || 0;
13082         end = typeof end == "undefined" ? ns.length - 1 : end;
13083         var nodes = [];
13084         if(start <= end){
13085             for(var i = start; i <= end; i++){
13086                 nodes.push(ns[i]);
13087             }
13088         } else{
13089             for(var i = start; i >= end; i--){
13090                 nodes.push(ns[i]);
13091             }
13092         }
13093         return nodes;
13094     },
13095
13096     /**
13097      * Finds the index of the passed node
13098      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13099      * @return {Number} The index of the node or -1
13100      */
13101     indexOf : function(node){
13102         node = this.getNode(node);
13103         if(typeof node.nodeIndex == "number"){
13104             return node.nodeIndex;
13105         }
13106         var ns = this.nodes;
13107         for(var i = 0, len = ns.length; i < len; i++){
13108             if(ns[i] == node){
13109                 return i;
13110             }
13111         }
13112         return -1;
13113     }
13114 });
13115 /*
13116  * - LGPL
13117  *
13118  * based on jquery fullcalendar
13119  * 
13120  */
13121
13122 Roo.bootstrap = Roo.bootstrap || {};
13123 /**
13124  * @class Roo.bootstrap.Calendar
13125  * @extends Roo.bootstrap.Component
13126  * Bootstrap Calendar class
13127  * @cfg {Boolean} loadMask (true|false) default false
13128  * @cfg {Object} header generate the user specific header of the calendar, default false
13129
13130  * @constructor
13131  * Create a new Container
13132  * @param {Object} config The config object
13133  */
13134
13135
13136
13137 Roo.bootstrap.Calendar = function(config){
13138     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13139      this.addEvents({
13140         /**
13141              * @event select
13142              * Fires when a date is selected
13143              * @param {DatePicker} this
13144              * @param {Date} date The selected date
13145              */
13146         'select': true,
13147         /**
13148              * @event monthchange
13149              * Fires when the displayed month changes 
13150              * @param {DatePicker} this
13151              * @param {Date} date The selected month
13152              */
13153         'monthchange': true,
13154         /**
13155              * @event evententer
13156              * Fires when mouse over an event
13157              * @param {Calendar} this
13158              * @param {event} Event
13159              */
13160         'evententer': true,
13161         /**
13162              * @event eventleave
13163              * Fires when the mouse leaves an
13164              * @param {Calendar} this
13165              * @param {event}
13166              */
13167         'eventleave': true,
13168         /**
13169              * @event eventclick
13170              * Fires when the mouse click an
13171              * @param {Calendar} this
13172              * @param {event}
13173              */
13174         'eventclick': true
13175         
13176     });
13177
13178 };
13179
13180 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13181     
13182      /**
13183      * @cfg {Number} startDay
13184      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13185      */
13186     startDay : 0,
13187     
13188     loadMask : false,
13189     
13190     header : false,
13191       
13192     getAutoCreate : function(){
13193         
13194         
13195         var fc_button = function(name, corner, style, content ) {
13196             return Roo.apply({},{
13197                 tag : 'span',
13198                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13199                          (corner.length ?
13200                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13201                             ''
13202                         ),
13203                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13204                 unselectable: 'on'
13205             });
13206         };
13207         
13208         var header = {};
13209         
13210         if(!this.header){
13211             header = {
13212                 tag : 'table',
13213                 cls : 'fc-header',
13214                 style : 'width:100%',
13215                 cn : [
13216                     {
13217                         tag: 'tr',
13218                         cn : [
13219                             {
13220                                 tag : 'td',
13221                                 cls : 'fc-header-left',
13222                                 cn : [
13223                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13224                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13225                                     { tag: 'span', cls: 'fc-header-space' },
13226                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13227
13228
13229                                 ]
13230                             },
13231
13232                             {
13233                                 tag : 'td',
13234                                 cls : 'fc-header-center',
13235                                 cn : [
13236                                     {
13237                                         tag: 'span',
13238                                         cls: 'fc-header-title',
13239                                         cn : {
13240                                             tag: 'H2',
13241                                             html : 'month / year'
13242                                         }
13243                                     }
13244
13245                                 ]
13246                             },
13247                             {
13248                                 tag : 'td',
13249                                 cls : 'fc-header-right',
13250                                 cn : [
13251                               /*      fc_button('month', 'left', '', 'month' ),
13252                                     fc_button('week', '', '', 'week' ),
13253                                     fc_button('day', 'right', '', 'day' )
13254                                 */    
13255
13256                                 ]
13257                             }
13258
13259                         ]
13260                     }
13261                 ]
13262             };
13263         }
13264         
13265         header = this.header;
13266         
13267        
13268         var cal_heads = function() {
13269             var ret = [];
13270             // fixme - handle this.
13271             
13272             for (var i =0; i < Date.dayNames.length; i++) {
13273                 var d = Date.dayNames[i];
13274                 ret.push({
13275                     tag: 'th',
13276                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13277                     html : d.substring(0,3)
13278                 });
13279                 
13280             }
13281             ret[0].cls += ' fc-first';
13282             ret[6].cls += ' fc-last';
13283             return ret;
13284         };
13285         var cal_cell = function(n) {
13286             return  {
13287                 tag: 'td',
13288                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13289                 cn : [
13290                     {
13291                         cn : [
13292                             {
13293                                 cls: 'fc-day-number',
13294                                 html: 'D'
13295                             },
13296                             {
13297                                 cls: 'fc-day-content',
13298                              
13299                                 cn : [
13300                                      {
13301                                         style: 'position: relative;' // height: 17px;
13302                                     }
13303                                 ]
13304                             }
13305                             
13306                             
13307                         ]
13308                     }
13309                 ]
13310                 
13311             }
13312         };
13313         var cal_rows = function() {
13314             
13315             var ret = [];
13316             for (var r = 0; r < 6; r++) {
13317                 var row= {
13318                     tag : 'tr',
13319                     cls : 'fc-week',
13320                     cn : []
13321                 };
13322                 
13323                 for (var i =0; i < Date.dayNames.length; i++) {
13324                     var d = Date.dayNames[i];
13325                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13326
13327                 }
13328                 row.cn[0].cls+=' fc-first';
13329                 row.cn[0].cn[0].style = 'min-height:90px';
13330                 row.cn[6].cls+=' fc-last';
13331                 ret.push(row);
13332                 
13333             }
13334             ret[0].cls += ' fc-first';
13335             ret[4].cls += ' fc-prev-last';
13336             ret[5].cls += ' fc-last';
13337             return ret;
13338             
13339         };
13340         
13341         var cal_table = {
13342             tag: 'table',
13343             cls: 'fc-border-separate',
13344             style : 'width:100%',
13345             cellspacing  : 0,
13346             cn : [
13347                 { 
13348                     tag: 'thead',
13349                     cn : [
13350                         { 
13351                             tag: 'tr',
13352                             cls : 'fc-first fc-last',
13353                             cn : cal_heads()
13354                         }
13355                     ]
13356                 },
13357                 { 
13358                     tag: 'tbody',
13359                     cn : cal_rows()
13360                 }
13361                   
13362             ]
13363         };
13364          
13365          var cfg = {
13366             cls : 'fc fc-ltr',
13367             cn : [
13368                 header,
13369                 {
13370                     cls : 'fc-content',
13371                     style : "position: relative;",
13372                     cn : [
13373                         {
13374                             cls : 'fc-view fc-view-month fc-grid',
13375                             style : 'position: relative',
13376                             unselectable : 'on',
13377                             cn : [
13378                                 {
13379                                     cls : 'fc-event-container',
13380                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13381                                 },
13382                                 cal_table
13383                             ]
13384                         }
13385                     ]
13386     
13387                 }
13388            ] 
13389             
13390         };
13391         
13392          
13393         
13394         return cfg;
13395     },
13396     
13397     
13398     initEvents : function()
13399     {
13400         if(!this.store){
13401             throw "can not find store for calendar";
13402         }
13403         
13404         var mark = {
13405             tag: "div",
13406             cls:"x-dlg-mask",
13407             style: "text-align:center",
13408             cn: [
13409                 {
13410                     tag: "div",
13411                     style: "background-color:white;width:50%;margin:250 auto",
13412                     cn: [
13413                         {
13414                             tag: "img",
13415                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13416                         },
13417                         {
13418                             tag: "span",
13419                             html: "Loading"
13420                         }
13421                         
13422                     ]
13423                 }
13424             ]
13425         }
13426         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13427         
13428         var size = this.el.select('.fc-content', true).first().getSize();
13429         this.maskEl.setSize(size.width, size.height);
13430         this.maskEl.enableDisplayMode("block");
13431         if(!this.loadMask){
13432             this.maskEl.hide();
13433         }
13434         
13435         this.store = Roo.factory(this.store, Roo.data);
13436         this.store.on('load', this.onLoad, this);
13437         this.store.on('beforeload', this.onBeforeLoad, this);
13438         
13439         this.resize();
13440         
13441         this.cells = this.el.select('.fc-day',true);
13442         //Roo.log(this.cells);
13443         this.textNodes = this.el.query('.fc-day-number');
13444         this.cells.addClassOnOver('fc-state-hover');
13445         
13446         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13447         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13448         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13449         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13450         
13451         this.on('monthchange', this.onMonthChange, this);
13452         
13453         this.update(new Date().clearTime());
13454     },
13455     
13456     resize : function() {
13457         var sz  = this.el.getSize();
13458         
13459         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13460         this.el.select('.fc-day-content div',true).setHeight(34);
13461     },
13462     
13463     
13464     // private
13465     showPrevMonth : function(e){
13466         this.update(this.activeDate.add("mo", -1));
13467     },
13468     showToday : function(e){
13469         this.update(new Date().clearTime());
13470     },
13471     // private
13472     showNextMonth : function(e){
13473         this.update(this.activeDate.add("mo", 1));
13474     },
13475
13476     // private
13477     showPrevYear : function(){
13478         this.update(this.activeDate.add("y", -1));
13479     },
13480
13481     // private
13482     showNextYear : function(){
13483         this.update(this.activeDate.add("y", 1));
13484     },
13485
13486     
13487    // private
13488     update : function(date)
13489     {
13490         var vd = this.activeDate;
13491         this.activeDate = date;
13492 //        if(vd && this.el){
13493 //            var t = date.getTime();
13494 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13495 //                Roo.log('using add remove');
13496 //                
13497 //                this.fireEvent('monthchange', this, date);
13498 //                
13499 //                this.cells.removeClass("fc-state-highlight");
13500 //                this.cells.each(function(c){
13501 //                   if(c.dateValue == t){
13502 //                       c.addClass("fc-state-highlight");
13503 //                       setTimeout(function(){
13504 //                            try{c.dom.firstChild.focus();}catch(e){}
13505 //                       }, 50);
13506 //                       return false;
13507 //                   }
13508 //                   return true;
13509 //                });
13510 //                return;
13511 //            }
13512 //        }
13513         
13514         var days = date.getDaysInMonth();
13515         
13516         var firstOfMonth = date.getFirstDateOfMonth();
13517         var startingPos = firstOfMonth.getDay()-this.startDay;
13518         
13519         if(startingPos < this.startDay){
13520             startingPos += 7;
13521         }
13522         
13523         var pm = date.add(Date.MONTH, -1);
13524         var prevStart = pm.getDaysInMonth()-startingPos;
13525 //        
13526         this.cells = this.el.select('.fc-day',true);
13527         this.textNodes = this.el.query('.fc-day-number');
13528         this.cells.addClassOnOver('fc-state-hover');
13529         
13530         var cells = this.cells.elements;
13531         var textEls = this.textNodes;
13532         
13533         Roo.each(cells, function(cell){
13534             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13535         });
13536         
13537         days += startingPos;
13538
13539         // convert everything to numbers so it's fast
13540         var day = 86400000;
13541         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13542         //Roo.log(d);
13543         //Roo.log(pm);
13544         //Roo.log(prevStart);
13545         
13546         var today = new Date().clearTime().getTime();
13547         var sel = date.clearTime().getTime();
13548         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13549         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13550         var ddMatch = this.disabledDatesRE;
13551         var ddText = this.disabledDatesText;
13552         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13553         var ddaysText = this.disabledDaysText;
13554         var format = this.format;
13555         
13556         var setCellClass = function(cal, cell){
13557             cell.row = 0;
13558             cell.events = [];
13559             cell.more = [];
13560             //Roo.log('set Cell Class');
13561             cell.title = "";
13562             var t = d.getTime();
13563             
13564             //Roo.log(d);
13565             
13566             cell.dateValue = t;
13567             if(t == today){
13568                 cell.className += " fc-today";
13569                 cell.className += " fc-state-highlight";
13570                 cell.title = cal.todayText;
13571             }
13572             if(t == sel){
13573                 // disable highlight in other month..
13574                 //cell.className += " fc-state-highlight";
13575                 
13576             }
13577             // disabling
13578             if(t < min) {
13579                 cell.className = " fc-state-disabled";
13580                 cell.title = cal.minText;
13581                 return;
13582             }
13583             if(t > max) {
13584                 cell.className = " fc-state-disabled";
13585                 cell.title = cal.maxText;
13586                 return;
13587             }
13588             if(ddays){
13589                 if(ddays.indexOf(d.getDay()) != -1){
13590                     cell.title = ddaysText;
13591                     cell.className = " fc-state-disabled";
13592                 }
13593             }
13594             if(ddMatch && format){
13595                 var fvalue = d.dateFormat(format);
13596                 if(ddMatch.test(fvalue)){
13597                     cell.title = ddText.replace("%0", fvalue);
13598                     cell.className = " fc-state-disabled";
13599                 }
13600             }
13601             
13602             if (!cell.initialClassName) {
13603                 cell.initialClassName = cell.dom.className;
13604             }
13605             
13606             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13607         };
13608
13609         var i = 0;
13610         
13611         for(; i < startingPos; i++) {
13612             textEls[i].innerHTML = (++prevStart);
13613             d.setDate(d.getDate()+1);
13614             
13615             cells[i].className = "fc-past fc-other-month";
13616             setCellClass(this, cells[i]);
13617         }
13618         
13619         var intDay = 0;
13620         
13621         for(; i < days; i++){
13622             intDay = i - startingPos + 1;
13623             textEls[i].innerHTML = (intDay);
13624             d.setDate(d.getDate()+1);
13625             
13626             cells[i].className = ''; // "x-date-active";
13627             setCellClass(this, cells[i]);
13628         }
13629         var extraDays = 0;
13630         
13631         for(; i < 42; i++) {
13632             textEls[i].innerHTML = (++extraDays);
13633             d.setDate(d.getDate()+1);
13634             
13635             cells[i].className = "fc-future fc-other-month";
13636             setCellClass(this, cells[i]);
13637         }
13638         
13639         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13640         
13641         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13642         
13643         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13644         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13645         
13646         if(totalRows != 6){
13647             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13648             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13649         }
13650         
13651         this.fireEvent('monthchange', this, date);
13652         
13653         
13654         /*
13655         if(!this.internalRender){
13656             var main = this.el.dom.firstChild;
13657             var w = main.offsetWidth;
13658             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13659             Roo.fly(main).setWidth(w);
13660             this.internalRender = true;
13661             // opera does not respect the auto grow header center column
13662             // then, after it gets a width opera refuses to recalculate
13663             // without a second pass
13664             if(Roo.isOpera && !this.secondPass){
13665                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13666                 this.secondPass = true;
13667                 this.update.defer(10, this, [date]);
13668             }
13669         }
13670         */
13671         
13672     },
13673     
13674     findCell : function(dt) {
13675         dt = dt.clearTime().getTime();
13676         var ret = false;
13677         this.cells.each(function(c){
13678             //Roo.log("check " +c.dateValue + '?=' + dt);
13679             if(c.dateValue == dt){
13680                 ret = c;
13681                 return false;
13682             }
13683             return true;
13684         });
13685         
13686         return ret;
13687     },
13688     
13689     findCells : function(ev) {
13690         var s = ev.start.clone().clearTime().getTime();
13691        // Roo.log(s);
13692         var e= ev.end.clone().clearTime().getTime();
13693        // Roo.log(e);
13694         var ret = [];
13695         this.cells.each(function(c){
13696              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13697             
13698             if(c.dateValue > e){
13699                 return ;
13700             }
13701             if(c.dateValue < s){
13702                 return ;
13703             }
13704             ret.push(c);
13705         });
13706         
13707         return ret;    
13708     },
13709     
13710 //    findBestRow: function(cells)
13711 //    {
13712 //        var ret = 0;
13713 //        
13714 //        for (var i =0 ; i < cells.length;i++) {
13715 //            ret  = Math.max(cells[i].rows || 0,ret);
13716 //        }
13717 //        return ret;
13718 //        
13719 //    },
13720     
13721     
13722     addItem : function(ev)
13723     {
13724         // look for vertical location slot in
13725         var cells = this.findCells(ev);
13726         
13727 //        ev.row = this.findBestRow(cells);
13728         
13729         // work out the location.
13730         
13731         var crow = false;
13732         var rows = [];
13733         for(var i =0; i < cells.length; i++) {
13734             
13735             cells[i].row = cells[0].row;
13736             
13737             if(i == 0){
13738                 cells[i].row = cells[i].row + 1;
13739             }
13740             
13741             if (!crow) {
13742                 crow = {
13743                     start : cells[i],
13744                     end :  cells[i]
13745                 };
13746                 continue;
13747             }
13748             if (crow.start.getY() == cells[i].getY()) {
13749                 // on same row.
13750                 crow.end = cells[i];
13751                 continue;
13752             }
13753             // different row.
13754             rows.push(crow);
13755             crow = {
13756                 start: cells[i],
13757                 end : cells[i]
13758             };
13759             
13760         }
13761         
13762         rows.push(crow);
13763         ev.els = [];
13764         ev.rows = rows;
13765         ev.cells = cells;
13766         
13767         cells[0].events.push(ev);
13768         
13769         this.calevents.push(ev);
13770     },
13771     
13772     clearEvents: function() {
13773         
13774         if(!this.calevents){
13775             return;
13776         }
13777         
13778         Roo.each(this.cells.elements, function(c){
13779             c.row = 0;
13780             c.events = [];
13781             c.more = [];
13782         });
13783         
13784         Roo.each(this.calevents, function(e) {
13785             Roo.each(e.els, function(el) {
13786                 el.un('mouseenter' ,this.onEventEnter, this);
13787                 el.un('mouseleave' ,this.onEventLeave, this);
13788                 el.remove();
13789             },this);
13790         },this);
13791         
13792         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13793             e.remove();
13794         });
13795         
13796     },
13797     
13798     renderEvents: function()
13799     {   
13800         var _this = this;
13801         
13802         this.cells.each(function(c) {
13803             
13804             if(c.row < 5){
13805                 return;
13806             }
13807             
13808             var ev = c.events;
13809             
13810             var r = 4;
13811             if(c.row != c.events.length){
13812                 r = 4 - (4 - (c.row - c.events.length));
13813             }
13814             
13815             c.events = ev.slice(0, r);
13816             c.more = ev.slice(r);
13817             
13818             if(c.more.length && c.more.length == 1){
13819                 c.events.push(c.more.pop());
13820             }
13821             
13822             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13823             
13824         });
13825             
13826         this.cells.each(function(c) {
13827             
13828             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13829             
13830             
13831             for (var e = 0; e < c.events.length; e++){
13832                 var ev = c.events[e];
13833                 var rows = ev.rows;
13834                 
13835                 for(var i = 0; i < rows.length; i++) {
13836                 
13837                     // how many rows should it span..
13838
13839                     var  cfg = {
13840                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13841                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13842
13843                         unselectable : "on",
13844                         cn : [
13845                             {
13846                                 cls: 'fc-event-inner',
13847                                 cn : [
13848     //                                {
13849     //                                  tag:'span',
13850     //                                  cls: 'fc-event-time',
13851     //                                  html : cells.length > 1 ? '' : ev.time
13852     //                                },
13853                                     {
13854                                       tag:'span',
13855                                       cls: 'fc-event-title',
13856                                       html : String.format('{0}', ev.title)
13857                                     }
13858
13859
13860                                 ]
13861                             },
13862                             {
13863                                 cls: 'ui-resizable-handle ui-resizable-e',
13864                                 html : '&nbsp;&nbsp;&nbsp'
13865                             }
13866
13867                         ]
13868                     };
13869
13870                     if (i == 0) {
13871                         cfg.cls += ' fc-event-start';
13872                     }
13873                     if ((i+1) == rows.length) {
13874                         cfg.cls += ' fc-event-end';
13875                     }
13876
13877                     var ctr = _this.el.select('.fc-event-container',true).first();
13878                     var cg = ctr.createChild(cfg);
13879
13880                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13881                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13882
13883                     var r = (c.more.length) ? 1 : 0;
13884                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13885                     cg.setWidth(ebox.right - sbox.x -2);
13886
13887                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13888                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13889                     cg.on('click', _this.onEventClick, _this, ev);
13890
13891                     ev.els.push(cg);
13892                     
13893                 }
13894                 
13895             }
13896             
13897             
13898             if(c.more.length){
13899                 var  cfg = {
13900                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13901                     style : 'position: absolute',
13902                     unselectable : "on",
13903                     cn : [
13904                         {
13905                             cls: 'fc-event-inner',
13906                             cn : [
13907                                 {
13908                                   tag:'span',
13909                                   cls: 'fc-event-title',
13910                                   html : 'More'
13911                                 }
13912
13913
13914                             ]
13915                         },
13916                         {
13917                             cls: 'ui-resizable-handle ui-resizable-e',
13918                             html : '&nbsp;&nbsp;&nbsp'
13919                         }
13920
13921                     ]
13922                 };
13923
13924                 var ctr = _this.el.select('.fc-event-container',true).first();
13925                 var cg = ctr.createChild(cfg);
13926
13927                 var sbox = c.select('.fc-day-content',true).first().getBox();
13928                 var ebox = c.select('.fc-day-content',true).first().getBox();
13929                 //Roo.log(cg);
13930                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13931                 cg.setWidth(ebox.right - sbox.x -2);
13932
13933                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13934                 
13935             }
13936             
13937         });
13938         
13939         
13940         
13941     },
13942     
13943     onEventEnter: function (e, el,event,d) {
13944         this.fireEvent('evententer', this, el, event);
13945     },
13946     
13947     onEventLeave: function (e, el,event,d) {
13948         this.fireEvent('eventleave', this, el, event);
13949     },
13950     
13951     onEventClick: function (e, el,event,d) {
13952         this.fireEvent('eventclick', this, el, event);
13953     },
13954     
13955     onMonthChange: function () {
13956         this.store.load();
13957     },
13958     
13959     onMoreEventClick: function(e, el, more)
13960     {
13961         var _this = this;
13962         
13963         this.calpopover.placement = 'right';
13964         this.calpopover.setTitle('More');
13965         
13966         this.calpopover.setContent('');
13967         
13968         var ctr = this.calpopover.el.select('.popover-content', true).first();
13969         
13970         Roo.each(more, function(m){
13971             var cfg = {
13972                 cls : 'fc-event-hori fc-event-draggable',
13973                 html : m.title
13974             }
13975             var cg = ctr.createChild(cfg);
13976             
13977             cg.on('click', _this.onEventClick, _this, m);
13978         });
13979         
13980         this.calpopover.show(el);
13981         
13982         
13983     },
13984     
13985     onLoad: function () 
13986     {   
13987         this.calevents = [];
13988         var cal = this;
13989         
13990         if(this.store.getCount() > 0){
13991             this.store.data.each(function(d){
13992                cal.addItem({
13993                     id : d.data.id,
13994                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13995                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13996                     time : d.data.start_time,
13997                     title : d.data.title,
13998                     description : d.data.description,
13999                     venue : d.data.venue
14000                 });
14001             });
14002         }
14003         
14004         this.renderEvents();
14005         
14006         if(this.calevents.length && this.loadMask){
14007             this.maskEl.hide();
14008         }
14009     },
14010     
14011     onBeforeLoad: function()
14012     {
14013         this.clearEvents();
14014         if(this.loadMask){
14015             this.maskEl.show();
14016         }
14017     }
14018 });
14019
14020  
14021  /*
14022  * - LGPL
14023  *
14024  * element
14025  * 
14026  */
14027
14028 /**
14029  * @class Roo.bootstrap.Popover
14030  * @extends Roo.bootstrap.Component
14031  * Bootstrap Popover class
14032  * @cfg {String} html contents of the popover   (or false to use children..)
14033  * @cfg {String} title of popover (or false to hide)
14034  * @cfg {String} placement how it is placed
14035  * @cfg {String} trigger click || hover (or false to trigger manually)
14036  * @cfg {String} over what (parent or false to trigger manually.)
14037  * @cfg {Number} delay - delay before showing
14038  
14039  * @constructor
14040  * Create a new Popover
14041  * @param {Object} config The config object
14042  */
14043
14044 Roo.bootstrap.Popover = function(config){
14045     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14046 };
14047
14048 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14049     
14050     title: 'Fill in a title',
14051     html: false,
14052     
14053     placement : 'right',
14054     trigger : 'hover', // hover
14055     
14056     delay : 0,
14057     
14058     over: 'parent',
14059     
14060     can_build_overlaid : false,
14061     
14062     getChildContainer : function()
14063     {
14064         return this.el.select('.popover-content',true).first();
14065     },
14066     
14067     getAutoCreate : function(){
14068          Roo.log('make popover?');
14069         var cfg = {
14070            cls : 'popover roo-dynamic',
14071            style: 'display:block',
14072            cn : [
14073                 {
14074                     cls : 'arrow'
14075                 },
14076                 {
14077                     cls : 'popover-inner',
14078                     cn : [
14079                         {
14080                             tag: 'h3',
14081                             cls: 'popover-title',
14082                             html : this.title
14083                         },
14084                         {
14085                             cls : 'popover-content',
14086                             html : this.html
14087                         }
14088                     ]
14089                     
14090                 }
14091            ]
14092         };
14093         
14094         return cfg;
14095     },
14096     setTitle: function(str)
14097     {
14098         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14099     },
14100     setContent: function(str)
14101     {
14102         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14103     },
14104     // as it get's added to the bottom of the page.
14105     onRender : function(ct, position)
14106     {
14107         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14108         if(!this.el){
14109             var cfg = Roo.apply({},  this.getAutoCreate());
14110             cfg.id = Roo.id();
14111             
14112             if (this.cls) {
14113                 cfg.cls += ' ' + this.cls;
14114             }
14115             if (this.style) {
14116                 cfg.style = this.style;
14117             }
14118             Roo.log("adding to ")
14119             this.el = Roo.get(document.body).createChild(cfg, position);
14120             Roo.log(this.el);
14121         }
14122         this.initEvents();
14123     },
14124     
14125     initEvents : function()
14126     {
14127         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14128         this.el.enableDisplayMode('block');
14129         this.el.hide();
14130         if (this.over === false) {
14131             return; 
14132         }
14133         if (this.triggers === false) {
14134             return;
14135         }
14136         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14137         var triggers = this.trigger ? this.trigger.split(' ') : [];
14138         Roo.each(triggers, function(trigger) {
14139         
14140             if (trigger == 'click') {
14141                 on_el.on('click', this.toggle, this);
14142             } else if (trigger != 'manual') {
14143                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14144                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14145       
14146                 on_el.on(eventIn  ,this.enter, this);
14147                 on_el.on(eventOut, this.leave, this);
14148             }
14149         }, this);
14150         
14151     },
14152     
14153     
14154     // private
14155     timeout : null,
14156     hoverState : null,
14157     
14158     toggle : function () {
14159         this.hoverState == 'in' ? this.leave() : this.enter();
14160     },
14161     
14162     enter : function () {
14163        
14164     
14165         clearTimeout(this.timeout);
14166     
14167         this.hoverState = 'in';
14168     
14169         if (!this.delay || !this.delay.show) {
14170             this.show();
14171             return;
14172         }
14173         var _t = this;
14174         this.timeout = setTimeout(function () {
14175             if (_t.hoverState == 'in') {
14176                 _t.show();
14177             }
14178         }, this.delay.show)
14179     },
14180     leave : function() {
14181         clearTimeout(this.timeout);
14182     
14183         this.hoverState = 'out';
14184     
14185         if (!this.delay || !this.delay.hide) {
14186             this.hide();
14187             return;
14188         }
14189         var _t = this;
14190         this.timeout = setTimeout(function () {
14191             if (_t.hoverState == 'out') {
14192                 _t.hide();
14193             }
14194         }, this.delay.hide)
14195     },
14196     
14197     show : function (on_el)
14198     {
14199         if (!on_el) {
14200             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14201         }
14202         // set content.
14203         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14204         if (this.html !== false) {
14205             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14206         }
14207         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14208         if (!this.title.length) {
14209             this.el.select('.popover-title',true).hide();
14210         }
14211         
14212         var placement = typeof this.placement == 'function' ?
14213             this.placement.call(this, this.el, on_el) :
14214             this.placement;
14215             
14216         var autoToken = /\s?auto?\s?/i;
14217         var autoPlace = autoToken.test(placement);
14218         if (autoPlace) {
14219             placement = placement.replace(autoToken, '') || 'top';
14220         }
14221         
14222         //this.el.detach()
14223         //this.el.setXY([0,0]);
14224         this.el.show();
14225         this.el.dom.style.display='block';
14226         this.el.addClass(placement);
14227         
14228         //this.el.appendTo(on_el);
14229         
14230         var p = this.getPosition();
14231         var box = this.el.getBox();
14232         
14233         if (autoPlace) {
14234             // fixme..
14235         }
14236         var align = Roo.bootstrap.Popover.alignment[placement];
14237         this.el.alignTo(on_el, align[0],align[1]);
14238         //var arrow = this.el.select('.arrow',true).first();
14239         //arrow.set(align[2], 
14240         
14241         this.el.addClass('in');
14242         this.hoverState = null;
14243         
14244         if (this.el.hasClass('fade')) {
14245             // fade it?
14246         }
14247         
14248     },
14249     hide : function()
14250     {
14251         this.el.setXY([0,0]);
14252         this.el.removeClass('in');
14253         this.el.hide();
14254         
14255     }
14256     
14257 });
14258
14259 Roo.bootstrap.Popover.alignment = {
14260     'left' : ['r-l', [-10,0], 'right'],
14261     'right' : ['l-r', [10,0], 'left'],
14262     'bottom' : ['t-b', [0,10], 'top'],
14263     'top' : [ 'b-t', [0,-10], 'bottom']
14264 };
14265
14266  /*
14267  * - LGPL
14268  *
14269  * Progress
14270  * 
14271  */
14272
14273 /**
14274  * @class Roo.bootstrap.Progress
14275  * @extends Roo.bootstrap.Component
14276  * Bootstrap Progress class
14277  * @cfg {Boolean} striped striped of the progress bar
14278  * @cfg {Boolean} active animated of the progress bar
14279  * 
14280  * 
14281  * @constructor
14282  * Create a new Progress
14283  * @param {Object} config The config object
14284  */
14285
14286 Roo.bootstrap.Progress = function(config){
14287     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14288 };
14289
14290 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14291     
14292     striped : false,
14293     active: false,
14294     
14295     getAutoCreate : function(){
14296         var cfg = {
14297             tag: 'div',
14298             cls: 'progress'
14299         };
14300         
14301         
14302         if(this.striped){
14303             cfg.cls += ' progress-striped';
14304         }
14305       
14306         if(this.active){
14307             cfg.cls += ' active';
14308         }
14309         
14310         
14311         return cfg;
14312     }
14313    
14314 });
14315
14316  
14317
14318  /*
14319  * - LGPL
14320  *
14321  * ProgressBar
14322  * 
14323  */
14324
14325 /**
14326  * @class Roo.bootstrap.ProgressBar
14327  * @extends Roo.bootstrap.Component
14328  * Bootstrap ProgressBar class
14329  * @cfg {Number} aria_valuenow aria-value now
14330  * @cfg {Number} aria_valuemin aria-value min
14331  * @cfg {Number} aria_valuemax aria-value max
14332  * @cfg {String} label label for the progress bar
14333  * @cfg {String} panel (success | info | warning | danger )
14334  * @cfg {String} role role of the progress bar
14335  * @cfg {String} sr_only text
14336  * 
14337  * 
14338  * @constructor
14339  * Create a new ProgressBar
14340  * @param {Object} config The config object
14341  */
14342
14343 Roo.bootstrap.ProgressBar = function(config){
14344     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14345 };
14346
14347 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14348     
14349     aria_valuenow : 0,
14350     aria_valuemin : 0,
14351     aria_valuemax : 100,
14352     label : false,
14353     panel : false,
14354     role : false,
14355     sr_only: false,
14356     
14357     getAutoCreate : function()
14358     {
14359         
14360         var cfg = {
14361             tag: 'div',
14362             cls: 'progress-bar',
14363             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14364         };
14365         
14366         if(this.sr_only){
14367             cfg.cn = {
14368                 tag: 'span',
14369                 cls: 'sr-only',
14370                 html: this.sr_only
14371             }
14372         }
14373         
14374         if(this.role){
14375             cfg.role = this.role;
14376         }
14377         
14378         if(this.aria_valuenow){
14379             cfg['aria-valuenow'] = this.aria_valuenow;
14380         }
14381         
14382         if(this.aria_valuemin){
14383             cfg['aria-valuemin'] = this.aria_valuemin;
14384         }
14385         
14386         if(this.aria_valuemax){
14387             cfg['aria-valuemax'] = this.aria_valuemax;
14388         }
14389         
14390         if(this.label && !this.sr_only){
14391             cfg.html = this.label;
14392         }
14393         
14394         if(this.panel){
14395             cfg.cls += ' progress-bar-' + this.panel;
14396         }
14397         
14398         return cfg;
14399     },
14400     
14401     update : function(aria_valuenow)
14402     {
14403         this.aria_valuenow = aria_valuenow;
14404         
14405         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14406     }
14407    
14408 });
14409
14410  
14411
14412  /*
14413  * - LGPL
14414  *
14415  * column
14416  * 
14417  */
14418
14419 /**
14420  * @class Roo.bootstrap.TabGroup
14421  * @extends Roo.bootstrap.Column
14422  * Bootstrap Column class
14423  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14424  * @cfg {Boolean} carousel true to make the group behave like a carousel
14425  * 
14426  * @constructor
14427  * Create a new TabGroup
14428  * @param {Object} config The config object
14429  */
14430
14431 Roo.bootstrap.TabGroup = function(config){
14432     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14433     if (!this.navId) {
14434         this.navId = Roo.id();
14435     }
14436     this.tabs = [];
14437     Roo.bootstrap.TabGroup.register(this);
14438     
14439 };
14440
14441 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14442     
14443     carousel : false,
14444     transition : false,
14445      
14446     getAutoCreate : function()
14447     {
14448         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14449         
14450         cfg.cls += ' tab-content';
14451         
14452         if (this.carousel) {
14453             cfg.cls += ' carousel slide';
14454             cfg.cn = [{
14455                cls : 'carousel-inner'
14456             }]
14457         }
14458         
14459         
14460         return cfg;
14461     },
14462     getChildContainer : function()
14463     {
14464         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14465     },
14466     
14467     /**
14468     * register a Navigation item
14469     * @param {Roo.bootstrap.NavItem} the navitem to add
14470     */
14471     register : function(item)
14472     {
14473         this.tabs.push( item);
14474         item.navId = this.navId; // not really needed..
14475     
14476     },
14477     
14478     getActivePanel : function()
14479     {
14480         var r = false;
14481         Roo.each(this.tabs, function(t) {
14482             if (t.active) {
14483                 r = t;
14484                 return false;
14485             }
14486             return null;
14487         });
14488         return r;
14489         
14490     },
14491     getPanelByName : function(n)
14492     {
14493         var r = false;
14494         Roo.each(this.tabs, function(t) {
14495             if (t.tabId == n) {
14496                 r = t;
14497                 return false;
14498             }
14499             return null;
14500         });
14501         return r;
14502     },
14503     indexOfPanel : function(p)
14504     {
14505         var r = false;
14506         Roo.each(this.tabs, function(t,i) {
14507             if (t.tabId == p.tabId) {
14508                 r = i;
14509                 return false;
14510             }
14511             return null;
14512         });
14513         return r;
14514     },
14515     /**
14516      * show a specific panel
14517      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14518      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14519      */
14520     showPanel : function (pan)
14521     {
14522         
14523         if (typeof(pan) == 'number') {
14524             pan = this.tabs[pan];
14525         }
14526         if (typeof(pan) == 'string') {
14527             pan = this.getPanelByName(pan);
14528         }
14529         if (pan.tabId == this.getActivePanel().tabId) {
14530             return true;
14531         }
14532         var cur = this.getActivePanel();
14533         
14534         if (false === cur.fireEvent('beforedeactivate')) {
14535             return false;
14536         }
14537         
14538         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14539             
14540             this.transition = true;
14541             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14542             var lr = dir == 'next' ? 'left' : 'right';
14543             pan.el.addClass(dir); // or prev
14544             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14545             cur.el.addClass(lr); // or right
14546             pan.el.addClass(lr);
14547             
14548             var _this = this;
14549             cur.el.on('transitionend', function() {
14550                 Roo.log("trans end?");
14551                 
14552                 pan.el.removeClass([lr,dir]);
14553                 pan.setActive(true);
14554                 
14555                 cur.el.removeClass([lr]);
14556                 cur.setActive(false);
14557                 
14558                 _this.transition = false;
14559                 
14560             }, this, { single:  true } );
14561             return true;
14562         }
14563         
14564         cur.setActive(false);
14565         pan.setActive(true);
14566         return true;
14567         
14568     },
14569     showPanelNext : function()
14570     {
14571         var i = this.indexOfPanel(this.getActivePanel());
14572         if (i > this.tabs.length) {
14573             return;
14574         }
14575         this.showPanel(this.tabs[i+1]);
14576     },
14577     showPanelPrev : function()
14578     {
14579         var i = this.indexOfPanel(this.getActivePanel());
14580         if (i  < 1) {
14581             return;
14582         }
14583         this.showPanel(this.tabs[i-1]);
14584     }
14585     
14586     
14587   
14588 });
14589
14590  
14591
14592  
14593  
14594 Roo.apply(Roo.bootstrap.TabGroup, {
14595     
14596     groups: {},
14597      /**
14598     * register a Navigation Group
14599     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14600     */
14601     register : function(navgrp)
14602     {
14603         this.groups[navgrp.navId] = navgrp;
14604         
14605     },
14606     /**
14607     * fetch a Navigation Group based on the navigation ID
14608     * if one does not exist , it will get created.
14609     * @param {string} the navgroup to add
14610     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14611     */
14612     get: function(navId) {
14613         if (typeof(this.groups[navId]) == 'undefined') {
14614             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14615         }
14616         return this.groups[navId] ;
14617     }
14618     
14619     
14620     
14621 });
14622
14623  /*
14624  * - LGPL
14625  *
14626  * TabPanel
14627  * 
14628  */
14629
14630 /**
14631  * @class Roo.bootstrap.TabPanel
14632  * @extends Roo.bootstrap.Component
14633  * Bootstrap TabPanel class
14634  * @cfg {Boolean} active panel active
14635  * @cfg {String} html panel content
14636  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14637  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14638  * 
14639  * 
14640  * @constructor
14641  * Create a new TabPanel
14642  * @param {Object} config The config object
14643  */
14644
14645 Roo.bootstrap.TabPanel = function(config){
14646     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14647     this.addEvents({
14648         /**
14649              * @event changed
14650              * Fires when the active status changes
14651              * @param {Roo.bootstrap.TabPanel} this
14652              * @param {Boolean} state the new state
14653             
14654          */
14655         'changed': true,
14656         /**
14657              * @event beforedeactivate
14658              * Fires before a tab is de-activated - can be used to do validation on a form.
14659              * @param {Roo.bootstrap.TabPanel} this
14660              * @return {Boolean} false if there is an error
14661             
14662          */
14663         'beforedeactivate': true
14664      });
14665     
14666     this.tabId = this.tabId || Roo.id();
14667   
14668 };
14669
14670 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14671     
14672     active: false,
14673     html: false,
14674     tabId: false,
14675     navId : false,
14676     
14677     getAutoCreate : function(){
14678         var cfg = {
14679             tag: 'div',
14680             // item is needed for carousel - not sure if it has any effect otherwise
14681             cls: 'tab-pane item',
14682             html: this.html || ''
14683         };
14684         
14685         if(this.active){
14686             cfg.cls += ' active';
14687         }
14688         
14689         if(this.tabId){
14690             cfg.tabId = this.tabId;
14691         }
14692         
14693         
14694         return cfg;
14695     },
14696     
14697     initEvents:  function()
14698     {
14699         Roo.log('-------- init events on tab panel ---------');
14700         
14701         var p = this.parent();
14702         this.navId = this.navId || p.navId;
14703         
14704         if (typeof(this.navId) != 'undefined') {
14705             // not really needed.. but just in case.. parent should be a NavGroup.
14706             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14707             Roo.log(['register', tg, this]);
14708             tg.register(this);
14709         }
14710     },
14711     
14712     
14713     onRender : function(ct, position)
14714     {
14715        // Roo.log("Call onRender: " + this.xtype);
14716         
14717         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14718         
14719         
14720         
14721         
14722         
14723     },
14724     
14725     setActive: function(state)
14726     {
14727         Roo.log("panel - set active " + this.tabId + "=" + state);
14728         
14729         this.active = state;
14730         if (!state) {
14731             this.el.removeClass('active');
14732             
14733         } else  if (!this.el.hasClass('active')) {
14734             this.el.addClass('active');
14735         }
14736         this.fireEvent('changed', this, state);
14737     }
14738     
14739     
14740 });
14741  
14742
14743  
14744
14745  /*
14746  * - LGPL
14747  *
14748  * DateField
14749  * 
14750  */
14751
14752 /**
14753  * @class Roo.bootstrap.DateField
14754  * @extends Roo.bootstrap.Input
14755  * Bootstrap DateField class
14756  * @cfg {Number} weekStart default 0
14757  * @cfg {String} viewMode default empty, (months|years)
14758  * @cfg {String} minViewMode default empty, (months|years)
14759  * @cfg {Number} startDate default -Infinity
14760  * @cfg {Number} endDate default Infinity
14761  * @cfg {Boolean} todayHighlight default false
14762  * @cfg {Boolean} todayBtn default false
14763  * @cfg {Boolean} calendarWeeks default false
14764  * @cfg {Object} daysOfWeekDisabled default empty
14765  * @cfg {Boolean} singleMode default false (true | false)
14766  * 
14767  * @cfg {Boolean} keyboardNavigation default true
14768  * @cfg {String} language default en
14769  * 
14770  * @constructor
14771  * Create a new DateField
14772  * @param {Object} config The config object
14773  */
14774
14775 Roo.bootstrap.DateField = function(config){
14776     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14777      this.addEvents({
14778             /**
14779              * @event show
14780              * Fires when this field show.
14781              * @param {Roo.bootstrap.DateField} this
14782              * @param {Mixed} date The date value
14783              */
14784             show : true,
14785             /**
14786              * @event show
14787              * Fires when this field hide.
14788              * @param {Roo.bootstrap.DateField} this
14789              * @param {Mixed} date The date value
14790              */
14791             hide : true,
14792             /**
14793              * @event select
14794              * Fires when select a date.
14795              * @param {Roo.bootstrap.DateField} this
14796              * @param {Mixed} date The date value
14797              */
14798             select : true
14799         });
14800 };
14801
14802 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14803     
14804     /**
14805      * @cfg {String} format
14806      * The default date format string which can be overriden for localization support.  The format must be
14807      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14808      */
14809     format : "m/d/y",
14810     /**
14811      * @cfg {String} altFormats
14812      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14813      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14814      */
14815     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14816     
14817     weekStart : 0,
14818     
14819     viewMode : '',
14820     
14821     minViewMode : '',
14822     
14823     todayHighlight : false,
14824     
14825     todayBtn: false,
14826     
14827     language: 'en',
14828     
14829     keyboardNavigation: true,
14830     
14831     calendarWeeks: false,
14832     
14833     startDate: -Infinity,
14834     
14835     endDate: Infinity,
14836     
14837     daysOfWeekDisabled: [],
14838     
14839     _events: [],
14840     
14841     singleMode : false,
14842     
14843     UTCDate: function()
14844     {
14845         return new Date(Date.UTC.apply(Date, arguments));
14846     },
14847     
14848     UTCToday: function()
14849     {
14850         var today = new Date();
14851         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14852     },
14853     
14854     getDate: function() {
14855             var d = this.getUTCDate();
14856             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14857     },
14858     
14859     getUTCDate: function() {
14860             return this.date;
14861     },
14862     
14863     setDate: function(d) {
14864             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14865     },
14866     
14867     setUTCDate: function(d) {
14868             this.date = d;
14869             this.setValue(this.formatDate(this.date));
14870     },
14871         
14872     onRender: function(ct, position)
14873     {
14874         
14875         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14876         
14877         this.language = this.language || 'en';
14878         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14879         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14880         
14881         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14882         this.format = this.format || 'm/d/y';
14883         this.isInline = false;
14884         this.isInput = true;
14885         this.component = this.el.select('.add-on', true).first() || false;
14886         this.component = (this.component && this.component.length === 0) ? false : this.component;
14887         this.hasInput = this.component && this.inputEL().length;
14888         
14889         if (typeof(this.minViewMode === 'string')) {
14890             switch (this.minViewMode) {
14891                 case 'months':
14892                     this.minViewMode = 1;
14893                     break;
14894                 case 'years':
14895                     this.minViewMode = 2;
14896                     break;
14897                 default:
14898                     this.minViewMode = 0;
14899                     break;
14900             }
14901         }
14902         
14903         if (typeof(this.viewMode === 'string')) {
14904             switch (this.viewMode) {
14905                 case 'months':
14906                     this.viewMode = 1;
14907                     break;
14908                 case 'years':
14909                     this.viewMode = 2;
14910                     break;
14911                 default:
14912                     this.viewMode = 0;
14913                     break;
14914             }
14915         }
14916                 
14917         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14918         
14919 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14920         
14921         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14922         
14923         this.picker().on('mousedown', this.onMousedown, this);
14924         this.picker().on('click', this.onClick, this);
14925         
14926         this.picker().addClass('datepicker-dropdown');
14927         
14928         this.startViewMode = this.viewMode;
14929         
14930         if(this.singleMode){
14931             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14932                 v.setVisibilityMode(Roo.Element.DISPLAY)
14933                 v.hide();
14934             });
14935             
14936             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14937                 v.setStyle('width', '189px');
14938             });
14939         }
14940         
14941         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14942             if(!this.calendarWeeks){
14943                 v.remove();
14944                 return;
14945             }
14946             
14947             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14948             v.attr('colspan', function(i, val){
14949                 return parseInt(val) + 1;
14950             });
14951         })
14952                         
14953         
14954         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14955         
14956         this.setStartDate(this.startDate);
14957         this.setEndDate(this.endDate);
14958         
14959         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14960         
14961         this.fillDow();
14962         this.fillMonths();
14963         this.update();
14964         this.showMode();
14965         
14966         if(this.isInline) {
14967             this.show();
14968         }
14969     },
14970     
14971     picker : function()
14972     {
14973         return this.pickerEl;
14974 //        return this.el.select('.datepicker', true).first();
14975     },
14976     
14977     fillDow: function()
14978     {
14979         var dowCnt = this.weekStart;
14980         
14981         var dow = {
14982             tag: 'tr',
14983             cn: [
14984                 
14985             ]
14986         };
14987         
14988         if(this.calendarWeeks){
14989             dow.cn.push({
14990                 tag: 'th',
14991                 cls: 'cw',
14992                 html: '&nbsp;'
14993             })
14994         }
14995         
14996         while (dowCnt < this.weekStart + 7) {
14997             dow.cn.push({
14998                 tag: 'th',
14999                 cls: 'dow',
15000                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15001             });
15002         }
15003         
15004         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15005     },
15006     
15007     fillMonths: function()
15008     {    
15009         var i = 0;
15010         var months = this.picker().select('>.datepicker-months td', true).first();
15011         
15012         months.dom.innerHTML = '';
15013         
15014         while (i < 12) {
15015             var month = {
15016                 tag: 'span',
15017                 cls: 'month',
15018                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15019             }
15020             
15021             months.createChild(month);
15022         }
15023         
15024     },
15025     
15026     update: function()
15027     {
15028         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;
15029         
15030         if (this.date < this.startDate) {
15031             this.viewDate = new Date(this.startDate);
15032         } else if (this.date > this.endDate) {
15033             this.viewDate = new Date(this.endDate);
15034         } else {
15035             this.viewDate = new Date(this.date);
15036         }
15037         
15038         this.fill();
15039     },
15040     
15041     fill: function() 
15042     {
15043         var d = new Date(this.viewDate),
15044                 year = d.getUTCFullYear(),
15045                 month = d.getUTCMonth(),
15046                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15047                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15048                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15049                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15050                 currentDate = this.date && this.date.valueOf(),
15051                 today = this.UTCToday();
15052         
15053         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15054         
15055 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15056         
15057 //        this.picker.select('>tfoot th.today').
15058 //                                              .text(dates[this.language].today)
15059 //                                              .toggle(this.todayBtn !== false);
15060     
15061         this.updateNavArrows();
15062         this.fillMonths();
15063                                                 
15064         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15065         
15066         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15067          
15068         prevMonth.setUTCDate(day);
15069         
15070         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15071         
15072         var nextMonth = new Date(prevMonth);
15073         
15074         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15075         
15076         nextMonth = nextMonth.valueOf();
15077         
15078         var fillMonths = false;
15079         
15080         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15081         
15082         while(prevMonth.valueOf() < nextMonth) {
15083             var clsName = '';
15084             
15085             if (prevMonth.getUTCDay() === this.weekStart) {
15086                 if(fillMonths){
15087                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15088                 }
15089                     
15090                 fillMonths = {
15091                     tag: 'tr',
15092                     cn: []
15093                 };
15094                 
15095                 if(this.calendarWeeks){
15096                     // ISO 8601: First week contains first thursday.
15097                     // ISO also states week starts on Monday, but we can be more abstract here.
15098                     var
15099                     // Start of current week: based on weekstart/current date
15100                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15101                     // Thursday of this week
15102                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15103                     // First Thursday of year, year from thursday
15104                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15105                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15106                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15107                     
15108                     fillMonths.cn.push({
15109                         tag: 'td',
15110                         cls: 'cw',
15111                         html: calWeek
15112                     });
15113                 }
15114             }
15115             
15116             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15117                 clsName += ' old';
15118             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15119                 clsName += ' new';
15120             }
15121             if (this.todayHighlight &&
15122                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15123                 prevMonth.getUTCMonth() == today.getMonth() &&
15124                 prevMonth.getUTCDate() == today.getDate()) {
15125                 clsName += ' today';
15126             }
15127             
15128             if (currentDate && prevMonth.valueOf() === currentDate) {
15129                 clsName += ' active';
15130             }
15131             
15132             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15133                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15134                     clsName += ' disabled';
15135             }
15136             
15137             fillMonths.cn.push({
15138                 tag: 'td',
15139                 cls: 'day ' + clsName,
15140                 html: prevMonth.getDate()
15141             })
15142             
15143             prevMonth.setDate(prevMonth.getDate()+1);
15144         }
15145           
15146         var currentYear = this.date && this.date.getUTCFullYear();
15147         var currentMonth = this.date && this.date.getUTCMonth();
15148         
15149         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15150         
15151         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15152             v.removeClass('active');
15153             
15154             if(currentYear === year && k === currentMonth){
15155                 v.addClass('active');
15156             }
15157             
15158             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15159                 v.addClass('disabled');
15160             }
15161             
15162         });
15163         
15164         
15165         year = parseInt(year/10, 10) * 10;
15166         
15167         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15168         
15169         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15170         
15171         year -= 1;
15172         for (var i = -1; i < 11; i++) {
15173             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15174                 tag: 'span',
15175                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15176                 html: year
15177             })
15178             
15179             year += 1;
15180         }
15181     },
15182     
15183     showMode: function(dir) 
15184     {
15185         if (dir) {
15186             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15187         }
15188         
15189         Roo.each(this.picker().select('>div',true).elements, function(v){
15190             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15191             v.hide();
15192         });
15193         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15194     },
15195     
15196     place: function()
15197     {
15198         if(this.isInline) return;
15199         
15200         this.picker().removeClass(['bottom', 'top']);
15201         
15202         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15203             /*
15204              * place to the top of element!
15205              *
15206              */
15207             
15208             this.picker().addClass('top');
15209             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15210             
15211             return;
15212         }
15213         
15214         this.picker().addClass('bottom');
15215         
15216         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15217     },
15218     
15219     parseDate : function(value)
15220     {
15221         if(!value || value instanceof Date){
15222             return value;
15223         }
15224         var v = Date.parseDate(value, this.format);
15225         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15226             v = Date.parseDate(value, 'Y-m-d');
15227         }
15228         if(!v && this.altFormats){
15229             if(!this.altFormatsArray){
15230                 this.altFormatsArray = this.altFormats.split("|");
15231             }
15232             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15233                 v = Date.parseDate(value, this.altFormatsArray[i]);
15234             }
15235         }
15236         return v;
15237     },
15238     
15239     formatDate : function(date, fmt)
15240     {   
15241         return (!date || !(date instanceof Date)) ?
15242         date : date.dateFormat(fmt || this.format);
15243     },
15244     
15245     onFocus : function()
15246     {
15247         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15248         this.show();
15249     },
15250     
15251     onBlur : function()
15252     {
15253         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15254         
15255         var d = this.inputEl().getValue();
15256         
15257         this.setValue(d);
15258                 
15259         this.hide();
15260     },
15261     
15262     show : function()
15263     {
15264         this.picker().show();
15265         this.update();
15266         this.place();
15267         
15268         this.fireEvent('show', this, this.date);
15269     },
15270     
15271     hide : function()
15272     {
15273         if(this.isInline) return;
15274         this.picker().hide();
15275         this.viewMode = this.startViewMode;
15276         this.showMode();
15277         
15278         this.fireEvent('hide', this, this.date);
15279         
15280     },
15281     
15282     onMousedown: function(e)
15283     {
15284         e.stopPropagation();
15285         e.preventDefault();
15286     },
15287     
15288     keyup: function(e)
15289     {
15290         Roo.bootstrap.DateField.superclass.keyup.call(this);
15291         this.update();
15292     },
15293
15294     setValue: function(v)
15295     {
15296         
15297         // v can be a string or a date..
15298         
15299         
15300         var d = new Date(this.parseDate(v) ).clearTime();
15301         
15302         if(isNaN(d.getTime())){
15303             this.date = this.viewDate = '';
15304             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15305             return;
15306         }
15307         
15308         v = this.formatDate(d);
15309         
15310         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15311         
15312         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15313      
15314         this.update();
15315
15316         this.fireEvent('select', this, this.date);
15317         
15318     },
15319     
15320     getValue: function()
15321     {
15322         return this.formatDate(this.date);
15323     },
15324     
15325     fireKey: function(e)
15326     {
15327         if (!this.picker().isVisible()){
15328             if (e.keyCode == 27) // allow escape to hide and re-show picker
15329                 this.show();
15330             return;
15331         }
15332         
15333         var dateChanged = false,
15334         dir, day, month,
15335         newDate, newViewDate;
15336         
15337         switch(e.keyCode){
15338             case 27: // escape
15339                 this.hide();
15340                 e.preventDefault();
15341                 break;
15342             case 37: // left
15343             case 39: // right
15344                 if (!this.keyboardNavigation) break;
15345                 dir = e.keyCode == 37 ? -1 : 1;
15346                 
15347                 if (e.ctrlKey){
15348                     newDate = this.moveYear(this.date, dir);
15349                     newViewDate = this.moveYear(this.viewDate, dir);
15350                 } else if (e.shiftKey){
15351                     newDate = this.moveMonth(this.date, dir);
15352                     newViewDate = this.moveMonth(this.viewDate, dir);
15353                 } else {
15354                     newDate = new Date(this.date);
15355                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15356                     newViewDate = new Date(this.viewDate);
15357                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15358                 }
15359                 if (this.dateWithinRange(newDate)){
15360                     this.date = newDate;
15361                     this.viewDate = newViewDate;
15362                     this.setValue(this.formatDate(this.date));
15363 //                    this.update();
15364                     e.preventDefault();
15365                     dateChanged = true;
15366                 }
15367                 break;
15368             case 38: // up
15369             case 40: // down
15370                 if (!this.keyboardNavigation) break;
15371                 dir = e.keyCode == 38 ? -1 : 1;
15372                 if (e.ctrlKey){
15373                     newDate = this.moveYear(this.date, dir);
15374                     newViewDate = this.moveYear(this.viewDate, dir);
15375                 } else if (e.shiftKey){
15376                     newDate = this.moveMonth(this.date, dir);
15377                     newViewDate = this.moveMonth(this.viewDate, dir);
15378                 } else {
15379                     newDate = new Date(this.date);
15380                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15381                     newViewDate = new Date(this.viewDate);
15382                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15383                 }
15384                 if (this.dateWithinRange(newDate)){
15385                     this.date = newDate;
15386                     this.viewDate = newViewDate;
15387                     this.setValue(this.formatDate(this.date));
15388 //                    this.update();
15389                     e.preventDefault();
15390                     dateChanged = true;
15391                 }
15392                 break;
15393             case 13: // enter
15394                 this.setValue(this.formatDate(this.date));
15395                 this.hide();
15396                 e.preventDefault();
15397                 break;
15398             case 9: // tab
15399                 this.setValue(this.formatDate(this.date));
15400                 this.hide();
15401                 break;
15402             case 16: // shift
15403             case 17: // ctrl
15404             case 18: // alt
15405                 break;
15406             default :
15407                 this.hide();
15408                 
15409         }
15410     },
15411     
15412     
15413     onClick: function(e) 
15414     {
15415         e.stopPropagation();
15416         e.preventDefault();
15417         
15418         var target = e.getTarget();
15419         
15420         if(target.nodeName.toLowerCase() === 'i'){
15421             target = Roo.get(target).dom.parentNode;
15422         }
15423         
15424         var nodeName = target.nodeName;
15425         var className = target.className;
15426         var html = target.innerHTML;
15427         //Roo.log(nodeName);
15428         
15429         switch(nodeName.toLowerCase()) {
15430             case 'th':
15431                 switch(className) {
15432                     case 'switch':
15433                         this.showMode(1);
15434                         break;
15435                     case 'prev':
15436                     case 'next':
15437                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15438                         switch(this.viewMode){
15439                                 case 0:
15440                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15441                                         break;
15442                                 case 1:
15443                                 case 2:
15444                                         this.viewDate = this.moveYear(this.viewDate, dir);
15445                                         break;
15446                         }
15447                         this.fill();
15448                         break;
15449                     case 'today':
15450                         var date = new Date();
15451                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15452 //                        this.fill()
15453                         this.setValue(this.formatDate(this.date));
15454                         
15455                         this.hide();
15456                         break;
15457                 }
15458                 break;
15459             case 'span':
15460                 if (className.indexOf('disabled') < 0) {
15461                     this.viewDate.setUTCDate(1);
15462                     if (className.indexOf('month') > -1) {
15463                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15464                     } else {
15465                         var year = parseInt(html, 10) || 0;
15466                         this.viewDate.setUTCFullYear(year);
15467                         
15468                     }
15469                     
15470                     if(this.singleMode){
15471                         this.setValue(this.formatDate(this.viewDate));
15472                         this.hide();
15473                         return;
15474                     }
15475                     
15476                     this.showMode(-1);
15477                     this.fill();
15478                 }
15479                 break;
15480                 
15481             case 'td':
15482                 //Roo.log(className);
15483                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15484                     var day = parseInt(html, 10) || 1;
15485                     var year = this.viewDate.getUTCFullYear(),
15486                         month = this.viewDate.getUTCMonth();
15487
15488                     if (className.indexOf('old') > -1) {
15489                         if(month === 0 ){
15490                             month = 11;
15491                             year -= 1;
15492                         }else{
15493                             month -= 1;
15494                         }
15495                     } else if (className.indexOf('new') > -1) {
15496                         if (month == 11) {
15497                             month = 0;
15498                             year += 1;
15499                         } else {
15500                             month += 1;
15501                         }
15502                     }
15503                     //Roo.log([year,month,day]);
15504                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15505                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15506 //                    this.fill();
15507                     //Roo.log(this.formatDate(this.date));
15508                     this.setValue(this.formatDate(this.date));
15509                     this.hide();
15510                 }
15511                 break;
15512         }
15513     },
15514     
15515     setStartDate: function(startDate)
15516     {
15517         this.startDate = startDate || -Infinity;
15518         if (this.startDate !== -Infinity) {
15519             this.startDate = this.parseDate(this.startDate);
15520         }
15521         this.update();
15522         this.updateNavArrows();
15523     },
15524
15525     setEndDate: function(endDate)
15526     {
15527         this.endDate = endDate || Infinity;
15528         if (this.endDate !== Infinity) {
15529             this.endDate = this.parseDate(this.endDate);
15530         }
15531         this.update();
15532         this.updateNavArrows();
15533     },
15534     
15535     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15536     {
15537         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15538         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15539             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15540         }
15541         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15542             return parseInt(d, 10);
15543         });
15544         this.update();
15545         this.updateNavArrows();
15546     },
15547     
15548     updateNavArrows: function() 
15549     {
15550         if(this.singleMode){
15551             return;
15552         }
15553         
15554         var d = new Date(this.viewDate),
15555         year = d.getUTCFullYear(),
15556         month = d.getUTCMonth();
15557         
15558         Roo.each(this.picker().select('.prev', true).elements, function(v){
15559             v.show();
15560             switch (this.viewMode) {
15561                 case 0:
15562
15563                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15564                         v.hide();
15565                     }
15566                     break;
15567                 case 1:
15568                 case 2:
15569                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15570                         v.hide();
15571                     }
15572                     break;
15573             }
15574         });
15575         
15576         Roo.each(this.picker().select('.next', true).elements, function(v){
15577             v.show();
15578             switch (this.viewMode) {
15579                 case 0:
15580
15581                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15582                         v.hide();
15583                     }
15584                     break;
15585                 case 1:
15586                 case 2:
15587                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15588                         v.hide();
15589                     }
15590                     break;
15591             }
15592         })
15593     },
15594     
15595     moveMonth: function(date, dir)
15596     {
15597         if (!dir) return date;
15598         var new_date = new Date(date.valueOf()),
15599         day = new_date.getUTCDate(),
15600         month = new_date.getUTCMonth(),
15601         mag = Math.abs(dir),
15602         new_month, test;
15603         dir = dir > 0 ? 1 : -1;
15604         if (mag == 1){
15605             test = dir == -1
15606             // If going back one month, make sure month is not current month
15607             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15608             ? function(){
15609                 return new_date.getUTCMonth() == month;
15610             }
15611             // If going forward one month, make sure month is as expected
15612             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15613             : function(){
15614                 return new_date.getUTCMonth() != new_month;
15615             };
15616             new_month = month + dir;
15617             new_date.setUTCMonth(new_month);
15618             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15619             if (new_month < 0 || new_month > 11)
15620                 new_month = (new_month + 12) % 12;
15621         } else {
15622             // For magnitudes >1, move one month at a time...
15623             for (var i=0; i<mag; i++)
15624                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15625                 new_date = this.moveMonth(new_date, dir);
15626             // ...then reset the day, keeping it in the new month
15627             new_month = new_date.getUTCMonth();
15628             new_date.setUTCDate(day);
15629             test = function(){
15630                 return new_month != new_date.getUTCMonth();
15631             };
15632         }
15633         // Common date-resetting loop -- if date is beyond end of month, make it
15634         // end of month
15635         while (test()){
15636             new_date.setUTCDate(--day);
15637             new_date.setUTCMonth(new_month);
15638         }
15639         return new_date;
15640     },
15641
15642     moveYear: function(date, dir)
15643     {
15644         return this.moveMonth(date, dir*12);
15645     },
15646
15647     dateWithinRange: function(date)
15648     {
15649         return date >= this.startDate && date <= this.endDate;
15650     },
15651
15652     
15653     remove: function() 
15654     {
15655         this.picker().remove();
15656     }
15657    
15658 });
15659
15660 Roo.apply(Roo.bootstrap.DateField,  {
15661     
15662     head : {
15663         tag: 'thead',
15664         cn: [
15665         {
15666             tag: 'tr',
15667             cn: [
15668             {
15669                 tag: 'th',
15670                 cls: 'prev',
15671                 html: '<i class="fa fa-arrow-left"/>'
15672             },
15673             {
15674                 tag: 'th',
15675                 cls: 'switch',
15676                 colspan: '5'
15677             },
15678             {
15679                 tag: 'th',
15680                 cls: 'next',
15681                 html: '<i class="fa fa-arrow-right"/>'
15682             }
15683
15684             ]
15685         }
15686         ]
15687     },
15688     
15689     content : {
15690         tag: 'tbody',
15691         cn: [
15692         {
15693             tag: 'tr',
15694             cn: [
15695             {
15696                 tag: 'td',
15697                 colspan: '7'
15698             }
15699             ]
15700         }
15701         ]
15702     },
15703     
15704     footer : {
15705         tag: 'tfoot',
15706         cn: [
15707         {
15708             tag: 'tr',
15709             cn: [
15710             {
15711                 tag: 'th',
15712                 colspan: '7',
15713                 cls: 'today'
15714             }
15715                     
15716             ]
15717         }
15718         ]
15719     },
15720     
15721     dates:{
15722         en: {
15723             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15724             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15725             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15726             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15727             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15728             today: "Today"
15729         }
15730     },
15731     
15732     modes: [
15733     {
15734         clsName: 'days',
15735         navFnc: 'Month',
15736         navStep: 1
15737     },
15738     {
15739         clsName: 'months',
15740         navFnc: 'FullYear',
15741         navStep: 1
15742     },
15743     {
15744         clsName: 'years',
15745         navFnc: 'FullYear',
15746         navStep: 10
15747     }]
15748 });
15749
15750 Roo.apply(Roo.bootstrap.DateField,  {
15751   
15752     template : {
15753         tag: 'div',
15754         cls: 'datepicker dropdown-menu roo-dynamic',
15755         cn: [
15756         {
15757             tag: 'div',
15758             cls: 'datepicker-days',
15759             cn: [
15760             {
15761                 tag: 'table',
15762                 cls: 'table-condensed',
15763                 cn:[
15764                 Roo.bootstrap.DateField.head,
15765                 {
15766                     tag: 'tbody'
15767                 },
15768                 Roo.bootstrap.DateField.footer
15769                 ]
15770             }
15771             ]
15772         },
15773         {
15774             tag: 'div',
15775             cls: 'datepicker-months',
15776             cn: [
15777             {
15778                 tag: 'table',
15779                 cls: 'table-condensed',
15780                 cn:[
15781                 Roo.bootstrap.DateField.head,
15782                 Roo.bootstrap.DateField.content,
15783                 Roo.bootstrap.DateField.footer
15784                 ]
15785             }
15786             ]
15787         },
15788         {
15789             tag: 'div',
15790             cls: 'datepicker-years',
15791             cn: [
15792             {
15793                 tag: 'table',
15794                 cls: 'table-condensed',
15795                 cn:[
15796                 Roo.bootstrap.DateField.head,
15797                 Roo.bootstrap.DateField.content,
15798                 Roo.bootstrap.DateField.footer
15799                 ]
15800             }
15801             ]
15802         }
15803         ]
15804     }
15805 });
15806
15807  
15808
15809  /*
15810  * - LGPL
15811  *
15812  * TimeField
15813  * 
15814  */
15815
15816 /**
15817  * @class Roo.bootstrap.TimeField
15818  * @extends Roo.bootstrap.Input
15819  * Bootstrap DateField class
15820  * 
15821  * 
15822  * @constructor
15823  * Create a new TimeField
15824  * @param {Object} config The config object
15825  */
15826
15827 Roo.bootstrap.TimeField = function(config){
15828     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15829     this.addEvents({
15830             /**
15831              * @event show
15832              * Fires when this field show.
15833              * @param {Roo.bootstrap.DateField} thisthis
15834              * @param {Mixed} date The date value
15835              */
15836             show : true,
15837             /**
15838              * @event show
15839              * Fires when this field hide.
15840              * @param {Roo.bootstrap.DateField} this
15841              * @param {Mixed} date The date value
15842              */
15843             hide : true,
15844             /**
15845              * @event select
15846              * Fires when select a date.
15847              * @param {Roo.bootstrap.DateField} this
15848              * @param {Mixed} date The date value
15849              */
15850             select : true
15851         });
15852 };
15853
15854 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15855     
15856     /**
15857      * @cfg {String} format
15858      * The default time format string which can be overriden for localization support.  The format must be
15859      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15860      */
15861     format : "H:i",
15862        
15863     onRender: function(ct, position)
15864     {
15865         
15866         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15867                 
15868         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15869         
15870         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15871         
15872         this.pop = this.picker().select('>.datepicker-time',true).first();
15873         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15874         
15875         this.picker().on('mousedown', this.onMousedown, this);
15876         this.picker().on('click', this.onClick, this);
15877         
15878         this.picker().addClass('datepicker-dropdown');
15879     
15880         this.fillTime();
15881         this.update();
15882             
15883         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15884         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15885         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15886         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15887         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15888         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15889
15890     },
15891     
15892     fireKey: function(e){
15893         if (!this.picker().isVisible()){
15894             if (e.keyCode == 27) { // allow escape to hide and re-show picker
15895                 this.show();
15896             }
15897             return;
15898         }
15899
15900         e.preventDefault();
15901         
15902         switch(e.keyCode){
15903             case 27: // escape
15904                 this.hide();
15905                 break;
15906             case 37: // left
15907             case 39: // right
15908                 this.onTogglePeriod();
15909                 break;
15910             case 38: // up
15911                 this.onIncrementMinutes();
15912                 break;
15913             case 40: // down
15914                 this.onDecrementMinutes();
15915                 break;
15916             case 13: // enter
15917             case 9: // tab
15918                 this.setTime();
15919                 break;
15920         }
15921     },
15922     
15923     onClick: function(e) {
15924         e.stopPropagation();
15925         e.preventDefault();
15926     },
15927     
15928     picker : function()
15929     {
15930         return this.el.select('.datepicker', true).first();
15931     },
15932     
15933     fillTime: function()
15934     {    
15935         var time = this.pop.select('tbody', true).first();
15936         
15937         time.dom.innerHTML = '';
15938         
15939         time.createChild({
15940             tag: 'tr',
15941             cn: [
15942                 {
15943                     tag: 'td',
15944                     cn: [
15945                         {
15946                             tag: 'a',
15947                             href: '#',
15948                             cls: 'btn',
15949                             cn: [
15950                                 {
15951                                     tag: 'span',
15952                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15953                                 }
15954                             ]
15955                         } 
15956                     ]
15957                 },
15958                 {
15959                     tag: 'td',
15960                     cls: 'separator'
15961                 },
15962                 {
15963                     tag: 'td',
15964                     cn: [
15965                         {
15966                             tag: 'a',
15967                             href: '#',
15968                             cls: 'btn',
15969                             cn: [
15970                                 {
15971                                     tag: 'span',
15972                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15973                                 }
15974                             ]
15975                         }
15976                     ]
15977                 },
15978                 {
15979                     tag: 'td',
15980                     cls: 'separator'
15981                 }
15982             ]
15983         });
15984         
15985         time.createChild({
15986             tag: 'tr',
15987             cn: [
15988                 {
15989                     tag: 'td',
15990                     cn: [
15991                         {
15992                             tag: 'span',
15993                             cls: 'timepicker-hour',
15994                             html: '00'
15995                         }  
15996                     ]
15997                 },
15998                 {
15999                     tag: 'td',
16000                     cls: 'separator',
16001                     html: ':'
16002                 },
16003                 {
16004                     tag: 'td',
16005                     cn: [
16006                         {
16007                             tag: 'span',
16008                             cls: 'timepicker-minute',
16009                             html: '00'
16010                         }  
16011                     ]
16012                 },
16013                 {
16014                     tag: 'td',
16015                     cls: 'separator'
16016                 },
16017                 {
16018                     tag: 'td',
16019                     cn: [
16020                         {
16021                             tag: 'button',
16022                             type: 'button',
16023                             cls: 'btn btn-primary period',
16024                             html: 'AM'
16025                             
16026                         }
16027                     ]
16028                 }
16029             ]
16030         });
16031         
16032         time.createChild({
16033             tag: 'tr',
16034             cn: [
16035                 {
16036                     tag: 'td',
16037                     cn: [
16038                         {
16039                             tag: 'a',
16040                             href: '#',
16041                             cls: 'btn',
16042                             cn: [
16043                                 {
16044                                     tag: 'span',
16045                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16046                                 }
16047                             ]
16048                         }
16049                     ]
16050                 },
16051                 {
16052                     tag: 'td',
16053                     cls: 'separator'
16054                 },
16055                 {
16056                     tag: 'td',
16057                     cn: [
16058                         {
16059                             tag: 'a',
16060                             href: '#',
16061                             cls: 'btn',
16062                             cn: [
16063                                 {
16064                                     tag: 'span',
16065                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16066                                 }
16067                             ]
16068                         }
16069                     ]
16070                 },
16071                 {
16072                     tag: 'td',
16073                     cls: 'separator'
16074                 }
16075             ]
16076         });
16077         
16078     },
16079     
16080     update: function()
16081     {
16082         
16083         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16084         
16085         this.fill();
16086     },
16087     
16088     fill: function() 
16089     {
16090         var hours = this.time.getHours();
16091         var minutes = this.time.getMinutes();
16092         var period = 'AM';
16093         
16094         if(hours > 11){
16095             period = 'PM';
16096         }
16097         
16098         if(hours == 0){
16099             hours = 12;
16100         }
16101         
16102         
16103         if(hours > 12){
16104             hours = hours - 12;
16105         }
16106         
16107         if(hours < 10){
16108             hours = '0' + hours;
16109         }
16110         
16111         if(minutes < 10){
16112             minutes = '0' + minutes;
16113         }
16114         
16115         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16116         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16117         this.pop.select('button', true).first().dom.innerHTML = period;
16118         
16119     },
16120     
16121     place: function()
16122     {   
16123         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16124         
16125         var cls = ['bottom'];
16126         
16127         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16128             cls.pop();
16129             cls.push('top');
16130         }
16131         
16132         cls.push('right');
16133         
16134         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16135             cls.pop();
16136             cls.push('left');
16137         }
16138         
16139         this.picker().addClass(cls.join('-'));
16140         
16141         var _this = this;
16142         
16143         Roo.each(cls, function(c){
16144             if(c == 'bottom'){
16145                 _this.picker().setTop(_this.inputEl().getHeight());
16146                 return;
16147             }
16148             if(c == 'top'){
16149                 _this.picker().setTop(0 - _this.picker().getHeight());
16150                 return;
16151             }
16152             
16153             if(c == 'left'){
16154                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16155                 return;
16156             }
16157             if(c == 'right'){
16158                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16159                 return;
16160             }
16161         });
16162         
16163     },
16164   
16165     onFocus : function()
16166     {
16167         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16168         this.show();
16169     },
16170     
16171     onBlur : function()
16172     {
16173         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16174         this.hide();
16175     },
16176     
16177     show : function()
16178     {
16179         this.picker().show();
16180         this.pop.show();
16181         this.update();
16182         this.place();
16183         
16184         this.fireEvent('show', this, this.date);
16185     },
16186     
16187     hide : function()
16188     {
16189         this.picker().hide();
16190         this.pop.hide();
16191         
16192         this.fireEvent('hide', this, this.date);
16193     },
16194     
16195     setTime : function()
16196     {
16197         this.hide();
16198         this.setValue(this.time.format(this.format));
16199         
16200         this.fireEvent('select', this, this.date);
16201         
16202         
16203     },
16204     
16205     onMousedown: function(e){
16206         e.stopPropagation();
16207         e.preventDefault();
16208     },
16209     
16210     onIncrementHours: function()
16211     {
16212         Roo.log('onIncrementHours');
16213         this.time = this.time.add(Date.HOUR, 1);
16214         this.update();
16215         
16216     },
16217     
16218     onDecrementHours: function()
16219     {
16220         Roo.log('onDecrementHours');
16221         this.time = this.time.add(Date.HOUR, -1);
16222         this.update();
16223     },
16224     
16225     onIncrementMinutes: function()
16226     {
16227         Roo.log('onIncrementMinutes');
16228         this.time = this.time.add(Date.MINUTE, 1);
16229         this.update();
16230     },
16231     
16232     onDecrementMinutes: function()
16233     {
16234         Roo.log('onDecrementMinutes');
16235         this.time = this.time.add(Date.MINUTE, -1);
16236         this.update();
16237     },
16238     
16239     onTogglePeriod: function()
16240     {
16241         Roo.log('onTogglePeriod');
16242         this.time = this.time.add(Date.HOUR, 12);
16243         this.update();
16244     }
16245     
16246    
16247 });
16248
16249 Roo.apply(Roo.bootstrap.TimeField,  {
16250     
16251     content : {
16252         tag: 'tbody',
16253         cn: [
16254             {
16255                 tag: 'tr',
16256                 cn: [
16257                 {
16258                     tag: 'td',
16259                     colspan: '7'
16260                 }
16261                 ]
16262             }
16263         ]
16264     },
16265     
16266     footer : {
16267         tag: 'tfoot',
16268         cn: [
16269             {
16270                 tag: 'tr',
16271                 cn: [
16272                 {
16273                     tag: 'th',
16274                     colspan: '7',
16275                     cls: '',
16276                     cn: [
16277                         {
16278                             tag: 'button',
16279                             cls: 'btn btn-info ok',
16280                             html: 'OK'
16281                         }
16282                     ]
16283                 }
16284
16285                 ]
16286             }
16287         ]
16288     }
16289 });
16290
16291 Roo.apply(Roo.bootstrap.TimeField,  {
16292   
16293     template : {
16294         tag: 'div',
16295         cls: 'datepicker dropdown-menu',
16296         cn: [
16297             {
16298                 tag: 'div',
16299                 cls: 'datepicker-time',
16300                 cn: [
16301                 {
16302                     tag: 'table',
16303                     cls: 'table-condensed',
16304                     cn:[
16305                     Roo.bootstrap.TimeField.content,
16306                     Roo.bootstrap.TimeField.footer
16307                     ]
16308                 }
16309                 ]
16310             }
16311         ]
16312     }
16313 });
16314
16315  
16316
16317  /*
16318  * - LGPL
16319  *
16320  * MonthField
16321  * 
16322  */
16323
16324 /**
16325  * @class Roo.bootstrap.MonthField
16326  * @extends Roo.bootstrap.Input
16327  * Bootstrap MonthField class
16328  * 
16329  * @cfg {String} language default en
16330  * 
16331  * @constructor
16332  * Create a new MonthField
16333  * @param {Object} config The config object
16334  */
16335
16336 Roo.bootstrap.MonthField = function(config){
16337     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16338     
16339     this.addEvents({
16340         /**
16341          * @event show
16342          * Fires when this field show.
16343          * @param {Roo.bootstrap.MonthField} this
16344          * @param {Mixed} date The date value
16345          */
16346         show : true,
16347         /**
16348          * @event show
16349          * Fires when this field hide.
16350          * @param {Roo.bootstrap.MonthField} this
16351          * @param {Mixed} date The date value
16352          */
16353         hide : true,
16354         /**
16355          * @event select
16356          * Fires when select a date.
16357          * @param {Roo.bootstrap.MonthField} this
16358          * @param {String} oldvalue The old value
16359          * @param {String} newvalue The new value
16360          */
16361         select : true
16362     });
16363 };
16364
16365 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16366     
16367     onRender: function(ct, position)
16368     {
16369         
16370         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16371         
16372         this.language = this.language || 'en';
16373         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16374         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16375         
16376         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16377         this.isInline = false;
16378         this.isInput = true;
16379         this.component = this.el.select('.add-on', true).first() || false;
16380         this.component = (this.component && this.component.length === 0) ? false : this.component;
16381         this.hasInput = this.component && this.inputEL().length;
16382         
16383         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16384         
16385         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16386         
16387         this.picker().on('mousedown', this.onMousedown, this);
16388         this.picker().on('click', this.onClick, this);
16389         
16390         this.picker().addClass('datepicker-dropdown');
16391         
16392         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16393             v.setStyle('width', '189px');
16394         });
16395         
16396         this.fillMonths();
16397         
16398         this.update();
16399         
16400         if(this.isInline) {
16401             this.show();
16402         }
16403         
16404     },
16405     
16406     setValue: function(v, suppressEvent)
16407     {   
16408         var o = this.getValue();
16409         
16410         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16411         
16412         this.update();
16413
16414         if(suppressEvent !== true){
16415             this.fireEvent('select', this, o, v);
16416         }
16417         
16418     },
16419     
16420     getValue: function()
16421     {
16422         return this.value;
16423     },
16424     
16425     onClick: function(e) 
16426     {
16427         e.stopPropagation();
16428         e.preventDefault();
16429         
16430         var target = e.getTarget();
16431         
16432         if(target.nodeName.toLowerCase() === 'i'){
16433             target = Roo.get(target).dom.parentNode;
16434         }
16435         
16436         var nodeName = target.nodeName;
16437         var className = target.className;
16438         var html = target.innerHTML;
16439         
16440         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16441             return;
16442         }
16443         
16444         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16445         
16446         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16447         
16448         this.hide();
16449                         
16450     },
16451     
16452     picker : function()
16453     {
16454         return this.pickerEl;
16455     },
16456     
16457     fillMonths: function()
16458     {    
16459         var i = 0;
16460         var months = this.picker().select('>.datepicker-months td', true).first();
16461         
16462         months.dom.innerHTML = '';
16463         
16464         while (i < 12) {
16465             var month = {
16466                 tag: 'span',
16467                 cls: 'month',
16468                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16469             }
16470             
16471             months.createChild(month);
16472         }
16473         
16474     },
16475     
16476     update: function()
16477     {
16478         var _this = this;
16479         
16480         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16481             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16482         }
16483         
16484         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16485             e.removeClass('active');
16486             
16487             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16488                 e.addClass('active');
16489             }
16490         })
16491     },
16492     
16493     place: function()
16494     {
16495         if(this.isInline) return;
16496         
16497         this.picker().removeClass(['bottom', 'top']);
16498         
16499         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16500             /*
16501              * place to the top of element!
16502              *
16503              */
16504             
16505             this.picker().addClass('top');
16506             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16507             
16508             return;
16509         }
16510         
16511         this.picker().addClass('bottom');
16512         
16513         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16514     },
16515     
16516     onFocus : function()
16517     {
16518         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16519         this.show();
16520     },
16521     
16522     onBlur : function()
16523     {
16524         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16525         
16526         var d = this.inputEl().getValue();
16527         
16528         this.setValue(d);
16529                 
16530         this.hide();
16531     },
16532     
16533     show : function()
16534     {
16535         this.picker().show();
16536         this.picker().select('>.datepicker-months', true).first().show();
16537         this.update();
16538         this.place();
16539         
16540         this.fireEvent('show', this, this.date);
16541     },
16542     
16543     hide : function()
16544     {
16545         if(this.isInline) return;
16546         this.picker().hide();
16547         this.fireEvent('hide', this, this.date);
16548         
16549     },
16550     
16551     onMousedown: function(e)
16552     {
16553         e.stopPropagation();
16554         e.preventDefault();
16555     },
16556     
16557     keyup: function(e)
16558     {
16559         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16560         this.update();
16561     },
16562
16563     fireKey: function(e)
16564     {
16565         if (!this.picker().isVisible()){
16566             if (e.keyCode == 27) // allow escape to hide and re-show picker
16567                 this.show();
16568             return;
16569         }
16570         
16571         var dir;
16572         
16573         switch(e.keyCode){
16574             case 27: // escape
16575                 this.hide();
16576                 e.preventDefault();
16577                 break;
16578             case 37: // left
16579             case 39: // right
16580                 dir = e.keyCode == 37 ? -1 : 1;
16581                 
16582                 this.vIndex = this.vIndex + dir;
16583                 
16584                 if(this.vIndex < 0){
16585                     this.vIndex = 0;
16586                 }
16587                 
16588                 if(this.vIndex > 11){
16589                     this.vIndex = 11;
16590                 }
16591                 
16592                 if(isNaN(this.vIndex)){
16593                     this.vIndex = 0;
16594                 }
16595                 
16596                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16597                 
16598                 break;
16599             case 38: // up
16600             case 40: // down
16601                 
16602                 dir = e.keyCode == 38 ? -1 : 1;
16603                 
16604                 this.vIndex = this.vIndex + dir * 4;
16605                 
16606                 if(this.vIndex < 0){
16607                     this.vIndex = 0;
16608                 }
16609                 
16610                 if(this.vIndex > 11){
16611                     this.vIndex = 11;
16612                 }
16613                 
16614                 if(isNaN(this.vIndex)){
16615                     this.vIndex = 0;
16616                 }
16617                 
16618                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16619                 break;
16620                 
16621             case 13: // enter
16622                 
16623                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16624                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16625                 }
16626                 
16627                 this.hide();
16628                 e.preventDefault();
16629                 break;
16630             case 9: // tab
16631                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16632                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16633                 }
16634                 this.hide();
16635                 break;
16636             case 16: // shift
16637             case 17: // ctrl
16638             case 18: // alt
16639                 break;
16640             default :
16641                 this.hide();
16642                 
16643         }
16644     },
16645     
16646     remove: function() 
16647     {
16648         this.picker().remove();
16649     }
16650    
16651 });
16652
16653 Roo.apply(Roo.bootstrap.MonthField,  {
16654     
16655     content : {
16656         tag: 'tbody',
16657         cn: [
16658         {
16659             tag: 'tr',
16660             cn: [
16661             {
16662                 tag: 'td',
16663                 colspan: '7'
16664             }
16665             ]
16666         }
16667         ]
16668     },
16669     
16670     dates:{
16671         en: {
16672             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16673             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16674         }
16675     }
16676 });
16677
16678 Roo.apply(Roo.bootstrap.MonthField,  {
16679   
16680     template : {
16681         tag: 'div',
16682         cls: 'datepicker dropdown-menu roo-dynamic',
16683         cn: [
16684             {
16685                 tag: 'div',
16686                 cls: 'datepicker-months',
16687                 cn: [
16688                 {
16689                     tag: 'table',
16690                     cls: 'table-condensed',
16691                     cn:[
16692                         Roo.bootstrap.DateField.content
16693                     ]
16694                 }
16695                 ]
16696             }
16697         ]
16698     }
16699 });
16700
16701  
16702
16703  
16704  /*
16705  * - LGPL
16706  *
16707  * CheckBox
16708  * 
16709  */
16710
16711 /**
16712  * @class Roo.bootstrap.CheckBox
16713  * @extends Roo.bootstrap.Input
16714  * Bootstrap CheckBox class
16715  * 
16716  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16717  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16718  * @cfg {String} boxLabel The text that appears beside the checkbox
16719  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16720  * @cfg {Boolean} checked initnal the element
16721  * @cfg {Boolean} inline inline the element (default false)
16722  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16723  * 
16724  * @constructor
16725  * Create a new CheckBox
16726  * @param {Object} config The config object
16727  */
16728
16729 Roo.bootstrap.CheckBox = function(config){
16730     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16731    
16732     this.addEvents({
16733         /**
16734         * @event check
16735         * Fires when the element is checked or unchecked.
16736         * @param {Roo.bootstrap.CheckBox} this This input
16737         * @param {Boolean} checked The new checked value
16738         */
16739        check : true
16740     });
16741     
16742 };
16743
16744 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16745   
16746     inputType: 'checkbox',
16747     inputValue: 1,
16748     valueOff: 0,
16749     boxLabel: false,
16750     checked: false,
16751     weight : false,
16752     inline: false,
16753     
16754     getAutoCreate : function()
16755     {
16756         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16757         
16758         var id = Roo.id();
16759         
16760         var cfg = {};
16761         
16762         cfg.cls = 'form-group ' + this.inputType; //input-group
16763         
16764         if(this.inline){
16765             cfg.cls += ' ' + this.inputType + '-inline';
16766         }
16767         
16768         var input =  {
16769             tag: 'input',
16770             id : id,
16771             type : this.inputType,
16772             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16773             cls : 'roo-' + this.inputType, //'form-box',
16774             placeholder : this.placeholder || ''
16775             
16776         };
16777         
16778         if (this.weight) { // Validity check?
16779             cfg.cls += " " + this.inputType + "-" + this.weight;
16780         }
16781         
16782         if (this.disabled) {
16783             input.disabled=true;
16784         }
16785         
16786         if(this.checked){
16787             input.checked = this.checked;
16788         }
16789         
16790         if (this.name) {
16791             input.name = this.name;
16792         }
16793         
16794         if (this.size) {
16795             input.cls += ' input-' + this.size;
16796         }
16797         
16798         var settings=this;
16799         
16800         ['xs','sm','md','lg'].map(function(size){
16801             if (settings[size]) {
16802                 cfg.cls += ' col-' + size + '-' + settings[size];
16803             }
16804         });
16805         
16806         var inputblock = input;
16807          
16808         if (this.before || this.after) {
16809             
16810             inputblock = {
16811                 cls : 'input-group',
16812                 cn :  [] 
16813             };
16814             
16815             if (this.before) {
16816                 inputblock.cn.push({
16817                     tag :'span',
16818                     cls : 'input-group-addon',
16819                     html : this.before
16820                 });
16821             }
16822             
16823             inputblock.cn.push(input);
16824             
16825             if (this.after) {
16826                 inputblock.cn.push({
16827                     tag :'span',
16828                     cls : 'input-group-addon',
16829                     html : this.after
16830                 });
16831             }
16832             
16833         }
16834         
16835         if (align ==='left' && this.fieldLabel.length) {
16836                 Roo.log("left and has label");
16837                 cfg.cn = [
16838                     
16839                     {
16840                         tag: 'label',
16841                         'for' :  id,
16842                         cls : 'control-label col-md-' + this.labelWidth,
16843                         html : this.fieldLabel
16844                         
16845                     },
16846                     {
16847                         cls : "col-md-" + (12 - this.labelWidth), 
16848                         cn: [
16849                             inputblock
16850                         ]
16851                     }
16852                     
16853                 ];
16854         } else if ( this.fieldLabel.length) {
16855                 Roo.log(" label");
16856                 cfg.cn = [
16857                    
16858                     {
16859                         tag: this.boxLabel ? 'span' : 'label',
16860                         'for': id,
16861                         cls: 'control-label box-input-label',
16862                         //cls : 'input-group-addon',
16863                         html : this.fieldLabel
16864                         
16865                     },
16866                     
16867                     inputblock
16868                     
16869                 ];
16870
16871         } else {
16872             
16873                 Roo.log(" no label && no align");
16874                 cfg.cn = [  inputblock ] ;
16875                 
16876                 
16877         }
16878         if(this.boxLabel){
16879              var boxLabelCfg = {
16880                 tag: 'label',
16881                 //'for': id, // box label is handled by onclick - so no for...
16882                 cls: 'box-label',
16883                 html: this.boxLabel
16884             }
16885             
16886             if(this.tooltip){
16887                 boxLabelCfg.tooltip = this.tooltip;
16888             }
16889              
16890             cfg.cn.push(boxLabelCfg);
16891         }
16892         
16893         
16894        
16895         return cfg;
16896         
16897     },
16898     
16899     /**
16900      * return the real input element.
16901      */
16902     inputEl: function ()
16903     {
16904         return this.el.select('input.roo-' + this.inputType,true).first();
16905     },
16906     
16907     labelEl: function()
16908     {
16909         return this.el.select('label.control-label',true).first();
16910     },
16911     /* depricated... */
16912     
16913     label: function()
16914     {
16915         return this.labelEl();
16916     },
16917     
16918     initEvents : function()
16919     {
16920 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16921         
16922         this.inputEl().on('click', this.onClick,  this);
16923         
16924         if (this.boxLabel) { 
16925             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
16926         }
16927         
16928         this.startValue = this.getValue();
16929         
16930         if(this.groupId){
16931             Roo.bootstrap.CheckBox.register(this);
16932         }
16933     },
16934     
16935     onClick : function()
16936     {   
16937         this.setChecked(!this.checked);
16938     },
16939     
16940     setChecked : function(state,suppressEvent)
16941     {
16942         this.startValue = this.getValue();
16943         
16944         if(this.inputType == 'radio'){
16945             
16946             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16947                 e.dom.checked = false;
16948             });
16949             
16950             this.inputEl().dom.checked = true;
16951             
16952             this.inputEl().dom.value = this.inputValue;
16953             
16954             if(suppressEvent !== true){
16955                 this.fireEvent('check', this, true);
16956             }
16957             
16958             this.validate();
16959             
16960             return;
16961         }
16962         
16963         this.checked = state;
16964         
16965         this.inputEl().dom.checked = state;
16966         
16967         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16968         
16969         if(suppressEvent !== true){
16970             this.fireEvent('check', this, state);
16971         }
16972         
16973         this.validate();
16974     },
16975     
16976     getValue : function()
16977     {
16978         if(this.inputType == 'radio'){
16979             return this.getGroupValue();
16980         }
16981         
16982         return this.inputEl().getValue();
16983         
16984     },
16985     
16986     getGroupValue : function()
16987     {
16988         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16989             return '';
16990         }
16991         
16992         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16993     },
16994     
16995     setValue : function(v,suppressEvent)
16996     {
16997         if(this.inputType == 'radio'){
16998             this.setGroupValue(v, suppressEvent);
16999             return;
17000         }
17001         
17002         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17003         
17004         this.validate();
17005     },
17006     
17007     setGroupValue : function(v, suppressEvent)
17008     {
17009         this.startValue = this.getValue();
17010         
17011         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17012             e.dom.checked = false;
17013             
17014             if(e.dom.value == v){
17015                 e.dom.checked = true;
17016             }
17017         });
17018         
17019         if(suppressEvent !== true){
17020             this.fireEvent('check', this, true);
17021         }
17022
17023         this.validate();
17024         
17025         return;
17026     },
17027     
17028     validate : function()
17029     {
17030         if(
17031                 this.disabled || 
17032                 (this.inputType == 'radio' && this.validateRadio()) ||
17033                 (this.inputType == 'checkbox' && this.validateCheckbox())
17034         ){
17035             this.markValid();
17036             return true;
17037         }
17038         
17039         this.markInvalid();
17040         return false;
17041     },
17042     
17043     validateRadio : function()
17044     {
17045         var valid = false;
17046         
17047         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17048             if(!e.dom.checked){
17049                 return;
17050             }
17051             
17052             valid = true;
17053             
17054             return false;
17055         });
17056         
17057         return valid;
17058     },
17059     
17060     validateCheckbox : function()
17061     {
17062         if(!this.groupId){
17063             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17064         }
17065         
17066         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17067         
17068         if(!group){
17069             return false;
17070         }
17071         
17072         var r = false;
17073         
17074         for(var i in group){
17075             if(r){
17076                 break;
17077             }
17078             
17079             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17080         }
17081         
17082         return r;
17083     },
17084     
17085     /**
17086      * Mark this field as valid
17087      */
17088     markValid : function()
17089     {
17090         if(this.allowBlank){
17091             return;
17092         }
17093         
17094         var _this = this;
17095         
17096         this.fireEvent('valid', this);
17097         
17098         if(this.inputType == 'radio'){
17099             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17100                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17101                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17102             });
17103             
17104             return;
17105         }
17106         
17107         if(!this.groupId){
17108             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17109             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17110             return;
17111         }
17112         
17113         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17114             
17115         if(!group){
17116             return;
17117         }
17118         
17119         for(var i in group){
17120             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17121             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17122         }
17123     },
17124     
17125      /**
17126      * Mark this field as invalid
17127      * @param {String} msg The validation message
17128      */
17129     markInvalid : function(msg)
17130     {
17131         if(this.allowBlank){
17132             return;
17133         }
17134         
17135         var _this = this;
17136         
17137         this.fireEvent('invalid', this, msg);
17138         
17139         if(this.inputType == 'radio'){
17140             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17141                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17142                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17143             });
17144             
17145             return;
17146         }
17147         
17148         if(!this.groupId){
17149             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17150             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17151             return;
17152         }
17153         
17154         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17155             
17156         if(!group){
17157             return;
17158         }
17159         
17160         for(var i in group){
17161             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17162             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17163         }
17164         
17165     }
17166     
17167 });
17168
17169 Roo.apply(Roo.bootstrap.CheckBox, {
17170     
17171     groups: {},
17172     
17173      /**
17174     * register a CheckBox Group
17175     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17176     */
17177     register : function(checkbox)
17178     {
17179         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17180             this.groups[checkbox.groupId] = {};
17181         }
17182         
17183         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17184             return;
17185         }
17186         
17187         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17188         
17189     },
17190     /**
17191     * fetch a CheckBox Group based on the group ID
17192     * @param {string} the group ID
17193     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17194     */
17195     get: function(groupId) {
17196         if (typeof(this.groups[groupId]) == 'undefined') {
17197             return false;
17198         }
17199         
17200         return this.groups[groupId] ;
17201     }
17202     
17203     
17204 });
17205 /*
17206  * - LGPL
17207  *
17208  * Radio
17209  *
17210  *
17211  * not inline
17212  *<div class="radio">
17213   <label>
17214     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17215     Option one is this and that&mdash;be sure to include why it's great
17216   </label>
17217 </div>
17218  *
17219  *
17220  *inline
17221  *<span>
17222  *<label class="radio-inline">fieldLabel</label>
17223  *<label class="radio-inline">
17224   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17225 </label>
17226 <span>
17227  * 
17228  * 
17229  */
17230
17231 /**
17232  * @class Roo.bootstrap.Radio
17233  * @extends Roo.bootstrap.CheckBox
17234  * Bootstrap Radio class
17235
17236  * @constructor
17237  * Create a new Radio
17238  * @param {Object} config The config object
17239  */
17240
17241 Roo.bootstrap.Radio = function(config){
17242     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17243    
17244 };
17245
17246 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17247     
17248     inputType: 'radio',
17249     inputValue: '',
17250     valueOff: '',
17251     
17252     getAutoCreate : function()
17253     {
17254         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17255         align = align || 'left'; // default...
17256         
17257         
17258         
17259         var id = Roo.id();
17260         
17261         var cfg = {
17262                 tag : this.inline ? 'span' : 'div',
17263                 cls : '',
17264                 cn : []
17265         };
17266         
17267         var inline = this.inline ? ' radio-inline' : '';
17268         
17269         var lbl = {
17270                 tag: 'label' ,
17271                 // does not need for, as we wrap the input with it..
17272                 'for' : id,
17273                 cls : 'control-label box-label' + inline,
17274                 cn : []
17275         };
17276         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17277         
17278         var fieldLabel = {
17279             tag: 'label' ,
17280             //cls : 'control-label' + inline,
17281             html : this.fieldLabel,
17282             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17283         };
17284         
17285  
17286         
17287         
17288         var input =  {
17289             tag: 'input',
17290             id : id,
17291             type : this.inputType,
17292             //value : (!this.checked) ? this.valueOff : this.inputValue,
17293             value : this.inputValue,
17294             cls : 'roo-radio',
17295             placeholder : this.placeholder || '' // ?? needed????
17296             
17297         };
17298         if (this.weight) { // Validity check?
17299             input.cls += " radio-" + this.weight;
17300         }
17301         if (this.disabled) {
17302             input.disabled=true;
17303         }
17304         
17305         if(this.checked){
17306             input.checked = this.checked;
17307         }
17308         
17309         if (this.name) {
17310             input.name = this.name;
17311         }
17312         
17313         if (this.size) {
17314             input.cls += ' input-' + this.size;
17315         }
17316         
17317         //?? can span's inline have a width??
17318         
17319         var settings=this;
17320         ['xs','sm','md','lg'].map(function(size){
17321             if (settings[size]) {
17322                 cfg.cls += ' col-' + size + '-' + settings[size];
17323             }
17324         });
17325         
17326         var inputblock = input;
17327         
17328         if (this.before || this.after) {
17329             
17330             inputblock = {
17331                 cls : 'input-group',
17332                 tag : 'span',
17333                 cn :  [] 
17334             };
17335             if (this.before) {
17336                 inputblock.cn.push({
17337                     tag :'span',
17338                     cls : 'input-group-addon',
17339                     html : this.before
17340                 });
17341             }
17342             inputblock.cn.push(input);
17343             if (this.after) {
17344                 inputblock.cn.push({
17345                     tag :'span',
17346                     cls : 'input-group-addon',
17347                     html : this.after
17348                 });
17349             }
17350             
17351         };
17352         
17353         
17354         if (this.fieldLabel && this.fieldLabel.length) {
17355             cfg.cn.push(fieldLabel);
17356         }
17357        
17358         // normal bootstrap puts the input inside the label.
17359         // however with our styled version - it has to go after the input.
17360        
17361         //lbl.cn.push(inputblock);
17362         
17363         var lblwrap =  {
17364             tag: 'span',
17365             cls: 'radio' + inline,
17366             cn: [
17367                 inputblock,
17368                 lbl
17369             ]
17370         };
17371         
17372         cfg.cn.push( lblwrap);
17373         
17374         if(this.boxLabel){
17375             lbl.cn.push({
17376                 tag: 'span',
17377                 html: this.boxLabel
17378             })
17379         }
17380          
17381         
17382         return cfg;
17383         
17384     },
17385     
17386     initEvents : function()
17387     {
17388 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17389         
17390         this.inputEl().on('click', this.onClick,  this);
17391         if (this.boxLabel) {
17392             Roo.log('find label')
17393             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17394         }
17395         
17396     },
17397     
17398     inputEl: function ()
17399     {
17400         return this.el.select('input.roo-radio',true).first();
17401     },
17402     onClick : function()
17403     {   
17404         Roo.log("click");
17405         this.setChecked(true);
17406     },
17407     
17408     setChecked : function(state,suppressEvent)
17409     {
17410         if(state){
17411             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17412                 v.dom.checked = false;
17413             });
17414         }
17415         Roo.log(this.inputEl().dom);
17416         this.checked = state;
17417         this.inputEl().dom.checked = state;
17418         
17419         if(suppressEvent !== true){
17420             this.fireEvent('check', this, state);
17421         }
17422         
17423         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17424         
17425     },
17426     
17427     getGroupValue : function()
17428     {
17429         var value = '';
17430         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17431             if(v.dom.checked == true){
17432                 value = v.dom.value;
17433             }
17434         });
17435         
17436         return value;
17437     },
17438     
17439     /**
17440      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17441      * @return {Mixed} value The field value
17442      */
17443     getValue : function(){
17444         return this.getGroupValue();
17445     }
17446     
17447 });
17448
17449  
17450 //<script type="text/javascript">
17451
17452 /*
17453  * Based  Ext JS Library 1.1.1
17454  * Copyright(c) 2006-2007, Ext JS, LLC.
17455  * LGPL
17456  *
17457  */
17458  
17459 /**
17460  * @class Roo.HtmlEditorCore
17461  * @extends Roo.Component
17462  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17463  *
17464  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17465  */
17466
17467 Roo.HtmlEditorCore = function(config){
17468     
17469     
17470     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17471     
17472     
17473     this.addEvents({
17474         /**
17475          * @event initialize
17476          * Fires when the editor is fully initialized (including the iframe)
17477          * @param {Roo.HtmlEditorCore} this
17478          */
17479         initialize: true,
17480         /**
17481          * @event activate
17482          * Fires when the editor is first receives the focus. Any insertion must wait
17483          * until after this event.
17484          * @param {Roo.HtmlEditorCore} this
17485          */
17486         activate: true,
17487          /**
17488          * @event beforesync
17489          * Fires before the textarea is updated with content from the editor iframe. Return false
17490          * to cancel the sync.
17491          * @param {Roo.HtmlEditorCore} this
17492          * @param {String} html
17493          */
17494         beforesync: true,
17495          /**
17496          * @event beforepush
17497          * Fires before the iframe editor is updated with content from the textarea. Return false
17498          * to cancel the push.
17499          * @param {Roo.HtmlEditorCore} this
17500          * @param {String} html
17501          */
17502         beforepush: true,
17503          /**
17504          * @event sync
17505          * Fires when the textarea is updated with content from the editor iframe.
17506          * @param {Roo.HtmlEditorCore} this
17507          * @param {String} html
17508          */
17509         sync: true,
17510          /**
17511          * @event push
17512          * Fires when the iframe editor is updated with content from the textarea.
17513          * @param {Roo.HtmlEditorCore} this
17514          * @param {String} html
17515          */
17516         push: true,
17517         
17518         /**
17519          * @event editorevent
17520          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17521          * @param {Roo.HtmlEditorCore} this
17522          */
17523         editorevent: true
17524         
17525     });
17526     
17527     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17528     
17529     // defaults : white / black...
17530     this.applyBlacklists();
17531     
17532     
17533     
17534 };
17535
17536
17537 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17538
17539
17540      /**
17541      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17542      */
17543     
17544     owner : false,
17545     
17546      /**
17547      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17548      *                        Roo.resizable.
17549      */
17550     resizable : false,
17551      /**
17552      * @cfg {Number} height (in pixels)
17553      */   
17554     height: 300,
17555    /**
17556      * @cfg {Number} width (in pixels)
17557      */   
17558     width: 500,
17559     
17560     /**
17561      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17562      * 
17563      */
17564     stylesheets: false,
17565     
17566     // id of frame..
17567     frameId: false,
17568     
17569     // private properties
17570     validationEvent : false,
17571     deferHeight: true,
17572     initialized : false,
17573     activated : false,
17574     sourceEditMode : false,
17575     onFocus : Roo.emptyFn,
17576     iframePad:3,
17577     hideMode:'offsets',
17578     
17579     clearUp: true,
17580     
17581     // blacklist + whitelisted elements..
17582     black: false,
17583     white: false,
17584      
17585     
17586
17587     /**
17588      * Protected method that will not generally be called directly. It
17589      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17590      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17591      */
17592     getDocMarkup : function(){
17593         // body styles..
17594         var st = '';
17595         
17596         // inherit styels from page...?? 
17597         if (this.stylesheets === false) {
17598             
17599             Roo.get(document.head).select('style').each(function(node) {
17600                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17601             });
17602             
17603             Roo.get(document.head).select('link').each(function(node) { 
17604                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17605             });
17606             
17607         } else if (!this.stylesheets.length) {
17608                 // simple..
17609                 st = '<style type="text/css">' +
17610                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17611                    '</style>';
17612         } else { 
17613             
17614         }
17615         
17616         st +=  '<style type="text/css">' +
17617             'IMG { cursor: pointer } ' +
17618         '</style>';
17619
17620         
17621         return '<html><head>' + st  +
17622             //<style type="text/css">' +
17623             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17624             //'</style>' +
17625             ' </head><body class="roo-htmleditor-body"></body></html>';
17626     },
17627
17628     // private
17629     onRender : function(ct, position)
17630     {
17631         var _t = this;
17632         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17633         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17634         
17635         
17636         this.el.dom.style.border = '0 none';
17637         this.el.dom.setAttribute('tabIndex', -1);
17638         this.el.addClass('x-hidden hide');
17639         
17640         
17641         
17642         if(Roo.isIE){ // fix IE 1px bogus margin
17643             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17644         }
17645        
17646         
17647         this.frameId = Roo.id();
17648         
17649          
17650         
17651         var iframe = this.owner.wrap.createChild({
17652             tag: 'iframe',
17653             cls: 'form-control', // bootstrap..
17654             id: this.frameId,
17655             name: this.frameId,
17656             frameBorder : 'no',
17657             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17658         }, this.el
17659         );
17660         
17661         
17662         this.iframe = iframe.dom;
17663
17664          this.assignDocWin();
17665         
17666         this.doc.designMode = 'on';
17667        
17668         this.doc.open();
17669         this.doc.write(this.getDocMarkup());
17670         this.doc.close();
17671
17672         
17673         var task = { // must defer to wait for browser to be ready
17674             run : function(){
17675                 //console.log("run task?" + this.doc.readyState);
17676                 this.assignDocWin();
17677                 if(this.doc.body || this.doc.readyState == 'complete'){
17678                     try {
17679                         this.doc.designMode="on";
17680                     } catch (e) {
17681                         return;
17682                     }
17683                     Roo.TaskMgr.stop(task);
17684                     this.initEditor.defer(10, this);
17685                 }
17686             },
17687             interval : 10,
17688             duration: 10000,
17689             scope: this
17690         };
17691         Roo.TaskMgr.start(task);
17692
17693     },
17694
17695     // private
17696     onResize : function(w, h)
17697     {
17698          Roo.log('resize: ' +w + ',' + h );
17699         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17700         if(!this.iframe){
17701             return;
17702         }
17703         if(typeof w == 'number'){
17704             
17705             this.iframe.style.width = w + 'px';
17706         }
17707         if(typeof h == 'number'){
17708             
17709             this.iframe.style.height = h + 'px';
17710             if(this.doc){
17711                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17712             }
17713         }
17714         
17715     },
17716
17717     /**
17718      * Toggles the editor between standard and source edit mode.
17719      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17720      */
17721     toggleSourceEdit : function(sourceEditMode){
17722         
17723         this.sourceEditMode = sourceEditMode === true;
17724         
17725         if(this.sourceEditMode){
17726  
17727             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17728             
17729         }else{
17730             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17731             //this.iframe.className = '';
17732             this.deferFocus();
17733         }
17734         //this.setSize(this.owner.wrap.getSize());
17735         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17736     },
17737
17738     
17739   
17740
17741     /**
17742      * Protected method that will not generally be called directly. If you need/want
17743      * custom HTML cleanup, this is the method you should override.
17744      * @param {String} html The HTML to be cleaned
17745      * return {String} The cleaned HTML
17746      */
17747     cleanHtml : function(html){
17748         html = String(html);
17749         if(html.length > 5){
17750             if(Roo.isSafari){ // strip safari nonsense
17751                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17752             }
17753         }
17754         if(html == '&nbsp;'){
17755             html = '';
17756         }
17757         return html;
17758     },
17759
17760     /**
17761      * HTML Editor -> Textarea
17762      * Protected method that will not generally be called directly. Syncs the contents
17763      * of the editor iframe with the textarea.
17764      */
17765     syncValue : function(){
17766         if(this.initialized){
17767             var bd = (this.doc.body || this.doc.documentElement);
17768             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17769             var html = bd.innerHTML;
17770             if(Roo.isSafari){
17771                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17772                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17773                 if(m && m[1]){
17774                     html = '<div style="'+m[0]+'">' + html + '</div>';
17775                 }
17776             }
17777             html = this.cleanHtml(html);
17778             // fix up the special chars.. normaly like back quotes in word...
17779             // however we do not want to do this with chinese..
17780             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17781                 var cc = b.charCodeAt();
17782                 if (
17783                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17784                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17785                     (cc >= 0xf900 && cc < 0xfb00 )
17786                 ) {
17787                         return b;
17788                 }
17789                 return "&#"+cc+";" 
17790             });
17791             if(this.owner.fireEvent('beforesync', this, html) !== false){
17792                 this.el.dom.value = html;
17793                 this.owner.fireEvent('sync', this, html);
17794             }
17795         }
17796     },
17797
17798     /**
17799      * Protected method that will not generally be called directly. Pushes the value of the textarea
17800      * into the iframe editor.
17801      */
17802     pushValue : function(){
17803         if(this.initialized){
17804             var v = this.el.dom.value.trim();
17805             
17806 //            if(v.length < 1){
17807 //                v = '&#160;';
17808 //            }
17809             
17810             if(this.owner.fireEvent('beforepush', this, v) !== false){
17811                 var d = (this.doc.body || this.doc.documentElement);
17812                 d.innerHTML = v;
17813                 this.cleanUpPaste();
17814                 this.el.dom.value = d.innerHTML;
17815                 this.owner.fireEvent('push', this, v);
17816             }
17817         }
17818     },
17819
17820     // private
17821     deferFocus : function(){
17822         this.focus.defer(10, this);
17823     },
17824
17825     // doc'ed in Field
17826     focus : function(){
17827         if(this.win && !this.sourceEditMode){
17828             this.win.focus();
17829         }else{
17830             this.el.focus();
17831         }
17832     },
17833     
17834     assignDocWin: function()
17835     {
17836         var iframe = this.iframe;
17837         
17838          if(Roo.isIE){
17839             this.doc = iframe.contentWindow.document;
17840             this.win = iframe.contentWindow;
17841         } else {
17842 //            if (!Roo.get(this.frameId)) {
17843 //                return;
17844 //            }
17845 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17846 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17847             
17848             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17849                 return;
17850             }
17851             
17852             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17853             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17854         }
17855     },
17856     
17857     // private
17858     initEditor : function(){
17859         //console.log("INIT EDITOR");
17860         this.assignDocWin();
17861         
17862         
17863         
17864         this.doc.designMode="on";
17865         this.doc.open();
17866         this.doc.write(this.getDocMarkup());
17867         this.doc.close();
17868         
17869         var dbody = (this.doc.body || this.doc.documentElement);
17870         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17871         // this copies styles from the containing element into thsi one..
17872         // not sure why we need all of this..
17873         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17874         
17875         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17876         //ss['background-attachment'] = 'fixed'; // w3c
17877         dbody.bgProperties = 'fixed'; // ie
17878         //Roo.DomHelper.applyStyles(dbody, ss);
17879         Roo.EventManager.on(this.doc, {
17880             //'mousedown': this.onEditorEvent,
17881             'mouseup': this.onEditorEvent,
17882             'dblclick': this.onEditorEvent,
17883             'click': this.onEditorEvent,
17884             'keyup': this.onEditorEvent,
17885             buffer:100,
17886             scope: this
17887         });
17888         if(Roo.isGecko){
17889             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17890         }
17891         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17892             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17893         }
17894         this.initialized = true;
17895
17896         this.owner.fireEvent('initialize', this);
17897         this.pushValue();
17898     },
17899
17900     // private
17901     onDestroy : function(){
17902         
17903         
17904         
17905         if(this.rendered){
17906             
17907             //for (var i =0; i < this.toolbars.length;i++) {
17908             //    // fixme - ask toolbars for heights?
17909             //    this.toolbars[i].onDestroy();
17910            // }
17911             
17912             //this.wrap.dom.innerHTML = '';
17913             //this.wrap.remove();
17914         }
17915     },
17916
17917     // private
17918     onFirstFocus : function(){
17919         
17920         this.assignDocWin();
17921         
17922         
17923         this.activated = true;
17924          
17925     
17926         if(Roo.isGecko){ // prevent silly gecko errors
17927             this.win.focus();
17928             var s = this.win.getSelection();
17929             if(!s.focusNode || s.focusNode.nodeType != 3){
17930                 var r = s.getRangeAt(0);
17931                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17932                 r.collapse(true);
17933                 this.deferFocus();
17934             }
17935             try{
17936                 this.execCmd('useCSS', true);
17937                 this.execCmd('styleWithCSS', false);
17938             }catch(e){}
17939         }
17940         this.owner.fireEvent('activate', this);
17941     },
17942
17943     // private
17944     adjustFont: function(btn){
17945         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17946         //if(Roo.isSafari){ // safari
17947         //    adjust *= 2;
17948        // }
17949         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17950         if(Roo.isSafari){ // safari
17951             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17952             v =  (v < 10) ? 10 : v;
17953             v =  (v > 48) ? 48 : v;
17954             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17955             
17956         }
17957         
17958         
17959         v = Math.max(1, v+adjust);
17960         
17961         this.execCmd('FontSize', v  );
17962     },
17963
17964     onEditorEvent : function(e){
17965         this.owner.fireEvent('editorevent', this, e);
17966       //  this.updateToolbar();
17967         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17968     },
17969
17970     insertTag : function(tg)
17971     {
17972         // could be a bit smarter... -> wrap the current selected tRoo..
17973         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17974             
17975             range = this.createRange(this.getSelection());
17976             var wrappingNode = this.doc.createElement(tg.toLowerCase());
17977             wrappingNode.appendChild(range.extractContents());
17978             range.insertNode(wrappingNode);
17979
17980             return;
17981             
17982             
17983             
17984         }
17985         this.execCmd("formatblock",   tg);
17986         
17987     },
17988     
17989     insertText : function(txt)
17990     {
17991         
17992         
17993         var range = this.createRange();
17994         range.deleteContents();
17995                //alert(Sender.getAttribute('label'));
17996                
17997         range.insertNode(this.doc.createTextNode(txt));
17998     } ,
17999     
18000      
18001
18002     /**
18003      * Executes a Midas editor command on the editor document and performs necessary focus and
18004      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18005      * @param {String} cmd The Midas command
18006      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18007      */
18008     relayCmd : function(cmd, value){
18009         this.win.focus();
18010         this.execCmd(cmd, value);
18011         this.owner.fireEvent('editorevent', this);
18012         //this.updateToolbar();
18013         this.owner.deferFocus();
18014     },
18015
18016     /**
18017      * Executes a Midas editor command directly on the editor document.
18018      * For visual commands, you should use {@link #relayCmd} instead.
18019      * <b>This should only be called after the editor is initialized.</b>
18020      * @param {String} cmd The Midas command
18021      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18022      */
18023     execCmd : function(cmd, value){
18024         this.doc.execCommand(cmd, false, value === undefined ? null : value);
18025         this.syncValue();
18026     },
18027  
18028  
18029    
18030     /**
18031      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18032      * to insert tRoo.
18033      * @param {String} text | dom node.. 
18034      */
18035     insertAtCursor : function(text)
18036     {
18037         
18038         
18039         
18040         if(!this.activated){
18041             return;
18042         }
18043         /*
18044         if(Roo.isIE){
18045             this.win.focus();
18046             var r = this.doc.selection.createRange();
18047             if(r){
18048                 r.collapse(true);
18049                 r.pasteHTML(text);
18050                 this.syncValue();
18051                 this.deferFocus();
18052             
18053             }
18054             return;
18055         }
18056         */
18057         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18058             this.win.focus();
18059             
18060             
18061             // from jquery ui (MIT licenced)
18062             var range, node;
18063             var win = this.win;
18064             
18065             if (win.getSelection && win.getSelection().getRangeAt) {
18066                 range = win.getSelection().getRangeAt(0);
18067                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18068                 range.insertNode(node);
18069             } else if (win.document.selection && win.document.selection.createRange) {
18070                 // no firefox support
18071                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18072                 win.document.selection.createRange().pasteHTML(txt);
18073             } else {
18074                 // no firefox support
18075                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18076                 this.execCmd('InsertHTML', txt);
18077             } 
18078             
18079             this.syncValue();
18080             
18081             this.deferFocus();
18082         }
18083     },
18084  // private
18085     mozKeyPress : function(e){
18086         if(e.ctrlKey){
18087             var c = e.getCharCode(), cmd;
18088           
18089             if(c > 0){
18090                 c = String.fromCharCode(c).toLowerCase();
18091                 switch(c){
18092                     case 'b':
18093                         cmd = 'bold';
18094                         break;
18095                     case 'i':
18096                         cmd = 'italic';
18097                         break;
18098                     
18099                     case 'u':
18100                         cmd = 'underline';
18101                         break;
18102                     
18103                     case 'v':
18104                         this.cleanUpPaste.defer(100, this);
18105                         return;
18106                         
18107                 }
18108                 if(cmd){
18109                     this.win.focus();
18110                     this.execCmd(cmd);
18111                     this.deferFocus();
18112                     e.preventDefault();
18113                 }
18114                 
18115             }
18116         }
18117     },
18118
18119     // private
18120     fixKeys : function(){ // load time branching for fastest keydown performance
18121         if(Roo.isIE){
18122             return function(e){
18123                 var k = e.getKey(), r;
18124                 if(k == e.TAB){
18125                     e.stopEvent();
18126                     r = this.doc.selection.createRange();
18127                     if(r){
18128                         r.collapse(true);
18129                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18130                         this.deferFocus();
18131                     }
18132                     return;
18133                 }
18134                 
18135                 if(k == e.ENTER){
18136                     r = this.doc.selection.createRange();
18137                     if(r){
18138                         var target = r.parentElement();
18139                         if(!target || target.tagName.toLowerCase() != 'li'){
18140                             e.stopEvent();
18141                             r.pasteHTML('<br />');
18142                             r.collapse(false);
18143                             r.select();
18144                         }
18145                     }
18146                 }
18147                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18148                     this.cleanUpPaste.defer(100, this);
18149                     return;
18150                 }
18151                 
18152                 
18153             };
18154         }else if(Roo.isOpera){
18155             return function(e){
18156                 var k = e.getKey();
18157                 if(k == e.TAB){
18158                     e.stopEvent();
18159                     this.win.focus();
18160                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18161                     this.deferFocus();
18162                 }
18163                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18164                     this.cleanUpPaste.defer(100, this);
18165                     return;
18166                 }
18167                 
18168             };
18169         }else if(Roo.isSafari){
18170             return function(e){
18171                 var k = e.getKey();
18172                 
18173                 if(k == e.TAB){
18174                     e.stopEvent();
18175                     this.execCmd('InsertText','\t');
18176                     this.deferFocus();
18177                     return;
18178                 }
18179                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18180                     this.cleanUpPaste.defer(100, this);
18181                     return;
18182                 }
18183                 
18184              };
18185         }
18186     }(),
18187     
18188     getAllAncestors: function()
18189     {
18190         var p = this.getSelectedNode();
18191         var a = [];
18192         if (!p) {
18193             a.push(p); // push blank onto stack..
18194             p = this.getParentElement();
18195         }
18196         
18197         
18198         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18199             a.push(p);
18200             p = p.parentNode;
18201         }
18202         a.push(this.doc.body);
18203         return a;
18204     },
18205     lastSel : false,
18206     lastSelNode : false,
18207     
18208     
18209     getSelection : function() 
18210     {
18211         this.assignDocWin();
18212         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18213     },
18214     
18215     getSelectedNode: function() 
18216     {
18217         // this may only work on Gecko!!!
18218         
18219         // should we cache this!!!!
18220         
18221         
18222         
18223          
18224         var range = this.createRange(this.getSelection()).cloneRange();
18225         
18226         if (Roo.isIE) {
18227             var parent = range.parentElement();
18228             while (true) {
18229                 var testRange = range.duplicate();
18230                 testRange.moveToElementText(parent);
18231                 if (testRange.inRange(range)) {
18232                     break;
18233                 }
18234                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18235                     break;
18236                 }
18237                 parent = parent.parentElement;
18238             }
18239             return parent;
18240         }
18241         
18242         // is ancestor a text element.
18243         var ac =  range.commonAncestorContainer;
18244         if (ac.nodeType == 3) {
18245             ac = ac.parentNode;
18246         }
18247         
18248         var ar = ac.childNodes;
18249          
18250         var nodes = [];
18251         var other_nodes = [];
18252         var has_other_nodes = false;
18253         for (var i=0;i<ar.length;i++) {
18254             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18255                 continue;
18256             }
18257             // fullly contained node.
18258             
18259             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18260                 nodes.push(ar[i]);
18261                 continue;
18262             }
18263             
18264             // probably selected..
18265             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18266                 other_nodes.push(ar[i]);
18267                 continue;
18268             }
18269             // outer..
18270             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18271                 continue;
18272             }
18273             
18274             
18275             has_other_nodes = true;
18276         }
18277         if (!nodes.length && other_nodes.length) {
18278             nodes= other_nodes;
18279         }
18280         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18281             return false;
18282         }
18283         
18284         return nodes[0];
18285     },
18286     createRange: function(sel)
18287     {
18288         // this has strange effects when using with 
18289         // top toolbar - not sure if it's a great idea.
18290         //this.editor.contentWindow.focus();
18291         if (typeof sel != "undefined") {
18292             try {
18293                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18294             } catch(e) {
18295                 return this.doc.createRange();
18296             }
18297         } else {
18298             return this.doc.createRange();
18299         }
18300     },
18301     getParentElement: function()
18302     {
18303         
18304         this.assignDocWin();
18305         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18306         
18307         var range = this.createRange(sel);
18308          
18309         try {
18310             var p = range.commonAncestorContainer;
18311             while (p.nodeType == 3) { // text node
18312                 p = p.parentNode;
18313             }
18314             return p;
18315         } catch (e) {
18316             return null;
18317         }
18318     
18319     },
18320     /***
18321      *
18322      * Range intersection.. the hard stuff...
18323      *  '-1' = before
18324      *  '0' = hits..
18325      *  '1' = after.
18326      *         [ -- selected range --- ]
18327      *   [fail]                        [fail]
18328      *
18329      *    basically..
18330      *      if end is before start or  hits it. fail.
18331      *      if start is after end or hits it fail.
18332      *
18333      *   if either hits (but other is outside. - then it's not 
18334      *   
18335      *    
18336      **/
18337     
18338     
18339     // @see http://www.thismuchiknow.co.uk/?p=64.
18340     rangeIntersectsNode : function(range, node)
18341     {
18342         var nodeRange = node.ownerDocument.createRange();
18343         try {
18344             nodeRange.selectNode(node);
18345         } catch (e) {
18346             nodeRange.selectNodeContents(node);
18347         }
18348     
18349         var rangeStartRange = range.cloneRange();
18350         rangeStartRange.collapse(true);
18351     
18352         var rangeEndRange = range.cloneRange();
18353         rangeEndRange.collapse(false);
18354     
18355         var nodeStartRange = nodeRange.cloneRange();
18356         nodeStartRange.collapse(true);
18357     
18358         var nodeEndRange = nodeRange.cloneRange();
18359         nodeEndRange.collapse(false);
18360     
18361         return rangeStartRange.compareBoundaryPoints(
18362                  Range.START_TO_START, nodeEndRange) == -1 &&
18363                rangeEndRange.compareBoundaryPoints(
18364                  Range.START_TO_START, nodeStartRange) == 1;
18365         
18366          
18367     },
18368     rangeCompareNode : function(range, node)
18369     {
18370         var nodeRange = node.ownerDocument.createRange();
18371         try {
18372             nodeRange.selectNode(node);
18373         } catch (e) {
18374             nodeRange.selectNodeContents(node);
18375         }
18376         
18377         
18378         range.collapse(true);
18379     
18380         nodeRange.collapse(true);
18381      
18382         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18383         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18384          
18385         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18386         
18387         var nodeIsBefore   =  ss == 1;
18388         var nodeIsAfter    = ee == -1;
18389         
18390         if (nodeIsBefore && nodeIsAfter)
18391             return 0; // outer
18392         if (!nodeIsBefore && nodeIsAfter)
18393             return 1; //right trailed.
18394         
18395         if (nodeIsBefore && !nodeIsAfter)
18396             return 2;  // left trailed.
18397         // fully contined.
18398         return 3;
18399     },
18400
18401     // private? - in a new class?
18402     cleanUpPaste :  function()
18403     {
18404         // cleans up the whole document..
18405         Roo.log('cleanuppaste');
18406         
18407         this.cleanUpChildren(this.doc.body);
18408         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18409         if (clean != this.doc.body.innerHTML) {
18410             this.doc.body.innerHTML = clean;
18411         }
18412         
18413     },
18414     
18415     cleanWordChars : function(input) {// change the chars to hex code
18416         var he = Roo.HtmlEditorCore;
18417         
18418         var output = input;
18419         Roo.each(he.swapCodes, function(sw) { 
18420             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18421             
18422             output = output.replace(swapper, sw[1]);
18423         });
18424         
18425         return output;
18426     },
18427     
18428     
18429     cleanUpChildren : function (n)
18430     {
18431         if (!n.childNodes.length) {
18432             return;
18433         }
18434         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18435            this.cleanUpChild(n.childNodes[i]);
18436         }
18437     },
18438     
18439     
18440         
18441     
18442     cleanUpChild : function (node)
18443     {
18444         var ed = this;
18445         //console.log(node);
18446         if (node.nodeName == "#text") {
18447             // clean up silly Windows -- stuff?
18448             return; 
18449         }
18450         if (node.nodeName == "#comment") {
18451             node.parentNode.removeChild(node);
18452             // clean up silly Windows -- stuff?
18453             return; 
18454         }
18455         var lcname = node.tagName.toLowerCase();
18456         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18457         // whitelist of tags..
18458         
18459         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18460             // remove node.
18461             node.parentNode.removeChild(node);
18462             return;
18463             
18464         }
18465         
18466         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18467         
18468         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18469         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18470         
18471         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18472         //    remove_keep_children = true;
18473         //}
18474         
18475         if (remove_keep_children) {
18476             this.cleanUpChildren(node);
18477             // inserts everything just before this node...
18478             while (node.childNodes.length) {
18479                 var cn = node.childNodes[0];
18480                 node.removeChild(cn);
18481                 node.parentNode.insertBefore(cn, node);
18482             }
18483             node.parentNode.removeChild(node);
18484             return;
18485         }
18486         
18487         if (!node.attributes || !node.attributes.length) {
18488             this.cleanUpChildren(node);
18489             return;
18490         }
18491         
18492         function cleanAttr(n,v)
18493         {
18494             
18495             if (v.match(/^\./) || v.match(/^\//)) {
18496                 return;
18497             }
18498             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18499                 return;
18500             }
18501             if (v.match(/^#/)) {
18502                 return;
18503             }
18504 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18505             node.removeAttribute(n);
18506             
18507         }
18508         
18509         var cwhite = this.cwhite;
18510         var cblack = this.cblack;
18511             
18512         function cleanStyle(n,v)
18513         {
18514             if (v.match(/expression/)) { //XSS?? should we even bother..
18515                 node.removeAttribute(n);
18516                 return;
18517             }
18518             
18519             var parts = v.split(/;/);
18520             var clean = [];
18521             
18522             Roo.each(parts, function(p) {
18523                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18524                 if (!p.length) {
18525                     return true;
18526                 }
18527                 var l = p.split(':').shift().replace(/\s+/g,'');
18528                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18529                 
18530                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18531 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18532                     //node.removeAttribute(n);
18533                     return true;
18534                 }
18535                 //Roo.log()
18536                 // only allow 'c whitelisted system attributes'
18537                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18538 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18539                     //node.removeAttribute(n);
18540                     return true;
18541                 }
18542                 
18543                 
18544                  
18545                 
18546                 clean.push(p);
18547                 return true;
18548             });
18549             if (clean.length) { 
18550                 node.setAttribute(n, clean.join(';'));
18551             } else {
18552                 node.removeAttribute(n);
18553             }
18554             
18555         }
18556         
18557         
18558         for (var i = node.attributes.length-1; i > -1 ; i--) {
18559             var a = node.attributes[i];
18560             //console.log(a);
18561             
18562             if (a.name.toLowerCase().substr(0,2)=='on')  {
18563                 node.removeAttribute(a.name);
18564                 continue;
18565             }
18566             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18567                 node.removeAttribute(a.name);
18568                 continue;
18569             }
18570             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18571                 cleanAttr(a.name,a.value); // fixme..
18572                 continue;
18573             }
18574             if (a.name == 'style') {
18575                 cleanStyle(a.name,a.value);
18576                 continue;
18577             }
18578             /// clean up MS crap..
18579             // tecnically this should be a list of valid class'es..
18580             
18581             
18582             if (a.name == 'class') {
18583                 if (a.value.match(/^Mso/)) {
18584                     node.className = '';
18585                 }
18586                 
18587                 if (a.value.match(/body/)) {
18588                     node.className = '';
18589                 }
18590                 continue;
18591             }
18592             
18593             // style cleanup!?
18594             // class cleanup?
18595             
18596         }
18597         
18598         
18599         this.cleanUpChildren(node);
18600         
18601         
18602     },
18603     /**
18604      * Clean up MS wordisms...
18605      */
18606     cleanWord : function(node)
18607     {
18608         var _t = this;
18609         var cleanWordChildren = function()
18610         {
18611             if (!node.childNodes.length) {
18612                 return;
18613             }
18614             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18615                _t.cleanWord(node.childNodes[i]);
18616             }
18617         }
18618         
18619         
18620         if (!node) {
18621             this.cleanWord(this.doc.body);
18622             return;
18623         }
18624         if (node.nodeName == "#text") {
18625             // clean up silly Windows -- stuff?
18626             return; 
18627         }
18628         if (node.nodeName == "#comment") {
18629             node.parentNode.removeChild(node);
18630             // clean up silly Windows -- stuff?
18631             return; 
18632         }
18633         
18634         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18635             node.parentNode.removeChild(node);
18636             return;
18637         }
18638         
18639         // remove - but keep children..
18640         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18641             while (node.childNodes.length) {
18642                 var cn = node.childNodes[0];
18643                 node.removeChild(cn);
18644                 node.parentNode.insertBefore(cn, node);
18645             }
18646             node.parentNode.removeChild(node);
18647             cleanWordChildren();
18648             return;
18649         }
18650         // clean styles
18651         if (node.className.length) {
18652             
18653             var cn = node.className.split(/\W+/);
18654             var cna = [];
18655             Roo.each(cn, function(cls) {
18656                 if (cls.match(/Mso[a-zA-Z]+/)) {
18657                     return;
18658                 }
18659                 cna.push(cls);
18660             });
18661             node.className = cna.length ? cna.join(' ') : '';
18662             if (!cna.length) {
18663                 node.removeAttribute("class");
18664             }
18665         }
18666         
18667         if (node.hasAttribute("lang")) {
18668             node.removeAttribute("lang");
18669         }
18670         
18671         if (node.hasAttribute("style")) {
18672             
18673             var styles = node.getAttribute("style").split(";");
18674             var nstyle = [];
18675             Roo.each(styles, function(s) {
18676                 if (!s.match(/:/)) {
18677                     return;
18678                 }
18679                 var kv = s.split(":");
18680                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18681                     return;
18682                 }
18683                 // what ever is left... we allow.
18684                 nstyle.push(s);
18685             });
18686             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18687             if (!nstyle.length) {
18688                 node.removeAttribute('style');
18689             }
18690         }
18691         
18692         cleanWordChildren();
18693         
18694         
18695     },
18696     domToHTML : function(currentElement, depth, nopadtext) {
18697         
18698         depth = depth || 0;
18699         nopadtext = nopadtext || false;
18700     
18701         if (!currentElement) {
18702             return this.domToHTML(this.doc.body);
18703         }
18704         
18705         //Roo.log(currentElement);
18706         var j;
18707         var allText = false;
18708         var nodeName = currentElement.nodeName;
18709         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18710         
18711         if  (nodeName == '#text') {
18712             
18713             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18714         }
18715         
18716         
18717         var ret = '';
18718         if (nodeName != 'BODY') {
18719              
18720             var i = 0;
18721             // Prints the node tagName, such as <A>, <IMG>, etc
18722             if (tagName) {
18723                 var attr = [];
18724                 for(i = 0; i < currentElement.attributes.length;i++) {
18725                     // quoting?
18726                     var aname = currentElement.attributes.item(i).name;
18727                     if (!currentElement.attributes.item(i).value.length) {
18728                         continue;
18729                     }
18730                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18731                 }
18732                 
18733                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18734             } 
18735             else {
18736                 
18737                 // eack
18738             }
18739         } else {
18740             tagName = false;
18741         }
18742         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18743             return ret;
18744         }
18745         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18746             nopadtext = true;
18747         }
18748         
18749         
18750         // Traverse the tree
18751         i = 0;
18752         var currentElementChild = currentElement.childNodes.item(i);
18753         var allText = true;
18754         var innerHTML  = '';
18755         lastnode = '';
18756         while (currentElementChild) {
18757             // Formatting code (indent the tree so it looks nice on the screen)
18758             var nopad = nopadtext;
18759             if (lastnode == 'SPAN') {
18760                 nopad  = true;
18761             }
18762             // text
18763             if  (currentElementChild.nodeName == '#text') {
18764                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18765                 toadd = nopadtext ? toadd : toadd.trim();
18766                 if (!nopad && toadd.length > 80) {
18767                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18768                 }
18769                 innerHTML  += toadd;
18770                 
18771                 i++;
18772                 currentElementChild = currentElement.childNodes.item(i);
18773                 lastNode = '';
18774                 continue;
18775             }
18776             allText = false;
18777             
18778             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18779                 
18780             // Recursively traverse the tree structure of the child node
18781             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18782             lastnode = currentElementChild.nodeName;
18783             i++;
18784             currentElementChild=currentElement.childNodes.item(i);
18785         }
18786         
18787         ret += innerHTML;
18788         
18789         if (!allText) {
18790                 // The remaining code is mostly for formatting the tree
18791             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18792         }
18793         
18794         
18795         if (tagName) {
18796             ret+= "</"+tagName+">";
18797         }
18798         return ret;
18799         
18800     },
18801         
18802     applyBlacklists : function()
18803     {
18804         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18805         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18806         
18807         this.white = [];
18808         this.black = [];
18809         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18810             if (b.indexOf(tag) > -1) {
18811                 return;
18812             }
18813             this.white.push(tag);
18814             
18815         }, this);
18816         
18817         Roo.each(w, function(tag) {
18818             if (b.indexOf(tag) > -1) {
18819                 return;
18820             }
18821             if (this.white.indexOf(tag) > -1) {
18822                 return;
18823             }
18824             this.white.push(tag);
18825             
18826         }, this);
18827         
18828         
18829         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18830             if (w.indexOf(tag) > -1) {
18831                 return;
18832             }
18833             this.black.push(tag);
18834             
18835         }, this);
18836         
18837         Roo.each(b, function(tag) {
18838             if (w.indexOf(tag) > -1) {
18839                 return;
18840             }
18841             if (this.black.indexOf(tag) > -1) {
18842                 return;
18843             }
18844             this.black.push(tag);
18845             
18846         }, this);
18847         
18848         
18849         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18850         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18851         
18852         this.cwhite = [];
18853         this.cblack = [];
18854         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18855             if (b.indexOf(tag) > -1) {
18856                 return;
18857             }
18858             this.cwhite.push(tag);
18859             
18860         }, this);
18861         
18862         Roo.each(w, function(tag) {
18863             if (b.indexOf(tag) > -1) {
18864                 return;
18865             }
18866             if (this.cwhite.indexOf(tag) > -1) {
18867                 return;
18868             }
18869             this.cwhite.push(tag);
18870             
18871         }, this);
18872         
18873         
18874         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18875             if (w.indexOf(tag) > -1) {
18876                 return;
18877             }
18878             this.cblack.push(tag);
18879             
18880         }, this);
18881         
18882         Roo.each(b, function(tag) {
18883             if (w.indexOf(tag) > -1) {
18884                 return;
18885             }
18886             if (this.cblack.indexOf(tag) > -1) {
18887                 return;
18888             }
18889             this.cblack.push(tag);
18890             
18891         }, this);
18892     },
18893     
18894     setStylesheets : function(stylesheets)
18895     {
18896         if(typeof(stylesheets) == 'string'){
18897             Roo.get(this.iframe.contentDocument.head).createChild({
18898                 tag : 'link',
18899                 rel : 'stylesheet',
18900                 type : 'text/css',
18901                 href : stylesheets
18902             });
18903             
18904             return;
18905         }
18906         var _this = this;
18907      
18908         Roo.each(stylesheets, function(s) {
18909             if(!s.length){
18910                 return;
18911             }
18912             
18913             Roo.get(_this.iframe.contentDocument.head).createChild({
18914                 tag : 'link',
18915                 rel : 'stylesheet',
18916                 type : 'text/css',
18917                 href : s
18918             });
18919         });
18920
18921         
18922     },
18923     
18924     removeStylesheets : function()
18925     {
18926         var _this = this;
18927         
18928         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18929             s.remove();
18930         });
18931     }
18932     
18933     // hide stuff that is not compatible
18934     /**
18935      * @event blur
18936      * @hide
18937      */
18938     /**
18939      * @event change
18940      * @hide
18941      */
18942     /**
18943      * @event focus
18944      * @hide
18945      */
18946     /**
18947      * @event specialkey
18948      * @hide
18949      */
18950     /**
18951      * @cfg {String} fieldClass @hide
18952      */
18953     /**
18954      * @cfg {String} focusClass @hide
18955      */
18956     /**
18957      * @cfg {String} autoCreate @hide
18958      */
18959     /**
18960      * @cfg {String} inputType @hide
18961      */
18962     /**
18963      * @cfg {String} invalidClass @hide
18964      */
18965     /**
18966      * @cfg {String} invalidText @hide
18967      */
18968     /**
18969      * @cfg {String} msgFx @hide
18970      */
18971     /**
18972      * @cfg {String} validateOnBlur @hide
18973      */
18974 });
18975
18976 Roo.HtmlEditorCore.white = [
18977         'area', 'br', 'img', 'input', 'hr', 'wbr',
18978         
18979        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
18980        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
18981        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
18982        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
18983        'table',   'ul',         'xmp', 
18984        
18985        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
18986       'thead',   'tr', 
18987      
18988       'dir', 'menu', 'ol', 'ul', 'dl',
18989        
18990       'embed',  'object'
18991 ];
18992
18993
18994 Roo.HtmlEditorCore.black = [
18995     //    'embed',  'object', // enable - backend responsiblity to clean thiese
18996         'applet', // 
18997         'base',   'basefont', 'bgsound', 'blink',  'body', 
18998         'frame',  'frameset', 'head',    'html',   'ilayer', 
18999         'iframe', 'layer',  'link',     'meta',    'object',   
19000         'script', 'style' ,'title',  'xml' // clean later..
19001 ];
19002 Roo.HtmlEditorCore.clean = [
19003     'script', 'style', 'title', 'xml'
19004 ];
19005 Roo.HtmlEditorCore.remove = [
19006     'font'
19007 ];
19008 // attributes..
19009
19010 Roo.HtmlEditorCore.ablack = [
19011     'on'
19012 ];
19013     
19014 Roo.HtmlEditorCore.aclean = [ 
19015     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
19016 ];
19017
19018 // protocols..
19019 Roo.HtmlEditorCore.pwhite= [
19020         'http',  'https',  'mailto'
19021 ];
19022
19023 // white listed style attributes.
19024 Roo.HtmlEditorCore.cwhite= [
19025       //  'text-align', /// default is to allow most things..
19026       
19027          
19028 //        'font-size'//??
19029 ];
19030
19031 // black listed style attributes.
19032 Roo.HtmlEditorCore.cblack= [
19033       //  'font-size' -- this can be set by the project 
19034 ];
19035
19036
19037 Roo.HtmlEditorCore.swapCodes   =[ 
19038     [    8211, "--" ], 
19039     [    8212, "--" ], 
19040     [    8216,  "'" ],  
19041     [    8217, "'" ],  
19042     [    8220, '"' ],  
19043     [    8221, '"' ],  
19044     [    8226, "*" ],  
19045     [    8230, "..." ]
19046 ]; 
19047
19048     /*
19049  * - LGPL
19050  *
19051  * HtmlEditor
19052  * 
19053  */
19054
19055 /**
19056  * @class Roo.bootstrap.HtmlEditor
19057  * @extends Roo.bootstrap.TextArea
19058  * Bootstrap HtmlEditor class
19059
19060  * @constructor
19061  * Create a new HtmlEditor
19062  * @param {Object} config The config object
19063  */
19064
19065 Roo.bootstrap.HtmlEditor = function(config){
19066     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19067     if (!this.toolbars) {
19068         this.toolbars = [];
19069     }
19070     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19071     this.addEvents({
19072             /**
19073              * @event initialize
19074              * Fires when the editor is fully initialized (including the iframe)
19075              * @param {HtmlEditor} this
19076              */
19077             initialize: true,
19078             /**
19079              * @event activate
19080              * Fires when the editor is first receives the focus. Any insertion must wait
19081              * until after this event.
19082              * @param {HtmlEditor} this
19083              */
19084             activate: true,
19085              /**
19086              * @event beforesync
19087              * Fires before the textarea is updated with content from the editor iframe. Return false
19088              * to cancel the sync.
19089              * @param {HtmlEditor} this
19090              * @param {String} html
19091              */
19092             beforesync: true,
19093              /**
19094              * @event beforepush
19095              * Fires before the iframe editor is updated with content from the textarea. Return false
19096              * to cancel the push.
19097              * @param {HtmlEditor} this
19098              * @param {String} html
19099              */
19100             beforepush: true,
19101              /**
19102              * @event sync
19103              * Fires when the textarea is updated with content from the editor iframe.
19104              * @param {HtmlEditor} this
19105              * @param {String} html
19106              */
19107             sync: true,
19108              /**
19109              * @event push
19110              * Fires when the iframe editor is updated with content from the textarea.
19111              * @param {HtmlEditor} this
19112              * @param {String} html
19113              */
19114             push: true,
19115              /**
19116              * @event editmodechange
19117              * Fires when the editor switches edit modes
19118              * @param {HtmlEditor} this
19119              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19120              */
19121             editmodechange: true,
19122             /**
19123              * @event editorevent
19124              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19125              * @param {HtmlEditor} this
19126              */
19127             editorevent: true,
19128             /**
19129              * @event firstfocus
19130              * Fires when on first focus - needed by toolbars..
19131              * @param {HtmlEditor} this
19132              */
19133             firstfocus: true,
19134             /**
19135              * @event autosave
19136              * Auto save the htmlEditor value as a file into Events
19137              * @param {HtmlEditor} this
19138              */
19139             autosave: true,
19140             /**
19141              * @event savedpreview
19142              * preview the saved version of htmlEditor
19143              * @param {HtmlEditor} this
19144              */
19145             savedpreview: true
19146         });
19147 };
19148
19149
19150 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19151     
19152     
19153       /**
19154      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19155      */
19156     toolbars : false,
19157    
19158      /**
19159      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19160      *                        Roo.resizable.
19161      */
19162     resizable : false,
19163      /**
19164      * @cfg {Number} height (in pixels)
19165      */   
19166     height: 300,
19167    /**
19168      * @cfg {Number} width (in pixels)
19169      */   
19170     width: false,
19171     
19172     /**
19173      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19174      * 
19175      */
19176     stylesheets: false,
19177     
19178     // id of frame..
19179     frameId: false,
19180     
19181     // private properties
19182     validationEvent : false,
19183     deferHeight: true,
19184     initialized : false,
19185     activated : false,
19186     
19187     onFocus : Roo.emptyFn,
19188     iframePad:3,
19189     hideMode:'offsets',
19190     
19191     
19192     tbContainer : false,
19193     
19194     toolbarContainer :function() {
19195         return this.wrap.select('.x-html-editor-tb',true).first();
19196     },
19197
19198     /**
19199      * Protected method that will not generally be called directly. It
19200      * is called when the editor creates its toolbar. Override this method if you need to
19201      * add custom toolbar buttons.
19202      * @param {HtmlEditor} editor
19203      */
19204     createToolbar : function(){
19205         
19206         Roo.log("create toolbars");
19207         
19208         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19209         this.toolbars[0].render(this.toolbarContainer());
19210         
19211         return;
19212         
19213 //        if (!editor.toolbars || !editor.toolbars.length) {
19214 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19215 //        }
19216 //        
19217 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19218 //            editor.toolbars[i] = Roo.factory(
19219 //                    typeof(editor.toolbars[i]) == 'string' ?
19220 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19221 //                Roo.bootstrap.HtmlEditor);
19222 //            editor.toolbars[i].init(editor);
19223 //        }
19224     },
19225
19226      
19227     // private
19228     onRender : function(ct, position)
19229     {
19230        // Roo.log("Call onRender: " + this.xtype);
19231         var _t = this;
19232         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19233       
19234         this.wrap = this.inputEl().wrap({
19235             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19236         });
19237         
19238         this.editorcore.onRender(ct, position);
19239          
19240         if (this.resizable) {
19241             this.resizeEl = new Roo.Resizable(this.wrap, {
19242                 pinned : true,
19243                 wrap: true,
19244                 dynamic : true,
19245                 minHeight : this.height,
19246                 height: this.height,
19247                 handles : this.resizable,
19248                 width: this.width,
19249                 listeners : {
19250                     resize : function(r, w, h) {
19251                         _t.onResize(w,h); // -something
19252                     }
19253                 }
19254             });
19255             
19256         }
19257         this.createToolbar(this);
19258        
19259         
19260         if(!this.width && this.resizable){
19261             this.setSize(this.wrap.getSize());
19262         }
19263         if (this.resizeEl) {
19264             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19265             // should trigger onReize..
19266         }
19267         
19268     },
19269
19270     // private
19271     onResize : function(w, h)
19272     {
19273         Roo.log('resize: ' +w + ',' + h );
19274         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19275         var ew = false;
19276         var eh = false;
19277         
19278         if(this.inputEl() ){
19279             if(typeof w == 'number'){
19280                 var aw = w - this.wrap.getFrameWidth('lr');
19281                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19282                 ew = aw;
19283             }
19284             if(typeof h == 'number'){
19285                  var tbh = -11;  // fixme it needs to tool bar size!
19286                 for (var i =0; i < this.toolbars.length;i++) {
19287                     // fixme - ask toolbars for heights?
19288                     tbh += this.toolbars[i].el.getHeight();
19289                     //if (this.toolbars[i].footer) {
19290                     //    tbh += this.toolbars[i].footer.el.getHeight();
19291                     //}
19292                 }
19293               
19294                 
19295                 
19296                 
19297                 
19298                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19299                 ah -= 5; // knock a few pixes off for look..
19300                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19301                 var eh = ah;
19302             }
19303         }
19304         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19305         this.editorcore.onResize(ew,eh);
19306         
19307     },
19308
19309     /**
19310      * Toggles the editor between standard and source edit mode.
19311      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19312      */
19313     toggleSourceEdit : function(sourceEditMode)
19314     {
19315         this.editorcore.toggleSourceEdit(sourceEditMode);
19316         
19317         if(this.editorcore.sourceEditMode){
19318             Roo.log('editor - showing textarea');
19319             
19320 //            Roo.log('in');
19321 //            Roo.log(this.syncValue());
19322             this.syncValue();
19323             this.inputEl().removeClass(['hide', 'x-hidden']);
19324             this.inputEl().dom.removeAttribute('tabIndex');
19325             this.inputEl().focus();
19326         }else{
19327             Roo.log('editor - hiding textarea');
19328 //            Roo.log('out')
19329 //            Roo.log(this.pushValue()); 
19330             this.pushValue();
19331             
19332             this.inputEl().addClass(['hide', 'x-hidden']);
19333             this.inputEl().dom.setAttribute('tabIndex', -1);
19334             //this.deferFocus();
19335         }
19336          
19337         if(this.resizable){
19338             this.setSize(this.wrap.getSize());
19339         }
19340         
19341         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19342     },
19343  
19344     // private (for BoxComponent)
19345     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19346
19347     // private (for BoxComponent)
19348     getResizeEl : function(){
19349         return this.wrap;
19350     },
19351
19352     // private (for BoxComponent)
19353     getPositionEl : function(){
19354         return this.wrap;
19355     },
19356
19357     // private
19358     initEvents : function(){
19359         this.originalValue = this.getValue();
19360     },
19361
19362 //    /**
19363 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19364 //     * @method
19365 //     */
19366 //    markInvalid : Roo.emptyFn,
19367 //    /**
19368 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19369 //     * @method
19370 //     */
19371 //    clearInvalid : Roo.emptyFn,
19372
19373     setValue : function(v){
19374         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19375         this.editorcore.pushValue();
19376     },
19377
19378      
19379     // private
19380     deferFocus : function(){
19381         this.focus.defer(10, this);
19382     },
19383
19384     // doc'ed in Field
19385     focus : function(){
19386         this.editorcore.focus();
19387         
19388     },
19389       
19390
19391     // private
19392     onDestroy : function(){
19393         
19394         
19395         
19396         if(this.rendered){
19397             
19398             for (var i =0; i < this.toolbars.length;i++) {
19399                 // fixme - ask toolbars for heights?
19400                 this.toolbars[i].onDestroy();
19401             }
19402             
19403             this.wrap.dom.innerHTML = '';
19404             this.wrap.remove();
19405         }
19406     },
19407
19408     // private
19409     onFirstFocus : function(){
19410         //Roo.log("onFirstFocus");
19411         this.editorcore.onFirstFocus();
19412          for (var i =0; i < this.toolbars.length;i++) {
19413             this.toolbars[i].onFirstFocus();
19414         }
19415         
19416     },
19417     
19418     // private
19419     syncValue : function()
19420     {   
19421         this.editorcore.syncValue();
19422     },
19423     
19424     pushValue : function()
19425     {   
19426         this.editorcore.pushValue();
19427     }
19428      
19429     
19430     // hide stuff that is not compatible
19431     /**
19432      * @event blur
19433      * @hide
19434      */
19435     /**
19436      * @event change
19437      * @hide
19438      */
19439     /**
19440      * @event focus
19441      * @hide
19442      */
19443     /**
19444      * @event specialkey
19445      * @hide
19446      */
19447     /**
19448      * @cfg {String} fieldClass @hide
19449      */
19450     /**
19451      * @cfg {String} focusClass @hide
19452      */
19453     /**
19454      * @cfg {String} autoCreate @hide
19455      */
19456     /**
19457      * @cfg {String} inputType @hide
19458      */
19459     /**
19460      * @cfg {String} invalidClass @hide
19461      */
19462     /**
19463      * @cfg {String} invalidText @hide
19464      */
19465     /**
19466      * @cfg {String} msgFx @hide
19467      */
19468     /**
19469      * @cfg {String} validateOnBlur @hide
19470      */
19471 });
19472  
19473     
19474    
19475    
19476    
19477       
19478 Roo.namespace('Roo.bootstrap.htmleditor');
19479 /**
19480  * @class Roo.bootstrap.HtmlEditorToolbar1
19481  * Basic Toolbar
19482  * 
19483  * Usage:
19484  *
19485  new Roo.bootstrap.HtmlEditor({
19486     ....
19487     toolbars : [
19488         new Roo.bootstrap.HtmlEditorToolbar1({
19489             disable : { fonts: 1 , format: 1, ..., ... , ...],
19490             btns : [ .... ]
19491         })
19492     }
19493      
19494  * 
19495  * @cfg {Object} disable List of elements to disable..
19496  * @cfg {Array} btns List of additional buttons.
19497  * 
19498  * 
19499  * NEEDS Extra CSS? 
19500  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19501  */
19502  
19503 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19504 {
19505     
19506     Roo.apply(this, config);
19507     
19508     // default disabled, based on 'good practice'..
19509     this.disable = this.disable || {};
19510     Roo.applyIf(this.disable, {
19511         fontSize : true,
19512         colors : true,
19513         specialElements : true
19514     });
19515     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19516     
19517     this.editor = config.editor;
19518     this.editorcore = config.editor.editorcore;
19519     
19520     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19521     
19522     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19523     // dont call parent... till later.
19524 }
19525 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19526      
19527     bar : true,
19528     
19529     editor : false,
19530     editorcore : false,
19531     
19532     
19533     formats : [
19534         "p" ,  
19535         "h1","h2","h3","h4","h5","h6", 
19536         "pre", "code", 
19537         "abbr", "acronym", "address", "cite", "samp", "var",
19538         'div','span'
19539     ],
19540     
19541     onRender : function(ct, position)
19542     {
19543        // Roo.log("Call onRender: " + this.xtype);
19544         
19545        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19546        Roo.log(this.el);
19547        this.el.dom.style.marginBottom = '0';
19548        var _this = this;
19549        var editorcore = this.editorcore;
19550        var editor= this.editor;
19551        
19552        var children = [];
19553        var btn = function(id,cmd , toggle, handler){
19554        
19555             var  event = toggle ? 'toggle' : 'click';
19556        
19557             var a = {
19558                 size : 'sm',
19559                 xtype: 'Button',
19560                 xns: Roo.bootstrap,
19561                 glyphicon : id,
19562                 cmd : id || cmd,
19563                 enableToggle:toggle !== false,
19564                 //html : 'submit'
19565                 pressed : toggle ? false : null,
19566                 listeners : {}
19567             }
19568             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19569                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19570             }
19571             children.push(a);
19572             return a;
19573        }
19574         
19575         var style = {
19576                 xtype: 'Button',
19577                 size : 'sm',
19578                 xns: Roo.bootstrap,
19579                 glyphicon : 'font',
19580                 //html : 'submit'
19581                 menu : {
19582                     xtype: 'Menu',
19583                     xns: Roo.bootstrap,
19584                     items:  []
19585                 }
19586         };
19587         Roo.each(this.formats, function(f) {
19588             style.menu.items.push({
19589                 xtype :'MenuItem',
19590                 xns: Roo.bootstrap,
19591                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19592                 tagname : f,
19593                 listeners : {
19594                     click : function()
19595                     {
19596                         editorcore.insertTag(this.tagname);
19597                         editor.focus();
19598                     }
19599                 }
19600                 
19601             });
19602         });
19603          children.push(style);   
19604             
19605             
19606         btn('bold',false,true);
19607         btn('italic',false,true);
19608         btn('align-left', 'justifyleft',true);
19609         btn('align-center', 'justifycenter',true);
19610         btn('align-right' , 'justifyright',true);
19611         btn('link', false, false, function(btn) {
19612             //Roo.log("create link?");
19613             var url = prompt(this.createLinkText, this.defaultLinkValue);
19614             if(url && url != 'http:/'+'/'){
19615                 this.editorcore.relayCmd('createlink', url);
19616             }
19617         }),
19618         btn('list','insertunorderedlist',true);
19619         btn('pencil', false,true, function(btn){
19620                 Roo.log(this);
19621                 
19622                 this.toggleSourceEdit(btn.pressed);
19623         });
19624         /*
19625         var cog = {
19626                 xtype: 'Button',
19627                 size : 'sm',
19628                 xns: Roo.bootstrap,
19629                 glyphicon : 'cog',
19630                 //html : 'submit'
19631                 menu : {
19632                     xtype: 'Menu',
19633                     xns: Roo.bootstrap,
19634                     items:  []
19635                 }
19636         };
19637         
19638         cog.menu.items.push({
19639             xtype :'MenuItem',
19640             xns: Roo.bootstrap,
19641             html : Clean styles,
19642             tagname : f,
19643             listeners : {
19644                 click : function()
19645                 {
19646                     editorcore.insertTag(this.tagname);
19647                     editor.focus();
19648                 }
19649             }
19650             
19651         });
19652        */
19653         
19654          
19655        this.xtype = 'NavSimplebar';
19656         
19657         for(var i=0;i< children.length;i++) {
19658             
19659             this.buttons.add(this.addxtypeChild(children[i]));
19660             
19661         }
19662         
19663         editor.on('editorevent', this.updateToolbar, this);
19664     },
19665     onBtnClick : function(id)
19666     {
19667        this.editorcore.relayCmd(id);
19668        this.editorcore.focus();
19669     },
19670     
19671     /**
19672      * Protected method that will not generally be called directly. It triggers
19673      * a toolbar update by reading the markup state of the current selection in the editor.
19674      */
19675     updateToolbar: function(){
19676
19677         if(!this.editorcore.activated){
19678             this.editor.onFirstFocus(); // is this neeed?
19679             return;
19680         }
19681
19682         var btns = this.buttons; 
19683         var doc = this.editorcore.doc;
19684         btns.get('bold').setActive(doc.queryCommandState('bold'));
19685         btns.get('italic').setActive(doc.queryCommandState('italic'));
19686         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19687         
19688         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19689         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19690         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19691         
19692         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19693         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19694          /*
19695         
19696         var ans = this.editorcore.getAllAncestors();
19697         if (this.formatCombo) {
19698             
19699             
19700             var store = this.formatCombo.store;
19701             this.formatCombo.setValue("");
19702             for (var i =0; i < ans.length;i++) {
19703                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19704                     // select it..
19705                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19706                     break;
19707                 }
19708             }
19709         }
19710         
19711         
19712         
19713         // hides menus... - so this cant be on a menu...
19714         Roo.bootstrap.MenuMgr.hideAll();
19715         */
19716         Roo.bootstrap.MenuMgr.hideAll();
19717         //this.editorsyncValue();
19718     },
19719     onFirstFocus: function() {
19720         this.buttons.each(function(item){
19721            item.enable();
19722         });
19723     },
19724     toggleSourceEdit : function(sourceEditMode){
19725         
19726           
19727         if(sourceEditMode){
19728             Roo.log("disabling buttons");
19729            this.buttons.each( function(item){
19730                 if(item.cmd != 'pencil'){
19731                     item.disable();
19732                 }
19733             });
19734           
19735         }else{
19736             Roo.log("enabling buttons");
19737             if(this.editorcore.initialized){
19738                 this.buttons.each( function(item){
19739                     item.enable();
19740                 });
19741             }
19742             
19743         }
19744         Roo.log("calling toggole on editor");
19745         // tell the editor that it's been pressed..
19746         this.editor.toggleSourceEdit(sourceEditMode);
19747        
19748     }
19749 });
19750
19751
19752
19753
19754
19755 /**
19756  * @class Roo.bootstrap.Table.AbstractSelectionModel
19757  * @extends Roo.util.Observable
19758  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19759  * implemented by descendant classes.  This class should not be directly instantiated.
19760  * @constructor
19761  */
19762 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19763     this.locked = false;
19764     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19765 };
19766
19767
19768 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19769     /** @ignore Called by the grid automatically. Do not call directly. */
19770     init : function(grid){
19771         this.grid = grid;
19772         this.initEvents();
19773     },
19774
19775     /**
19776      * Locks the selections.
19777      */
19778     lock : function(){
19779         this.locked = true;
19780     },
19781
19782     /**
19783      * Unlocks the selections.
19784      */
19785     unlock : function(){
19786         this.locked = false;
19787     },
19788
19789     /**
19790      * Returns true if the selections are locked.
19791      * @return {Boolean}
19792      */
19793     isLocked : function(){
19794         return this.locked;
19795     }
19796 });
19797 /**
19798  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19799  * @class Roo.bootstrap.Table.RowSelectionModel
19800  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19801  * It supports multiple selections and keyboard selection/navigation. 
19802  * @constructor
19803  * @param {Object} config
19804  */
19805
19806 Roo.bootstrap.Table.RowSelectionModel = function(config){
19807     Roo.apply(this, config);
19808     this.selections = new Roo.util.MixedCollection(false, function(o){
19809         return o.id;
19810     });
19811
19812     this.last = false;
19813     this.lastActive = false;
19814
19815     this.addEvents({
19816         /**
19817              * @event selectionchange
19818              * Fires when the selection changes
19819              * @param {SelectionModel} this
19820              */
19821             "selectionchange" : true,
19822         /**
19823              * @event afterselectionchange
19824              * Fires after the selection changes (eg. by key press or clicking)
19825              * @param {SelectionModel} this
19826              */
19827             "afterselectionchange" : true,
19828         /**
19829              * @event beforerowselect
19830              * Fires when a row is selected being selected, return false to cancel.
19831              * @param {SelectionModel} this
19832              * @param {Number} rowIndex The selected index
19833              * @param {Boolean} keepExisting False if other selections will be cleared
19834              */
19835             "beforerowselect" : true,
19836         /**
19837              * @event rowselect
19838              * Fires when a row is selected.
19839              * @param {SelectionModel} this
19840              * @param {Number} rowIndex The selected index
19841              * @param {Roo.data.Record} r The record
19842              */
19843             "rowselect" : true,
19844         /**
19845              * @event rowdeselect
19846              * Fires when a row is deselected.
19847              * @param {SelectionModel} this
19848              * @param {Number} rowIndex The selected index
19849              */
19850         "rowdeselect" : true
19851     });
19852     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19853     this.locked = false;
19854 };
19855
19856 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19857     /**
19858      * @cfg {Boolean} singleSelect
19859      * True to allow selection of only one row at a time (defaults to false)
19860      */
19861     singleSelect : false,
19862
19863     // private
19864     initEvents : function(){
19865
19866         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19867             this.grid.on("mousedown", this.handleMouseDown, this);
19868         }else{ // allow click to work like normal
19869             this.grid.on("rowclick", this.handleDragableRowClick, this);
19870         }
19871
19872         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19873             "up" : function(e){
19874                 if(!e.shiftKey){
19875                     this.selectPrevious(e.shiftKey);
19876                 }else if(this.last !== false && this.lastActive !== false){
19877                     var last = this.last;
19878                     this.selectRange(this.last,  this.lastActive-1);
19879                     this.grid.getView().focusRow(this.lastActive);
19880                     if(last !== false){
19881                         this.last = last;
19882                     }
19883                 }else{
19884                     this.selectFirstRow();
19885                 }
19886                 this.fireEvent("afterselectionchange", this);
19887             },
19888             "down" : function(e){
19889                 if(!e.shiftKey){
19890                     this.selectNext(e.shiftKey);
19891                 }else if(this.last !== false && this.lastActive !== false){
19892                     var last = this.last;
19893                     this.selectRange(this.last,  this.lastActive+1);
19894                     this.grid.getView().focusRow(this.lastActive);
19895                     if(last !== false){
19896                         this.last = last;
19897                     }
19898                 }else{
19899                     this.selectFirstRow();
19900                 }
19901                 this.fireEvent("afterselectionchange", this);
19902             },
19903             scope: this
19904         });
19905
19906         var view = this.grid.view;
19907         view.on("refresh", this.onRefresh, this);
19908         view.on("rowupdated", this.onRowUpdated, this);
19909         view.on("rowremoved", this.onRemove, this);
19910     },
19911
19912     // private
19913     onRefresh : function(){
19914         var ds = this.grid.dataSource, i, v = this.grid.view;
19915         var s = this.selections;
19916         s.each(function(r){
19917             if((i = ds.indexOfId(r.id)) != -1){
19918                 v.onRowSelect(i);
19919             }else{
19920                 s.remove(r);
19921             }
19922         });
19923     },
19924
19925     // private
19926     onRemove : function(v, index, r){
19927         this.selections.remove(r);
19928     },
19929
19930     // private
19931     onRowUpdated : function(v, index, r){
19932         if(this.isSelected(r)){
19933             v.onRowSelect(index);
19934         }
19935     },
19936
19937     /**
19938      * Select records.
19939      * @param {Array} records The records to select
19940      * @param {Boolean} keepExisting (optional) True to keep existing selections
19941      */
19942     selectRecords : function(records, keepExisting){
19943         if(!keepExisting){
19944             this.clearSelections();
19945         }
19946         var ds = this.grid.dataSource;
19947         for(var i = 0, len = records.length; i < len; i++){
19948             this.selectRow(ds.indexOf(records[i]), true);
19949         }
19950     },
19951
19952     /**
19953      * Gets the number of selected rows.
19954      * @return {Number}
19955      */
19956     getCount : function(){
19957         return this.selections.length;
19958     },
19959
19960     /**
19961      * Selects the first row in the grid.
19962      */
19963     selectFirstRow : function(){
19964         this.selectRow(0);
19965     },
19966
19967     /**
19968      * Select the last row.
19969      * @param {Boolean} keepExisting (optional) True to keep existing selections
19970      */
19971     selectLastRow : function(keepExisting){
19972         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19973     },
19974
19975     /**
19976      * Selects the row immediately following the last selected row.
19977      * @param {Boolean} keepExisting (optional) True to keep existing selections
19978      */
19979     selectNext : function(keepExisting){
19980         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19981             this.selectRow(this.last+1, keepExisting);
19982             this.grid.getView().focusRow(this.last);
19983         }
19984     },
19985
19986     /**
19987      * Selects the row that precedes the last selected row.
19988      * @param {Boolean} keepExisting (optional) True to keep existing selections
19989      */
19990     selectPrevious : function(keepExisting){
19991         if(this.last){
19992             this.selectRow(this.last-1, keepExisting);
19993             this.grid.getView().focusRow(this.last);
19994         }
19995     },
19996
19997     /**
19998      * Returns the selected records
19999      * @return {Array} Array of selected records
20000      */
20001     getSelections : function(){
20002         return [].concat(this.selections.items);
20003     },
20004
20005     /**
20006      * Returns the first selected record.
20007      * @return {Record}
20008      */
20009     getSelected : function(){
20010         return this.selections.itemAt(0);
20011     },
20012
20013
20014     /**
20015      * Clears all selections.
20016      */
20017     clearSelections : function(fast){
20018         if(this.locked) return;
20019         if(fast !== true){
20020             var ds = this.grid.dataSource;
20021             var s = this.selections;
20022             s.each(function(r){
20023                 this.deselectRow(ds.indexOfId(r.id));
20024             }, this);
20025             s.clear();
20026         }else{
20027             this.selections.clear();
20028         }
20029         this.last = false;
20030     },
20031
20032
20033     /**
20034      * Selects all rows.
20035      */
20036     selectAll : function(){
20037         if(this.locked) return;
20038         this.selections.clear();
20039         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20040             this.selectRow(i, true);
20041         }
20042     },
20043
20044     /**
20045      * Returns True if there is a selection.
20046      * @return {Boolean}
20047      */
20048     hasSelection : function(){
20049         return this.selections.length > 0;
20050     },
20051
20052     /**
20053      * Returns True if the specified row is selected.
20054      * @param {Number/Record} record The record or index of the record to check
20055      * @return {Boolean}
20056      */
20057     isSelected : function(index){
20058         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20059         return (r && this.selections.key(r.id) ? true : false);
20060     },
20061
20062     /**
20063      * Returns True if the specified record id is selected.
20064      * @param {String} id The id of record to check
20065      * @return {Boolean}
20066      */
20067     isIdSelected : function(id){
20068         return (this.selections.key(id) ? true : false);
20069     },
20070
20071     // private
20072     handleMouseDown : function(e, t){
20073         var view = this.grid.getView(), rowIndex;
20074         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20075             return;
20076         };
20077         if(e.shiftKey && this.last !== false){
20078             var last = this.last;
20079             this.selectRange(last, rowIndex, e.ctrlKey);
20080             this.last = last; // reset the last
20081             view.focusRow(rowIndex);
20082         }else{
20083             var isSelected = this.isSelected(rowIndex);
20084             if(e.button !== 0 && isSelected){
20085                 view.focusRow(rowIndex);
20086             }else if(e.ctrlKey && isSelected){
20087                 this.deselectRow(rowIndex);
20088             }else if(!isSelected){
20089                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20090                 view.focusRow(rowIndex);
20091             }
20092         }
20093         this.fireEvent("afterselectionchange", this);
20094     },
20095     // private
20096     handleDragableRowClick :  function(grid, rowIndex, e) 
20097     {
20098         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20099             this.selectRow(rowIndex, false);
20100             grid.view.focusRow(rowIndex);
20101              this.fireEvent("afterselectionchange", this);
20102         }
20103     },
20104     
20105     /**
20106      * Selects multiple rows.
20107      * @param {Array} rows Array of the indexes of the row to select
20108      * @param {Boolean} keepExisting (optional) True to keep existing selections
20109      */
20110     selectRows : function(rows, keepExisting){
20111         if(!keepExisting){
20112             this.clearSelections();
20113         }
20114         for(var i = 0, len = rows.length; i < len; i++){
20115             this.selectRow(rows[i], true);
20116         }
20117     },
20118
20119     /**
20120      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20121      * @param {Number} startRow The index of the first row in the range
20122      * @param {Number} endRow The index of the last row in the range
20123      * @param {Boolean} keepExisting (optional) True to retain existing selections
20124      */
20125     selectRange : function(startRow, endRow, keepExisting){
20126         if(this.locked) return;
20127         if(!keepExisting){
20128             this.clearSelections();
20129         }
20130         if(startRow <= endRow){
20131             for(var i = startRow; i <= endRow; i++){
20132                 this.selectRow(i, true);
20133             }
20134         }else{
20135             for(var i = startRow; i >= endRow; i--){
20136                 this.selectRow(i, true);
20137             }
20138         }
20139     },
20140
20141     /**
20142      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20143      * @param {Number} startRow The index of the first row in the range
20144      * @param {Number} endRow The index of the last row in the range
20145      */
20146     deselectRange : function(startRow, endRow, preventViewNotify){
20147         if(this.locked) return;
20148         for(var i = startRow; i <= endRow; i++){
20149             this.deselectRow(i, preventViewNotify);
20150         }
20151     },
20152
20153     /**
20154      * Selects a row.
20155      * @param {Number} row The index of the row to select
20156      * @param {Boolean} keepExisting (optional) True to keep existing selections
20157      */
20158     selectRow : function(index, keepExisting, preventViewNotify){
20159         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20160         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20161             if(!keepExisting || this.singleSelect){
20162                 this.clearSelections();
20163             }
20164             var r = this.grid.dataSource.getAt(index);
20165             this.selections.add(r);
20166             this.last = this.lastActive = index;
20167             if(!preventViewNotify){
20168                 this.grid.getView().onRowSelect(index);
20169             }
20170             this.fireEvent("rowselect", this, index, r);
20171             this.fireEvent("selectionchange", this);
20172         }
20173     },
20174
20175     /**
20176      * Deselects a row.
20177      * @param {Number} row The index of the row to deselect
20178      */
20179     deselectRow : function(index, preventViewNotify){
20180         if(this.locked) return;
20181         if(this.last == index){
20182             this.last = false;
20183         }
20184         if(this.lastActive == index){
20185             this.lastActive = false;
20186         }
20187         var r = this.grid.dataSource.getAt(index);
20188         this.selections.remove(r);
20189         if(!preventViewNotify){
20190             this.grid.getView().onRowDeselect(index);
20191         }
20192         this.fireEvent("rowdeselect", this, index);
20193         this.fireEvent("selectionchange", this);
20194     },
20195
20196     // private
20197     restoreLast : function(){
20198         if(this._last){
20199             this.last = this._last;
20200         }
20201     },
20202
20203     // private
20204     acceptsNav : function(row, col, cm){
20205         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20206     },
20207
20208     // private
20209     onEditorKey : function(field, e){
20210         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20211         if(k == e.TAB){
20212             e.stopEvent();
20213             ed.completeEdit();
20214             if(e.shiftKey){
20215                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20216             }else{
20217                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20218             }
20219         }else if(k == e.ENTER && !e.ctrlKey){
20220             e.stopEvent();
20221             ed.completeEdit();
20222             if(e.shiftKey){
20223                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20224             }else{
20225                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20226             }
20227         }else if(k == e.ESC){
20228             ed.cancelEdit();
20229         }
20230         if(newCell){
20231             g.startEditing(newCell[0], newCell[1]);
20232         }
20233     }
20234 });/*
20235  * Based on:
20236  * Ext JS Library 1.1.1
20237  * Copyright(c) 2006-2007, Ext JS, LLC.
20238  *
20239  * Originally Released Under LGPL - original licence link has changed is not relivant.
20240  *
20241  * Fork - LGPL
20242  * <script type="text/javascript">
20243  */
20244  
20245 /**
20246  * @class Roo.bootstrap.PagingToolbar
20247  * @extends Roo.Row
20248  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20249  * @constructor
20250  * Create a new PagingToolbar
20251  * @param {Object} config The config object
20252  */
20253 Roo.bootstrap.PagingToolbar = function(config)
20254 {
20255     // old args format still supported... - xtype is prefered..
20256         // created from xtype...
20257     var ds = config.dataSource;
20258     this.toolbarItems = [];
20259     if (config.items) {
20260         this.toolbarItems = config.items;
20261 //        config.items = [];
20262     }
20263     
20264     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20265     this.ds = ds;
20266     this.cursor = 0;
20267     if (ds) { 
20268         this.bind(ds);
20269     }
20270     
20271     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20272     
20273 };
20274
20275 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20276     /**
20277      * @cfg {Roo.data.Store} dataSource
20278      * The underlying data store providing the paged data
20279      */
20280     /**
20281      * @cfg {String/HTMLElement/Element} container
20282      * container The id or element that will contain the toolbar
20283      */
20284     /**
20285      * @cfg {Boolean} displayInfo
20286      * True to display the displayMsg (defaults to false)
20287      */
20288     /**
20289      * @cfg {Number} pageSize
20290      * The number of records to display per page (defaults to 20)
20291      */
20292     pageSize: 20,
20293     /**
20294      * @cfg {String} displayMsg
20295      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20296      */
20297     displayMsg : 'Displaying {0} - {1} of {2}',
20298     /**
20299      * @cfg {String} emptyMsg
20300      * The message to display when no records are found (defaults to "No data to display")
20301      */
20302     emptyMsg : 'No data to display',
20303     /**
20304      * Customizable piece of the default paging text (defaults to "Page")
20305      * @type String
20306      */
20307     beforePageText : "Page",
20308     /**
20309      * Customizable piece of the default paging text (defaults to "of %0")
20310      * @type String
20311      */
20312     afterPageText : "of {0}",
20313     /**
20314      * Customizable piece of the default paging text (defaults to "First Page")
20315      * @type String
20316      */
20317     firstText : "First Page",
20318     /**
20319      * Customizable piece of the default paging text (defaults to "Previous Page")
20320      * @type String
20321      */
20322     prevText : "Previous Page",
20323     /**
20324      * Customizable piece of the default paging text (defaults to "Next Page")
20325      * @type String
20326      */
20327     nextText : "Next Page",
20328     /**
20329      * Customizable piece of the default paging text (defaults to "Last Page")
20330      * @type String
20331      */
20332     lastText : "Last Page",
20333     /**
20334      * Customizable piece of the default paging text (defaults to "Refresh")
20335      * @type String
20336      */
20337     refreshText : "Refresh",
20338
20339     buttons : false,
20340     // private
20341     onRender : function(ct, position) 
20342     {
20343         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20344         this.navgroup.parentId = this.id;
20345         this.navgroup.onRender(this.el, null);
20346         // add the buttons to the navgroup
20347         
20348         if(this.displayInfo){
20349             Roo.log(this.el.select('ul.navbar-nav',true).first());
20350             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20351             this.displayEl = this.el.select('.x-paging-info', true).first();
20352 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20353 //            this.displayEl = navel.el.select('span',true).first();
20354         }
20355         
20356         var _this = this;
20357         
20358         if(this.buttons){
20359             Roo.each(_this.buttons, function(e){
20360                Roo.factory(e).onRender(_this.el, null);
20361             });
20362         }
20363             
20364         Roo.each(_this.toolbarItems, function(e) {
20365             _this.navgroup.addItem(e);
20366         });
20367         
20368         
20369         this.first = this.navgroup.addItem({
20370             tooltip: this.firstText,
20371             cls: "prev",
20372             icon : 'fa fa-backward',
20373             disabled: true,
20374             preventDefault: true,
20375             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20376         });
20377         
20378         this.prev =  this.navgroup.addItem({
20379             tooltip: this.prevText,
20380             cls: "prev",
20381             icon : 'fa fa-step-backward',
20382             disabled: true,
20383             preventDefault: true,
20384             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20385         });
20386     //this.addSeparator();
20387         
20388         
20389         var field = this.navgroup.addItem( {
20390             tagtype : 'span',
20391             cls : 'x-paging-position',
20392             
20393             html : this.beforePageText  +
20394                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20395                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20396          } ); //?? escaped?
20397         
20398         this.field = field.el.select('input', true).first();
20399         this.field.on("keydown", this.onPagingKeydown, this);
20400         this.field.on("focus", function(){this.dom.select();});
20401     
20402     
20403         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20404         //this.field.setHeight(18);
20405         //this.addSeparator();
20406         this.next = this.navgroup.addItem({
20407             tooltip: this.nextText,
20408             cls: "next",
20409             html : ' <i class="fa fa-step-forward">',
20410             disabled: true,
20411             preventDefault: true,
20412             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20413         });
20414         this.last = this.navgroup.addItem({
20415             tooltip: this.lastText,
20416             icon : 'fa fa-forward',
20417             cls: "next",
20418             disabled: true,
20419             preventDefault: true,
20420             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20421         });
20422     //this.addSeparator();
20423         this.loading = this.navgroup.addItem({
20424             tooltip: this.refreshText,
20425             icon: 'fa fa-refresh',
20426             preventDefault: true,
20427             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20428         });
20429
20430     },
20431
20432     // private
20433     updateInfo : function(){
20434         if(this.displayEl){
20435             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20436             var msg = count == 0 ?
20437                 this.emptyMsg :
20438                 String.format(
20439                     this.displayMsg,
20440                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20441                 );
20442             this.displayEl.update(msg);
20443         }
20444     },
20445
20446     // private
20447     onLoad : function(ds, r, o){
20448        this.cursor = o.params ? o.params.start : 0;
20449        var d = this.getPageData(),
20450             ap = d.activePage,
20451             ps = d.pages;
20452         
20453        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20454        this.field.dom.value = ap;
20455        this.first.setDisabled(ap == 1);
20456        this.prev.setDisabled(ap == 1);
20457        this.next.setDisabled(ap == ps);
20458        this.last.setDisabled(ap == ps);
20459        this.loading.enable();
20460        this.updateInfo();
20461     },
20462
20463     // private
20464     getPageData : function(){
20465         var total = this.ds.getTotalCount();
20466         return {
20467             total : total,
20468             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20469             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20470         };
20471     },
20472
20473     // private
20474     onLoadError : function(){
20475         this.loading.enable();
20476     },
20477
20478     // private
20479     onPagingKeydown : function(e){
20480         var k = e.getKey();
20481         var d = this.getPageData();
20482         if(k == e.RETURN){
20483             var v = this.field.dom.value, pageNum;
20484             if(!v || isNaN(pageNum = parseInt(v, 10))){
20485                 this.field.dom.value = d.activePage;
20486                 return;
20487             }
20488             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20489             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20490             e.stopEvent();
20491         }
20492         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))
20493         {
20494           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20495           this.field.dom.value = pageNum;
20496           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20497           e.stopEvent();
20498         }
20499         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20500         {
20501           var v = this.field.dom.value, pageNum; 
20502           var increment = (e.shiftKey) ? 10 : 1;
20503           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20504             increment *= -1;
20505           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20506             this.field.dom.value = d.activePage;
20507             return;
20508           }
20509           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20510           {
20511             this.field.dom.value = parseInt(v, 10) + increment;
20512             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20513             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20514           }
20515           e.stopEvent();
20516         }
20517     },
20518
20519     // private
20520     beforeLoad : function(){
20521         if(this.loading){
20522             this.loading.disable();
20523         }
20524     },
20525
20526     // private
20527     onClick : function(which){
20528         
20529         var ds = this.ds;
20530         if (!ds) {
20531             return;
20532         }
20533         
20534         switch(which){
20535             case "first":
20536                 ds.load({params:{start: 0, limit: this.pageSize}});
20537             break;
20538             case "prev":
20539                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20540             break;
20541             case "next":
20542                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20543             break;
20544             case "last":
20545                 var total = ds.getTotalCount();
20546                 var extra = total % this.pageSize;
20547                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20548                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20549             break;
20550             case "refresh":
20551                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20552             break;
20553         }
20554     },
20555
20556     /**
20557      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20558      * @param {Roo.data.Store} store The data store to unbind
20559      */
20560     unbind : function(ds){
20561         ds.un("beforeload", this.beforeLoad, this);
20562         ds.un("load", this.onLoad, this);
20563         ds.un("loadexception", this.onLoadError, this);
20564         ds.un("remove", this.updateInfo, this);
20565         ds.un("add", this.updateInfo, this);
20566         this.ds = undefined;
20567     },
20568
20569     /**
20570      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20571      * @param {Roo.data.Store} store The data store to bind
20572      */
20573     bind : function(ds){
20574         ds.on("beforeload", this.beforeLoad, this);
20575         ds.on("load", this.onLoad, this);
20576         ds.on("loadexception", this.onLoadError, this);
20577         ds.on("remove", this.updateInfo, this);
20578         ds.on("add", this.updateInfo, this);
20579         this.ds = ds;
20580     }
20581 });/*
20582  * - LGPL
20583  *
20584  * element
20585  * 
20586  */
20587
20588 /**
20589  * @class Roo.bootstrap.MessageBar
20590  * @extends Roo.bootstrap.Component
20591  * Bootstrap MessageBar class
20592  * @cfg {String} html contents of the MessageBar
20593  * @cfg {String} weight (info | success | warning | danger) default info
20594  * @cfg {String} beforeClass insert the bar before the given class
20595  * @cfg {Boolean} closable (true | false) default false
20596  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20597  * 
20598  * @constructor
20599  * Create a new Element
20600  * @param {Object} config The config object
20601  */
20602
20603 Roo.bootstrap.MessageBar = function(config){
20604     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20605 };
20606
20607 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20608     
20609     html: '',
20610     weight: 'info',
20611     closable: false,
20612     fixed: false,
20613     beforeClass: 'bootstrap-sticky-wrap',
20614     
20615     getAutoCreate : function(){
20616         
20617         var cfg = {
20618             tag: 'div',
20619             cls: 'alert alert-dismissable alert-' + this.weight,
20620             cn: [
20621                 {
20622                     tag: 'span',
20623                     cls: 'message',
20624                     html: this.html || ''
20625                 }
20626             ]
20627         }
20628         
20629         if(this.fixed){
20630             cfg.cls += ' alert-messages-fixed';
20631         }
20632         
20633         if(this.closable){
20634             cfg.cn.push({
20635                 tag: 'button',
20636                 cls: 'close',
20637                 html: 'x'
20638             });
20639         }
20640         
20641         return cfg;
20642     },
20643     
20644     onRender : function(ct, position)
20645     {
20646         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20647         
20648         if(!this.el){
20649             var cfg = Roo.apply({},  this.getAutoCreate());
20650             cfg.id = Roo.id();
20651             
20652             if (this.cls) {
20653                 cfg.cls += ' ' + this.cls;
20654             }
20655             if (this.style) {
20656                 cfg.style = this.style;
20657             }
20658             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20659             
20660             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20661         }
20662         
20663         this.el.select('>button.close').on('click', this.hide, this);
20664         
20665     },
20666     
20667     show : function()
20668     {
20669         if (!this.rendered) {
20670             this.render();
20671         }
20672         
20673         this.el.show();
20674         
20675         this.fireEvent('show', this);
20676         
20677     },
20678     
20679     hide : function()
20680     {
20681         if (!this.rendered) {
20682             this.render();
20683         }
20684         
20685         this.el.hide();
20686         
20687         this.fireEvent('hide', this);
20688     },
20689     
20690     update : function()
20691     {
20692 //        var e = this.el.dom.firstChild;
20693 //        
20694 //        if(this.closable){
20695 //            e = e.nextSibling;
20696 //        }
20697 //        
20698 //        e.data = this.html || '';
20699
20700         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20701     }
20702    
20703 });
20704
20705  
20706
20707      /*
20708  * - LGPL
20709  *
20710  * Graph
20711  * 
20712  */
20713
20714
20715 /**
20716  * @class Roo.bootstrap.Graph
20717  * @extends Roo.bootstrap.Component
20718  * Bootstrap Graph class
20719 > Prameters
20720  -sm {number} sm 4
20721  -md {number} md 5
20722  @cfg {String} graphtype  bar | vbar | pie
20723  @cfg {number} g_x coodinator | centre x (pie)
20724  @cfg {number} g_y coodinator | centre y (pie)
20725  @cfg {number} g_r radius (pie)
20726  @cfg {number} g_height height of the chart (respected by all elements in the set)
20727  @cfg {number} g_width width of the chart (respected by all elements in the set)
20728  @cfg {Object} title The title of the chart
20729     
20730  -{Array}  values
20731  -opts (object) options for the chart 
20732      o {
20733      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20734      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20735      o vgutter (number)
20736      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.
20737      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20738      o to
20739      o stretch (boolean)
20740      o }
20741  -opts (object) options for the pie
20742      o{
20743      o cut
20744      o startAngle (number)
20745      o endAngle (number)
20746      } 
20747  *
20748  * @constructor
20749  * Create a new Input
20750  * @param {Object} config The config object
20751  */
20752
20753 Roo.bootstrap.Graph = function(config){
20754     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20755     
20756     this.addEvents({
20757         // img events
20758         /**
20759          * @event click
20760          * The img click event for the img.
20761          * @param {Roo.EventObject} e
20762          */
20763         "click" : true
20764     });
20765 };
20766
20767 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20768     
20769     sm: 4,
20770     md: 5,
20771     graphtype: 'bar',
20772     g_height: 250,
20773     g_width: 400,
20774     g_x: 50,
20775     g_y: 50,
20776     g_r: 30,
20777     opts:{
20778         //g_colors: this.colors,
20779         g_type: 'soft',
20780         g_gutter: '20%'
20781
20782     },
20783     title : false,
20784
20785     getAutoCreate : function(){
20786         
20787         var cfg = {
20788             tag: 'div',
20789             html : null
20790         }
20791         
20792         
20793         return  cfg;
20794     },
20795
20796     onRender : function(ct,position){
20797         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20798         this.raphael = Raphael(this.el.dom);
20799         
20800                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20801                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20802                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20803                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20804                 /*
20805                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20806                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20807                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20808                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20809                 
20810                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20811                 r.barchart(330, 10, 300, 220, data1);
20812                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20813                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20814                 */
20815                 
20816                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20817                 // r.barchart(30, 30, 560, 250,  xdata, {
20818                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20819                 //     axis : "0 0 1 1",
20820                 //     axisxlabels :  xdata
20821                 //     //yvalues : cols,
20822                    
20823                 // });
20824 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20825 //        
20826 //        this.load(null,xdata,{
20827 //                axis : "0 0 1 1",
20828 //                axisxlabels :  xdata
20829 //                });
20830
20831     },
20832
20833     load : function(graphtype,xdata,opts){
20834         this.raphael.clear();
20835         if(!graphtype) {
20836             graphtype = this.graphtype;
20837         }
20838         if(!opts){
20839             opts = this.opts;
20840         }
20841         var r = this.raphael,
20842             fin = function () {
20843                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20844             },
20845             fout = function () {
20846                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20847             },
20848             pfin = function() {
20849                 this.sector.stop();
20850                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20851
20852                 if (this.label) {
20853                     this.label[0].stop();
20854                     this.label[0].attr({ r: 7.5 });
20855                     this.label[1].attr({ "font-weight": 800 });
20856                 }
20857             },
20858             pfout = function() {
20859                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20860
20861                 if (this.label) {
20862                     this.label[0].animate({ r: 5 }, 500, "bounce");
20863                     this.label[1].attr({ "font-weight": 400 });
20864                 }
20865             };
20866
20867         switch(graphtype){
20868             case 'bar':
20869                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20870                 break;
20871             case 'hbar':
20872                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20873                 break;
20874             case 'pie':
20875 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20876 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20877 //            
20878                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20879                 
20880                 break;
20881
20882         }
20883         
20884         if(this.title){
20885             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20886         }
20887         
20888     },
20889     
20890     setTitle: function(o)
20891     {
20892         this.title = o;
20893     },
20894     
20895     initEvents: function() {
20896         
20897         if(!this.href){
20898             this.el.on('click', this.onClick, this);
20899         }
20900     },
20901     
20902     onClick : function(e)
20903     {
20904         Roo.log('img onclick');
20905         this.fireEvent('click', this, e);
20906     }
20907    
20908 });
20909
20910  
20911 /*
20912  * - LGPL
20913  *
20914  * numberBox
20915  * 
20916  */
20917 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20918
20919 /**
20920  * @class Roo.bootstrap.dash.NumberBox
20921  * @extends Roo.bootstrap.Component
20922  * Bootstrap NumberBox class
20923  * @cfg {String} headline Box headline
20924  * @cfg {String} content Box content
20925  * @cfg {String} icon Box icon
20926  * @cfg {String} footer Footer text
20927  * @cfg {String} fhref Footer href
20928  * 
20929  * @constructor
20930  * Create a new NumberBox
20931  * @param {Object} config The config object
20932  */
20933
20934
20935 Roo.bootstrap.dash.NumberBox = function(config){
20936     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20937     
20938 };
20939
20940 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
20941     
20942     headline : '',
20943     content : '',
20944     icon : '',
20945     footer : '',
20946     fhref : '',
20947     ficon : '',
20948     
20949     getAutoCreate : function(){
20950         
20951         var cfg = {
20952             tag : 'div',
20953             cls : 'small-box ',
20954             cn : [
20955                 {
20956                     tag : 'div',
20957                     cls : 'inner',
20958                     cn :[
20959                         {
20960                             tag : 'h3',
20961                             cls : 'roo-headline',
20962                             html : this.headline
20963                         },
20964                         {
20965                             tag : 'p',
20966                             cls : 'roo-content',
20967                             html : this.content
20968                         }
20969                     ]
20970                 }
20971             ]
20972         }
20973         
20974         if(this.icon){
20975             cfg.cn.push({
20976                 tag : 'div',
20977                 cls : 'icon',
20978                 cn :[
20979                     {
20980                         tag : 'i',
20981                         cls : 'ion ' + this.icon
20982                     }
20983                 ]
20984             });
20985         }
20986         
20987         if(this.footer){
20988             var footer = {
20989                 tag : 'a',
20990                 cls : 'small-box-footer',
20991                 href : this.fhref || '#',
20992                 html : this.footer
20993             };
20994             
20995             cfg.cn.push(footer);
20996             
20997         }
20998         
20999         return  cfg;
21000     },
21001
21002     onRender : function(ct,position){
21003         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21004
21005
21006        
21007                 
21008     },
21009
21010     setHeadline: function (value)
21011     {
21012         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21013     },
21014     
21015     setFooter: function (value, href)
21016     {
21017         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21018         
21019         if(href){
21020             this.el.select('a.small-box-footer',true).first().attr('href', href);
21021         }
21022         
21023     },
21024
21025     setContent: function (value)
21026     {
21027         this.el.select('.roo-content',true).first().dom.innerHTML = value;
21028     },
21029
21030     initEvents: function() 
21031     {   
21032         
21033     }
21034     
21035 });
21036
21037  
21038 /*
21039  * - LGPL
21040  *
21041  * TabBox
21042  * 
21043  */
21044 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21045
21046 /**
21047  * @class Roo.bootstrap.dash.TabBox
21048  * @extends Roo.bootstrap.Component
21049  * Bootstrap TabBox class
21050  * @cfg {String} title Title of the TabBox
21051  * @cfg {String} icon Icon of the TabBox
21052  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21053  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21054  * 
21055  * @constructor
21056  * Create a new TabBox
21057  * @param {Object} config The config object
21058  */
21059
21060
21061 Roo.bootstrap.dash.TabBox = function(config){
21062     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21063     this.addEvents({
21064         // raw events
21065         /**
21066          * @event addpane
21067          * When a pane is added
21068          * @param {Roo.bootstrap.dash.TabPane} pane
21069          */
21070         "addpane" : true,
21071         /**
21072          * @event activatepane
21073          * When a pane is activated
21074          * @param {Roo.bootstrap.dash.TabPane} pane
21075          */
21076         "activatepane" : true
21077         
21078          
21079     });
21080     
21081     this.panes = [];
21082 };
21083
21084 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21085
21086     title : '',
21087     icon : false,
21088     showtabs : true,
21089     tabScrollable : false,
21090     
21091     getChildContainer : function()
21092     {
21093         return this.el.select('.tab-content', true).first();
21094     },
21095     
21096     getAutoCreate : function(){
21097         
21098         var header = {
21099             tag: 'li',
21100             cls: 'pull-left header',
21101             html: this.title,
21102             cn : []
21103         };
21104         
21105         if(this.icon){
21106             header.cn.push({
21107                 tag: 'i',
21108                 cls: 'fa ' + this.icon
21109             });
21110         }
21111         
21112         var h = {
21113             tag: 'ul',
21114             cls: 'nav nav-tabs pull-right',
21115             cn: [
21116                 header
21117             ]
21118         };
21119         
21120         if(this.tabScrollable){
21121             h = {
21122                 tag: 'div',
21123                 cls: 'tab-header',
21124                 cn: [
21125                     {
21126                         tag: 'ul',
21127                         cls: 'nav nav-tabs pull-right',
21128                         cn: [
21129                             header
21130                         ]
21131                     }
21132                 ]
21133             }
21134         }
21135         
21136         var cfg = {
21137             tag: 'div',
21138             cls: 'nav-tabs-custom',
21139             cn: [
21140                 h,
21141                 {
21142                     tag: 'div',
21143                     cls: 'tab-content no-padding',
21144                     cn: []
21145                 }
21146             ]
21147         }
21148
21149         return  cfg;
21150     },
21151     initEvents : function()
21152     {
21153         //Roo.log('add add pane handler');
21154         this.on('addpane', this.onAddPane, this);
21155     },
21156      /**
21157      * Updates the box title
21158      * @param {String} html to set the title to.
21159      */
21160     setTitle : function(value)
21161     {
21162         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21163     },
21164     onAddPane : function(pane)
21165     {
21166         this.panes.push(pane);
21167         //Roo.log('addpane');
21168         //Roo.log(pane);
21169         // tabs are rendere left to right..
21170         if(!this.showtabs){
21171             return;
21172         }
21173         
21174         var ctr = this.el.select('.nav-tabs', true).first();
21175          
21176          
21177         var existing = ctr.select('.nav-tab',true);
21178         var qty = existing.getCount();;
21179         
21180         
21181         var tab = ctr.createChild({
21182             tag : 'li',
21183             cls : 'nav-tab' + (qty ? '' : ' active'),
21184             cn : [
21185                 {
21186                     tag : 'a',
21187                     href:'#',
21188                     html : pane.title
21189                 }
21190             ]
21191         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21192         pane.tab = tab;
21193         
21194         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21195         if (!qty) {
21196             pane.el.addClass('active');
21197         }
21198         
21199                 
21200     },
21201     onTabClick : function(ev,un,ob,pane)
21202     {
21203         //Roo.log('tab - prev default');
21204         ev.preventDefault();
21205         
21206         
21207         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21208         pane.tab.addClass('active');
21209         //Roo.log(pane.title);
21210         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21211         // technically we should have a deactivate event.. but maybe add later.
21212         // and it should not de-activate the selected tab...
21213         this.fireEvent('activatepane', pane);
21214         pane.el.addClass('active');
21215         pane.fireEvent('activate');
21216         
21217         
21218     },
21219     
21220     getActivePane : function()
21221     {
21222         var r = false;
21223         Roo.each(this.panes, function(p) {
21224             if(p.el.hasClass('active')){
21225                 r = p;
21226                 return false;
21227             }
21228             
21229             return;
21230         });
21231         
21232         return r;
21233     }
21234     
21235     
21236 });
21237
21238  
21239 /*
21240  * - LGPL
21241  *
21242  * Tab pane
21243  * 
21244  */
21245 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21246 /**
21247  * @class Roo.bootstrap.TabPane
21248  * @extends Roo.bootstrap.Component
21249  * Bootstrap TabPane class
21250  * @cfg {Boolean} active (false | true) Default false
21251  * @cfg {String} title title of panel
21252
21253  * 
21254  * @constructor
21255  * Create a new TabPane
21256  * @param {Object} config The config object
21257  */
21258
21259 Roo.bootstrap.dash.TabPane = function(config){
21260     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21261     
21262     this.addEvents({
21263         // raw events
21264         /**
21265          * @event activate
21266          * When a pane is activated
21267          * @param {Roo.bootstrap.dash.TabPane} pane
21268          */
21269         "activate" : true
21270          
21271     });
21272 };
21273
21274 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21275     
21276     active : false,
21277     title : '',
21278     
21279     // the tabBox that this is attached to.
21280     tab : false,
21281      
21282     getAutoCreate : function() 
21283     {
21284         var cfg = {
21285             tag: 'div',
21286             cls: 'tab-pane'
21287         }
21288         
21289         if(this.active){
21290             cfg.cls += ' active';
21291         }
21292         
21293         return cfg;
21294     },
21295     initEvents  : function()
21296     {
21297         //Roo.log('trigger add pane handler');
21298         this.parent().fireEvent('addpane', this)
21299     },
21300     
21301      /**
21302      * Updates the tab title 
21303      * @param {String} html to set the title to.
21304      */
21305     setTitle: function(str)
21306     {
21307         if (!this.tab) {
21308             return;
21309         }
21310         this.title = str;
21311         this.tab.select('a', true).first().dom.innerHTML = str;
21312         
21313     }
21314     
21315     
21316     
21317 });
21318
21319  
21320
21321
21322  /*
21323  * - LGPL
21324  *
21325  * menu
21326  * 
21327  */
21328 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21329
21330 /**
21331  * @class Roo.bootstrap.menu.Menu
21332  * @extends Roo.bootstrap.Component
21333  * Bootstrap Menu class - container for Menu
21334  * @cfg {String} html Text of the menu
21335  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21336  * @cfg {String} icon Font awesome icon
21337  * @cfg {String} pos Menu align to (top | bottom) default bottom
21338  * 
21339  * 
21340  * @constructor
21341  * Create a new Menu
21342  * @param {Object} config The config object
21343  */
21344
21345
21346 Roo.bootstrap.menu.Menu = function(config){
21347     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21348     
21349     this.addEvents({
21350         /**
21351          * @event beforeshow
21352          * Fires before this menu is displayed
21353          * @param {Roo.bootstrap.menu.Menu} this
21354          */
21355         beforeshow : true,
21356         /**
21357          * @event beforehide
21358          * Fires before this menu is hidden
21359          * @param {Roo.bootstrap.menu.Menu} this
21360          */
21361         beforehide : true,
21362         /**
21363          * @event show
21364          * Fires after this menu is displayed
21365          * @param {Roo.bootstrap.menu.Menu} this
21366          */
21367         show : true,
21368         /**
21369          * @event hide
21370          * Fires after this menu is hidden
21371          * @param {Roo.bootstrap.menu.Menu} this
21372          */
21373         hide : true,
21374         /**
21375          * @event click
21376          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21377          * @param {Roo.bootstrap.menu.Menu} this
21378          * @param {Roo.EventObject} e
21379          */
21380         click : true
21381     });
21382     
21383 };
21384
21385 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21386     
21387     submenu : false,
21388     html : '',
21389     weight : 'default',
21390     icon : false,
21391     pos : 'bottom',
21392     
21393     
21394     getChildContainer : function() {
21395         if(this.isSubMenu){
21396             return this.el;
21397         }
21398         
21399         return this.el.select('ul.dropdown-menu', true).first();  
21400     },
21401     
21402     getAutoCreate : function()
21403     {
21404         var text = [
21405             {
21406                 tag : 'span',
21407                 cls : 'roo-menu-text',
21408                 html : this.html
21409             }
21410         ];
21411         
21412         if(this.icon){
21413             text.unshift({
21414                 tag : 'i',
21415                 cls : 'fa ' + this.icon
21416             })
21417         }
21418         
21419         
21420         var cfg = {
21421             tag : 'div',
21422             cls : 'btn-group',
21423             cn : [
21424                 {
21425                     tag : 'button',
21426                     cls : 'dropdown-button btn btn-' + this.weight,
21427                     cn : text
21428                 },
21429                 {
21430                     tag : 'button',
21431                     cls : 'dropdown-toggle btn btn-' + this.weight,
21432                     cn : [
21433                         {
21434                             tag : 'span',
21435                             cls : 'caret'
21436                         }
21437                     ]
21438                 },
21439                 {
21440                     tag : 'ul',
21441                     cls : 'dropdown-menu'
21442                 }
21443             ]
21444             
21445         };
21446         
21447         if(this.pos == 'top'){
21448             cfg.cls += ' dropup';
21449         }
21450         
21451         if(this.isSubMenu){
21452             cfg = {
21453                 tag : 'ul',
21454                 cls : 'dropdown-menu'
21455             }
21456         }
21457         
21458         return cfg;
21459     },
21460     
21461     onRender : function(ct, position)
21462     {
21463         this.isSubMenu = ct.hasClass('dropdown-submenu');
21464         
21465         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21466     },
21467     
21468     initEvents : function() 
21469     {
21470         if(this.isSubMenu){
21471             return;
21472         }
21473         
21474         this.hidden = true;
21475         
21476         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21477         this.triggerEl.on('click', this.onTriggerPress, this);
21478         
21479         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21480         this.buttonEl.on('click', this.onClick, this);
21481         
21482     },
21483     
21484     list : function()
21485     {
21486         if(this.isSubMenu){
21487             return this.el;
21488         }
21489         
21490         return this.el.select('ul.dropdown-menu', true).first();
21491     },
21492     
21493     onClick : function(e)
21494     {
21495         this.fireEvent("click", this, e);
21496     },
21497     
21498     onTriggerPress  : function(e)
21499     {   
21500         if (this.isVisible()) {
21501             this.hide();
21502         } else {
21503             this.show();
21504         }
21505     },
21506     
21507     isVisible : function(){
21508         return !this.hidden;
21509     },
21510     
21511     show : function()
21512     {
21513         this.fireEvent("beforeshow", this);
21514         
21515         this.hidden = false;
21516         this.el.addClass('open');
21517         
21518         Roo.get(document).on("mouseup", this.onMouseUp, this);
21519         
21520         this.fireEvent("show", this);
21521         
21522         
21523     },
21524     
21525     hide : function()
21526     {
21527         this.fireEvent("beforehide", this);
21528         
21529         this.hidden = true;
21530         this.el.removeClass('open');
21531         
21532         Roo.get(document).un("mouseup", this.onMouseUp);
21533         
21534         this.fireEvent("hide", this);
21535     },
21536     
21537     onMouseUp : function()
21538     {
21539         this.hide();
21540     }
21541     
21542 });
21543
21544  
21545  /*
21546  * - LGPL
21547  *
21548  * menu item
21549  * 
21550  */
21551 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21552
21553 /**
21554  * @class Roo.bootstrap.menu.Item
21555  * @extends Roo.bootstrap.Component
21556  * Bootstrap MenuItem class
21557  * @cfg {Boolean} submenu (true | false) default false
21558  * @cfg {String} html text of the item
21559  * @cfg {String} href the link
21560  * @cfg {Boolean} disable (true | false) default false
21561  * @cfg {Boolean} preventDefault (true | false) default true
21562  * @cfg {String} icon Font awesome icon
21563  * @cfg {String} pos Submenu align to (left | right) default right 
21564  * 
21565  * 
21566  * @constructor
21567  * Create a new Item
21568  * @param {Object} config The config object
21569  */
21570
21571
21572 Roo.bootstrap.menu.Item = function(config){
21573     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21574     this.addEvents({
21575         /**
21576          * @event mouseover
21577          * Fires when the mouse is hovering over this menu
21578          * @param {Roo.bootstrap.menu.Item} this
21579          * @param {Roo.EventObject} e
21580          */
21581         mouseover : true,
21582         /**
21583          * @event mouseout
21584          * Fires when the mouse exits this menu
21585          * @param {Roo.bootstrap.menu.Item} this
21586          * @param {Roo.EventObject} e
21587          */
21588         mouseout : true,
21589         // raw events
21590         /**
21591          * @event click
21592          * The raw click event for the entire grid.
21593          * @param {Roo.EventObject} e
21594          */
21595         click : true
21596     });
21597 };
21598
21599 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21600     
21601     submenu : false,
21602     href : '',
21603     html : '',
21604     preventDefault: true,
21605     disable : false,
21606     icon : false,
21607     pos : 'right',
21608     
21609     getAutoCreate : function()
21610     {
21611         var text = [
21612             {
21613                 tag : 'span',
21614                 cls : 'roo-menu-item-text',
21615                 html : this.html
21616             }
21617         ];
21618         
21619         if(this.icon){
21620             text.unshift({
21621                 tag : 'i',
21622                 cls : 'fa ' + this.icon
21623             })
21624         }
21625         
21626         var cfg = {
21627             tag : 'li',
21628             cn : [
21629                 {
21630                     tag : 'a',
21631                     href : this.href || '#',
21632                     cn : text
21633                 }
21634             ]
21635         };
21636         
21637         if(this.disable){
21638             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21639         }
21640         
21641         if(this.submenu){
21642             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21643             
21644             if(this.pos == 'left'){
21645                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21646             }
21647         }
21648         
21649         return cfg;
21650     },
21651     
21652     initEvents : function() 
21653     {
21654         this.el.on('mouseover', this.onMouseOver, this);
21655         this.el.on('mouseout', this.onMouseOut, this);
21656         
21657         this.el.select('a', true).first().on('click', this.onClick, this);
21658         
21659     },
21660     
21661     onClick : function(e)
21662     {
21663         if(this.preventDefault){
21664             e.preventDefault();
21665         }
21666         
21667         this.fireEvent("click", this, e);
21668     },
21669     
21670     onMouseOver : function(e)
21671     {
21672         if(this.submenu && this.pos == 'left'){
21673             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21674         }
21675         
21676         this.fireEvent("mouseover", this, e);
21677     },
21678     
21679     onMouseOut : function(e)
21680     {
21681         this.fireEvent("mouseout", this, e);
21682     }
21683 });
21684
21685  
21686
21687  /*
21688  * - LGPL
21689  *
21690  * menu separator
21691  * 
21692  */
21693 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21694
21695 /**
21696  * @class Roo.bootstrap.menu.Separator
21697  * @extends Roo.bootstrap.Component
21698  * Bootstrap Separator class
21699  * 
21700  * @constructor
21701  * Create a new Separator
21702  * @param {Object} config The config object
21703  */
21704
21705
21706 Roo.bootstrap.menu.Separator = function(config){
21707     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21708 };
21709
21710 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21711     
21712     getAutoCreate : function(){
21713         var cfg = {
21714             tag : 'li',
21715             cls: 'divider'
21716         };
21717         
21718         return cfg;
21719     }
21720    
21721 });
21722
21723  
21724
21725  /*
21726  * - LGPL
21727  *
21728  * Tooltip
21729  * 
21730  */
21731
21732 /**
21733  * @class Roo.bootstrap.Tooltip
21734  * Bootstrap Tooltip class
21735  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21736  * to determine which dom element triggers the tooltip.
21737  * 
21738  * It needs to add support for additional attributes like tooltip-position
21739  * 
21740  * @constructor
21741  * Create a new Toolti
21742  * @param {Object} config The config object
21743  */
21744
21745 Roo.bootstrap.Tooltip = function(config){
21746     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21747 };
21748
21749 Roo.apply(Roo.bootstrap.Tooltip, {
21750     /**
21751      * @function init initialize tooltip monitoring.
21752      * @static
21753      */
21754     currentEl : false,
21755     currentTip : false,
21756     currentRegion : false,
21757     
21758     //  init : delay?
21759     
21760     init : function()
21761     {
21762         Roo.get(document).on('mouseover', this.enter ,this);
21763         Roo.get(document).on('mouseout', this.leave, this);
21764          
21765         
21766         this.currentTip = new Roo.bootstrap.Tooltip();
21767     },
21768     
21769     enter : function(ev)
21770     {
21771         var dom = ev.getTarget();
21772         
21773         //Roo.log(['enter',dom]);
21774         var el = Roo.fly(dom);
21775         if (this.currentEl) {
21776             //Roo.log(dom);
21777             //Roo.log(this.currentEl);
21778             //Roo.log(this.currentEl.contains(dom));
21779             if (this.currentEl == el) {
21780                 return;
21781             }
21782             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21783                 return;
21784             }
21785
21786         }
21787         
21788         
21789         
21790         if (this.currentTip.el) {
21791             this.currentTip.el.hide(); // force hiding...
21792         }    
21793         //Roo.log(ev);
21794         var bindEl = el;
21795         
21796         // you can not look for children, as if el is the body.. then everythign is the child..
21797         if (!el.attr('tooltip')) { //
21798             if (!el.select("[tooltip]").elements.length) {
21799                 return;
21800             }
21801             // is the mouse over this child...?
21802             bindEl = el.select("[tooltip]").first();
21803             var xy = ev.getXY();
21804             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21805                 //Roo.log("not in region.");
21806                 return;
21807             }
21808             //Roo.log("child element over..");
21809             
21810         }
21811         this.currentEl = bindEl;
21812         this.currentTip.bind(bindEl);
21813         this.currentRegion = Roo.lib.Region.getRegion(dom);
21814         this.currentTip.enter();
21815         
21816     },
21817     leave : function(ev)
21818     {
21819         var dom = ev.getTarget();
21820         //Roo.log(['leave',dom]);
21821         if (!this.currentEl) {
21822             return;
21823         }
21824         
21825         
21826         if (dom != this.currentEl.dom) {
21827             return;
21828         }
21829         var xy = ev.getXY();
21830         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21831             return;
21832         }
21833         // only activate leave if mouse cursor is outside... bounding box..
21834         
21835         
21836         
21837         
21838         if (this.currentTip) {
21839             this.currentTip.leave();
21840         }
21841         //Roo.log('clear currentEl');
21842         this.currentEl = false;
21843         
21844         
21845     },
21846     alignment : {
21847         'left' : ['r-l', [-2,0], 'right'],
21848         'right' : ['l-r', [2,0], 'left'],
21849         'bottom' : ['t-b', [0,2], 'top'],
21850         'top' : [ 'b-t', [0,-2], 'bottom']
21851     }
21852     
21853 });
21854
21855
21856 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21857     
21858     
21859     bindEl : false,
21860     
21861     delay : null, // can be { show : 300 , hide: 500}
21862     
21863     timeout : null,
21864     
21865     hoverState : null, //???
21866     
21867     placement : 'bottom', 
21868     
21869     getAutoCreate : function(){
21870     
21871         var cfg = {
21872            cls : 'tooltip',
21873            role : 'tooltip',
21874            cn : [
21875                 {
21876                     cls : 'tooltip-arrow'
21877                 },
21878                 {
21879                     cls : 'tooltip-inner'
21880                 }
21881            ]
21882         };
21883         
21884         return cfg;
21885     },
21886     bind : function(el)
21887     {
21888         this.bindEl = el;
21889     },
21890       
21891     
21892     enter : function () {
21893        
21894         if (this.timeout != null) {
21895             clearTimeout(this.timeout);
21896         }
21897         
21898         this.hoverState = 'in';
21899          //Roo.log("enter - show");
21900         if (!this.delay || !this.delay.show) {
21901             this.show();
21902             return;
21903         }
21904         var _t = this;
21905         this.timeout = setTimeout(function () {
21906             if (_t.hoverState == 'in') {
21907                 _t.show();
21908             }
21909         }, this.delay.show);
21910     },
21911     leave : function()
21912     {
21913         clearTimeout(this.timeout);
21914     
21915         this.hoverState = 'out';
21916          if (!this.delay || !this.delay.hide) {
21917             this.hide();
21918             return;
21919         }
21920        
21921         var _t = this;
21922         this.timeout = setTimeout(function () {
21923             //Roo.log("leave - timeout");
21924             
21925             if (_t.hoverState == 'out') {
21926                 _t.hide();
21927                 Roo.bootstrap.Tooltip.currentEl = false;
21928             }
21929         }, delay);
21930     },
21931     
21932     show : function ()
21933     {
21934         if (!this.el) {
21935             this.render(document.body);
21936         }
21937         // set content.
21938         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21939         
21940         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
21941         
21942         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip
21943         
21944         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21945         
21946         var placement = typeof this.placement == 'function' ?
21947             this.placement.call(this, this.el, on_el) :
21948             this.placement;
21949             
21950         var autoToken = /\s?auto?\s?/i;
21951         var autoPlace = autoToken.test(placement);
21952         if (autoPlace) {
21953             placement = placement.replace(autoToken, '') || 'top';
21954         }
21955         
21956         //this.el.detach()
21957         //this.el.setXY([0,0]);
21958         this.el.show();
21959         //this.el.dom.style.display='block';
21960         this.el.addClass(placement);
21961         
21962         //this.el.appendTo(on_el);
21963         
21964         var p = this.getPosition();
21965         var box = this.el.getBox();
21966         
21967         if (autoPlace) {
21968             // fixme..
21969         }
21970         var align = Roo.bootstrap.Tooltip.alignment[placement];
21971         this.el.alignTo(this.bindEl, align[0],align[1]);
21972         //var arrow = this.el.select('.arrow',true).first();
21973         //arrow.set(align[2], 
21974         
21975         this.el.addClass('in fade');
21976         this.hoverState = null;
21977         
21978         if (this.el.hasClass('fade')) {
21979             // fade it?
21980         }
21981         
21982     },
21983     hide : function()
21984     {
21985          
21986         if (!this.el) {
21987             return;
21988         }
21989         //this.el.setXY([0,0]);
21990         this.el.removeClass('in');
21991         //this.el.hide();
21992         
21993     }
21994     
21995 });
21996  
21997
21998  /*
21999  * - LGPL
22000  *
22001  * Location Picker
22002  * 
22003  */
22004
22005 /**
22006  * @class Roo.bootstrap.LocationPicker
22007  * @extends Roo.bootstrap.Component
22008  * Bootstrap LocationPicker class
22009  * @cfg {Number} latitude Position when init default 0
22010  * @cfg {Number} longitude Position when init default 0
22011  * @cfg {Number} zoom default 15
22012  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22013  * @cfg {Boolean} mapTypeControl default false
22014  * @cfg {Boolean} disableDoubleClickZoom default false
22015  * @cfg {Boolean} scrollwheel default true
22016  * @cfg {Boolean} streetViewControl default false
22017  * @cfg {Number} radius default 0
22018  * @cfg {String} locationName
22019  * @cfg {Boolean} draggable default true
22020  * @cfg {Boolean} enableAutocomplete default false
22021  * @cfg {Boolean} enableReverseGeocode default true
22022  * @cfg {String} markerTitle
22023  * 
22024  * @constructor
22025  * Create a new LocationPicker
22026  * @param {Object} config The config object
22027  */
22028
22029
22030 Roo.bootstrap.LocationPicker = function(config){
22031     
22032     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22033     
22034     this.addEvents({
22035         /**
22036          * @event initial
22037          * Fires when the picker initialized.
22038          * @param {Roo.bootstrap.LocationPicker} this
22039          * @param {Google Location} location
22040          */
22041         initial : true,
22042         /**
22043          * @event positionchanged
22044          * Fires when the picker position changed.
22045          * @param {Roo.bootstrap.LocationPicker} this
22046          * @param {Google Location} location
22047          */
22048         positionchanged : true,
22049         /**
22050          * @event resize
22051          * Fires when the map resize.
22052          * @param {Roo.bootstrap.LocationPicker} this
22053          */
22054         resize : true,
22055         /**
22056          * @event show
22057          * Fires when the map show.
22058          * @param {Roo.bootstrap.LocationPicker} this
22059          */
22060         show : true,
22061         /**
22062          * @event hide
22063          * Fires when the map hide.
22064          * @param {Roo.bootstrap.LocationPicker} this
22065          */
22066         hide : true,
22067         /**
22068          * @event mapClick
22069          * Fires when click the map.
22070          * @param {Roo.bootstrap.LocationPicker} this
22071          * @param {Map event} e
22072          */
22073         mapClick : true,
22074         /**
22075          * @event mapRightClick
22076          * Fires when right click the map.
22077          * @param {Roo.bootstrap.LocationPicker} this
22078          * @param {Map event} e
22079          */
22080         mapRightClick : true,
22081         /**
22082          * @event markerClick
22083          * Fires when click the marker.
22084          * @param {Roo.bootstrap.LocationPicker} this
22085          * @param {Map event} e
22086          */
22087         markerClick : true,
22088         /**
22089          * @event markerRightClick
22090          * Fires when right click the marker.
22091          * @param {Roo.bootstrap.LocationPicker} this
22092          * @param {Map event} e
22093          */
22094         markerRightClick : true,
22095         /**
22096          * @event OverlayViewDraw
22097          * Fires when OverlayView Draw
22098          * @param {Roo.bootstrap.LocationPicker} this
22099          */
22100         OverlayViewDraw : true,
22101         /**
22102          * @event OverlayViewOnAdd
22103          * Fires when OverlayView Draw
22104          * @param {Roo.bootstrap.LocationPicker} this
22105          */
22106         OverlayViewOnAdd : true,
22107         /**
22108          * @event OverlayViewOnRemove
22109          * Fires when OverlayView Draw
22110          * @param {Roo.bootstrap.LocationPicker} this
22111          */
22112         OverlayViewOnRemove : true,
22113         /**
22114          * @event OverlayViewShow
22115          * Fires when OverlayView Draw
22116          * @param {Roo.bootstrap.LocationPicker} this
22117          * @param {Pixel} cpx
22118          */
22119         OverlayViewShow : true,
22120         /**
22121          * @event OverlayViewHide
22122          * Fires when OverlayView Draw
22123          * @param {Roo.bootstrap.LocationPicker} this
22124          */
22125         OverlayViewHide : true
22126     });
22127         
22128 };
22129
22130 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22131     
22132     gMapContext: false,
22133     
22134     latitude: 0,
22135     longitude: 0,
22136     zoom: 15,
22137     mapTypeId: false,
22138     mapTypeControl: false,
22139     disableDoubleClickZoom: false,
22140     scrollwheel: true,
22141     streetViewControl: false,
22142     radius: 0,
22143     locationName: '',
22144     draggable: true,
22145     enableAutocomplete: false,
22146     enableReverseGeocode: true,
22147     markerTitle: '',
22148     
22149     getAutoCreate: function()
22150     {
22151
22152         var cfg = {
22153             tag: 'div',
22154             cls: 'roo-location-picker'
22155         };
22156         
22157         return cfg
22158     },
22159     
22160     initEvents: function(ct, position)
22161     {       
22162         if(!this.el.getWidth() || this.isApplied()){
22163             return;
22164         }
22165         
22166         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22167         
22168         this.initial();
22169     },
22170     
22171     initial: function()
22172     {
22173         if(!this.mapTypeId){
22174             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22175         }
22176         
22177         this.gMapContext = this.GMapContext();
22178         
22179         this.initOverlayView();
22180         
22181         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22182         
22183         var _this = this;
22184                 
22185         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22186             _this.setPosition(_this.gMapContext.marker.position);
22187         });
22188         
22189         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22190             _this.fireEvent('mapClick', this, event);
22191             
22192         });
22193
22194         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22195             _this.fireEvent('mapRightClick', this, event);
22196             
22197         });
22198         
22199         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22200             _this.fireEvent('markerClick', this, event);
22201             
22202         });
22203
22204         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22205             _this.fireEvent('markerRightClick', this, event);
22206             
22207         });
22208         
22209         this.setPosition(this.gMapContext.location);
22210         
22211         this.fireEvent('initial', this, this.gMapContext.location);
22212     },
22213     
22214     initOverlayView: function()
22215     {
22216         var _this = this;
22217         
22218         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22219             
22220             draw: function()
22221             {
22222                 _this.fireEvent('OverlayViewDraw', _this);
22223             },
22224             
22225             onAdd: function()
22226             {
22227                 _this.fireEvent('OverlayViewOnAdd', _this);
22228             },
22229             
22230             onRemove: function()
22231             {
22232                 _this.fireEvent('OverlayViewOnRemove', _this);
22233             },
22234             
22235             show: function(cpx)
22236             {
22237                 _this.fireEvent('OverlayViewShow', _this, cpx);
22238             },
22239             
22240             hide: function()
22241             {
22242                 _this.fireEvent('OverlayViewHide', _this);
22243             }
22244             
22245         });
22246     },
22247     
22248     fromLatLngToContainerPixel: function(event)
22249     {
22250         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22251     },
22252     
22253     isApplied: function() 
22254     {
22255         return this.getGmapContext() == false ? false : true;
22256     },
22257     
22258     getGmapContext: function() 
22259     {
22260         return this.gMapContext
22261     },
22262     
22263     GMapContext: function() 
22264     {
22265         var position = new google.maps.LatLng(this.latitude, this.longitude);
22266         
22267         var _map = new google.maps.Map(this.el.dom, {
22268             center: position,
22269             zoom: this.zoom,
22270             mapTypeId: this.mapTypeId,
22271             mapTypeControl: this.mapTypeControl,
22272             disableDoubleClickZoom: this.disableDoubleClickZoom,
22273             scrollwheel: this.scrollwheel,
22274             streetViewControl: this.streetViewControl,
22275             locationName: this.locationName,
22276             draggable: this.draggable,
22277             enableAutocomplete: this.enableAutocomplete,
22278             enableReverseGeocode: this.enableReverseGeocode
22279         });
22280         
22281         var _marker = new google.maps.Marker({
22282             position: position,
22283             map: _map,
22284             title: this.markerTitle,
22285             draggable: this.draggable
22286         });
22287         
22288         return {
22289             map: _map,
22290             marker: _marker,
22291             circle: null,
22292             location: position,
22293             radius: this.radius,
22294             locationName: this.locationName,
22295             addressComponents: {
22296                 formatted_address: null,
22297                 addressLine1: null,
22298                 addressLine2: null,
22299                 streetName: null,
22300                 streetNumber: null,
22301                 city: null,
22302                 district: null,
22303                 state: null,
22304                 stateOrProvince: null
22305             },
22306             settings: this,
22307             domContainer: this.el.dom,
22308             geodecoder: new google.maps.Geocoder()
22309         };
22310     },
22311     
22312     drawCircle: function(center, radius, options) 
22313     {
22314         if (this.gMapContext.circle != null) {
22315             this.gMapContext.circle.setMap(null);
22316         }
22317         if (radius > 0) {
22318             radius *= 1;
22319             options = Roo.apply({}, options, {
22320                 strokeColor: "#0000FF",
22321                 strokeOpacity: .35,
22322                 strokeWeight: 2,
22323                 fillColor: "#0000FF",
22324                 fillOpacity: .2
22325             });
22326             
22327             options.map = this.gMapContext.map;
22328             options.radius = radius;
22329             options.center = center;
22330             this.gMapContext.circle = new google.maps.Circle(options);
22331             return this.gMapContext.circle;
22332         }
22333         
22334         return null;
22335     },
22336     
22337     setPosition: function(location) 
22338     {
22339         this.gMapContext.location = location;
22340         this.gMapContext.marker.setPosition(location);
22341         this.gMapContext.map.panTo(location);
22342         this.drawCircle(location, this.gMapContext.radius, {});
22343         
22344         var _this = this;
22345         
22346         if (this.gMapContext.settings.enableReverseGeocode) {
22347             this.gMapContext.geodecoder.geocode({
22348                 latLng: this.gMapContext.location
22349             }, function(results, status) {
22350                 
22351                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22352                     _this.gMapContext.locationName = results[0].formatted_address;
22353                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22354                     
22355                     _this.fireEvent('positionchanged', this, location);
22356                 }
22357             });
22358             
22359             return;
22360         }
22361         
22362         this.fireEvent('positionchanged', this, location);
22363     },
22364     
22365     resize: function()
22366     {
22367         google.maps.event.trigger(this.gMapContext.map, "resize");
22368         
22369         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22370         
22371         this.fireEvent('resize', this);
22372     },
22373     
22374     setPositionByLatLng: function(latitude, longitude)
22375     {
22376         this.setPosition(new google.maps.LatLng(latitude, longitude));
22377     },
22378     
22379     getCurrentPosition: function() 
22380     {
22381         return {
22382             latitude: this.gMapContext.location.lat(),
22383             longitude: this.gMapContext.location.lng()
22384         };
22385     },
22386     
22387     getAddressName: function() 
22388     {
22389         return this.gMapContext.locationName;
22390     },
22391     
22392     getAddressComponents: function() 
22393     {
22394         return this.gMapContext.addressComponents;
22395     },
22396     
22397     address_component_from_google_geocode: function(address_components) 
22398     {
22399         var result = {};
22400         
22401         for (var i = 0; i < address_components.length; i++) {
22402             var component = address_components[i];
22403             if (component.types.indexOf("postal_code") >= 0) {
22404                 result.postalCode = component.short_name;
22405             } else if (component.types.indexOf("street_number") >= 0) {
22406                 result.streetNumber = component.short_name;
22407             } else if (component.types.indexOf("route") >= 0) {
22408                 result.streetName = component.short_name;
22409             } else if (component.types.indexOf("neighborhood") >= 0) {
22410                 result.city = component.short_name;
22411             } else if (component.types.indexOf("locality") >= 0) {
22412                 result.city = component.short_name;
22413             } else if (component.types.indexOf("sublocality") >= 0) {
22414                 result.district = component.short_name;
22415             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22416                 result.stateOrProvince = component.short_name;
22417             } else if (component.types.indexOf("country") >= 0) {
22418                 result.country = component.short_name;
22419             }
22420         }
22421         
22422         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22423         result.addressLine2 = "";
22424         return result;
22425     },
22426     
22427     setZoomLevel: function(zoom)
22428     {
22429         this.gMapContext.map.setZoom(zoom);
22430     },
22431     
22432     show: function()
22433     {
22434         if(!this.el){
22435             return;
22436         }
22437         
22438         this.el.show();
22439         
22440         this.resize();
22441         
22442         this.fireEvent('show', this);
22443     },
22444     
22445     hide: function()
22446     {
22447         if(!this.el){
22448             return;
22449         }
22450         
22451         this.el.hide();
22452         
22453         this.fireEvent('hide', this);
22454     }
22455     
22456 });
22457
22458 Roo.apply(Roo.bootstrap.LocationPicker, {
22459     
22460     OverlayView : function(map, options)
22461     {
22462         options = options || {};
22463         
22464         this.setMap(map);
22465     }
22466     
22467     
22468 });/*
22469  * - LGPL
22470  *
22471  * Alert
22472  * 
22473  */
22474
22475 /**
22476  * @class Roo.bootstrap.Alert
22477  * @extends Roo.bootstrap.Component
22478  * Bootstrap Alert class
22479  * @cfg {String} title The title of alert
22480  * @cfg {String} html The content of alert
22481  * @cfg {String} weight (  success | info | warning | danger )
22482  * @cfg {String} faicon font-awesomeicon
22483  * 
22484  * @constructor
22485  * Create a new alert
22486  * @param {Object} config The config object
22487  */
22488
22489
22490 Roo.bootstrap.Alert = function(config){
22491     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22492     
22493 };
22494
22495 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22496     
22497     title: '',
22498     html: '',
22499     weight: false,
22500     faicon: false,
22501     
22502     getAutoCreate : function()
22503     {
22504         
22505         var cfg = {
22506             tag : 'div',
22507             cls : 'alert',
22508             cn : [
22509                 {
22510                     tag : 'i',
22511                     cls : 'roo-alert-icon'
22512                     
22513                 },
22514                 {
22515                     tag : 'b',
22516                     cls : 'roo-alert-title',
22517                     html : this.title
22518                 },
22519                 {
22520                     tag : 'span',
22521                     cls : 'roo-alert-text',
22522                     html : this.html
22523                 }
22524             ]
22525         };
22526         
22527         if(this.faicon){
22528             cfg.cn[0].cls += ' fa ' + this.faicon;
22529         }
22530         
22531         if(this.weight){
22532             cfg.cls += ' alert-' + this.weight;
22533         }
22534         
22535         return cfg;
22536     },
22537     
22538     initEvents: function() 
22539     {
22540         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22541     },
22542     
22543     setTitle : function(str)
22544     {
22545         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22546     },
22547     
22548     setText : function(str)
22549     {
22550         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22551     },
22552     
22553     setWeight : function(weight)
22554     {
22555         if(this.weight){
22556             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22557         }
22558         
22559         this.weight = weight;
22560         
22561         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22562     },
22563     
22564     setIcon : function(icon)
22565     {
22566         if(this.faicon){
22567             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22568         }
22569         
22570         this.faicon = icon
22571         
22572         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22573     },
22574     
22575     hide: function() 
22576     {
22577         this.el.hide();   
22578     },
22579     
22580     show: function() 
22581     {  
22582         this.el.show();   
22583     }
22584     
22585 });
22586
22587