roojs-ui.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  
17  * 
18  * @constructor
19  * Do not use directly - it does not do anything..
20  * @param {Object} config The config object
21  */
22
23
24
25 Roo.bootstrap.Component = function(config){
26     Roo.bootstrap.Component.superclass.constructor.call(this, config);
27 };
28
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
30     
31     
32     allowDomMove : false, // to stop relocations in parent onRender...
33     
34     cls : false,
35     
36     style : false,
37     
38     autoCreate : false,
39     
40     initEvents : function() {  },
41     
42     xattr : false,
43     
44     parentId : false,
45     
46     parent: function() {
47         // returns the parent component..
48         return Roo.ComponentMgr.get(this.parentId)
49         
50         
51     },
52     
53     // private
54     onRender : function(ct, position)
55     {
56        // Roo.log("Call onRender: " + this.xtype);
57         
58         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
59         
60         if(this.el){
61             if (this.el.attr('xtype')) {
62                 this.el.dom.removeAttribute('xtype');
63                 this.initEvents();
64             }
65             
66             return;
67         }
68         
69          
70         
71         var cfg = Roo.apply({},  this.getAutoCreate());
72         cfg.id = Roo.id();
73         
74         // fill in the extra attributes 
75         if (this.xattr && typeof(this.xattr) =='object') {
76             for (var i in this.xattr) {
77                 cfg[i] = this.xattr[i];
78             }
79         }
80         
81         if (this.cls) {
82             cfg.cls += ' ' + this.cls;
83         }
84         if (this.style) { // fixme needs to support more complex style data.
85             cfg.style = this.style;
86         }
87         this.el = ct.createChild(cfg, position);
88         if(this.tabIndex !== undefined){
89             this.el.dom.setAttribute('tabIndex', this.tabIndex);
90         }
91         this.initEvents();
92         
93         
94     },
95     
96     getChildContainer : function()
97     {
98         return this.el;
99     },
100     
101     addxtype : function (tree, cntr) {
102         var cn = this;
103         cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
104         
105         // render the element if it's not BODY.
106         if (tree.xtype != 'Body') {
107             
108             cn = Roo.factory(tree);
109            // Roo.log(cn);
110             cn.parentType = this.xtype; //??
111             cn.parentId = this.id;
112             
113             // does the container contain child eleemnts with 'xtype' attributes.
114             // that match this xtype..
115             // note - when we render we create these as well..
116             // so we should check to see if body has xtype set.
117             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
118             
119                 var echild = Roo.get(this[cntr]()).child('*[xtype]');
120                 if (echild) {
121                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
122                     cn.el = echild;
123                     //echild.dom.removeAttribute('xtype');
124                 } else {
125                     Roo.log("missing child for " + this.xtype);
126                 }
127             }
128             cn.render(this[cntr]());
129             // then add the element..
130         }
131         
132         
133         // handle the kids..
134         
135         var nitems = [];
136         if (typeof (tree.menu) != 'undefined') {
137             tree.menu.parentType = cn.xtype;
138             tree.menu.triggerEl = cn.el;
139             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
140             
141         }
142         
143         if (!tree.items || !tree.items.length) {
144             cn.items = nitems;
145             return cn;
146         }
147         var items = tree.items;
148         delete tree.items;
149         
150         //Roo.log(items.length);
151             // add the items..
152         for(var i =0;i < items.length;i++) {
153             nitems.push(cn.addxtype(Roo.apply({}, items[i])));
154         }
155         
156         cn.items = nitems;
157         
158         
159         return cn;
160     }
161     
162     
163     
164     
165 });
166
167  /*
168  * - LGPL
169  *
170  * page container.
171  * 
172  */ 
173 Roo.bootstrap.Body = function(config){
174     Roo.bootstrap.Body.superclass.constructor.call(this, config);
175     this.el = Roo.get(document.body);
176 };
177
178 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
179       
180         autoCreate : {
181         cls: 'container'
182     },
183     onRender : function(ct, position){
184         
185         
186         //this.el.addClass([this.fieldClass, this.cls]);
187         
188     }
189     
190     
191  
192    
193 });
194
195  /*
196  * - LGPL
197  *
198  * button group
199  * 
200  */
201
202
203 /**
204  * @class Roo.bootstrap.ButtonGroup
205  * @extends Roo.bootstrap.Component
206  * Bootstrap ButtonGroup class
207  * @cfg {String} size lg | sm | xs (default empty normal)
208  * @cfg {String} align vertical | justified  (default none)
209  * @cfg {String} direction up | down (default down)
210  * @cfg {Boolean} toolbar false | true
211  * @cfg {Boolean} btn true | false
212  * 
213  * 
214  * @constructor
215  * Create a new Input
216  * @param {Object} config The config object
217  */
218
219 Roo.bootstrap.ButtonGroup = function(config){
220     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
221 };
222
223 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
224     
225     size: '',
226     align: '',
227     direction: '',
228     toolbar: false,
229     btn: true,
230
231     getAutoCreate : function(){
232         var cfg = {
233             cls: 'btn-group',
234             html : null
235         }
236         
237         cfg.html = this.html || cfg.html;
238         
239         if (this.toolbar) {
240             cfg = {
241                 cls: 'btn-toolbar',
242                 html: null
243             }
244             
245             return cfg;
246         }
247         
248         if (['vertical','justified'].indexOf(this.align)!==-1) {
249             cfg.cls = 'btn-group-' + this.align;
250             
251             if (this.align == 'justified') {
252                 console.log(this.items);
253             }
254         }
255         
256         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
257             cfg.cls += ' btn-group-' + this.size;
258         }
259         
260         if (this.direction == 'up') {
261             cfg.cls += ' dropup' ;
262         }
263         
264         return cfg;
265     }
266    
267 });
268
269  /*
270  * - LGPL
271  *
272  * button
273  * 
274  */
275
276 /**
277  * @class Roo.bootstrap.Button
278  * @extends Roo.bootstrap.Component
279  * Bootstrap Button class
280  * @cfg {String} html The button content
281  * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
282  * @cfg {String} size empty | lg | sm | xs
283  * @cfg {String} tag empty | a | input | submit
284  * @cfg {String} href empty or href
285  * @cfg {Boolean} disabled false | true
286  * @cfg {Boolean} isClose false | true
287  * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
288  * @cfg {String} badge text for badge
289  * @cfg {String} theme default (or empty) | glow
290  * @cfg {Boolean} inverse false | true
291  * @cfg {Boolean} toggle false | true
292  * @cfg {String} ontext text for on toggle state
293  * @cfg {String} offtext text for off toggle state
294  * @cfg {Boolean} defaulton true | false
295  * 
296  * @constructor
297  * Create a new button
298  * @param {Object} config The config object
299  */
300
301
302 Roo.bootstrap.Button = function(config){
303     Roo.bootstrap.Button.superclass.constructor.call(this, config);
304     this.addEvents({
305         // raw events
306         /**
307          * @event click
308          * The raw click event for the entire grid.
309          * @param {Roo.EventObject} e
310          */
311         "click" : true
312     });
313 };
314
315 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
316     html: false,
317     active: false,
318     weight: '',
319     size: '',
320     tag: 'button',
321     href: '',
322     disabled: false,
323     isClose: false,
324     glyphicon: '',
325     badge: '',
326     theme: 'default',
327     inverse: false,
328     
329     toggle: false,
330     ontext: 'ON',
331     offtext: 'OFF',
332     defaulton: true,
333     
334     getAutoCreate : function(){
335         
336         var cfg = {
337             tag : 'button',
338             cls : 'roo-button',
339             html: 'hello'
340         };
341         
342         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
343             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
344             this.tag = 'button';
345         } else {
346             cfg.tag = this.tag;
347         }
348         cfg.html = this.html || cfg.html;
349         
350         if (this.toggle===true) {
351             cfg={
352                 tag: 'div',
353                 cls: 'slider-frame roo-button',
354                 cn: [
355                     {
356                         tag: 'span',
357                         'data-on-text':'ON',
358                         'data-off-text':'OFF',
359                         cls: 'slider-button',
360                         html: this.offtext
361                     }
362                 ]
363             };
364             
365             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
366                 cfg.cls += ' '+this.weight;
367             }
368             
369             return cfg;
370         }
371         
372         if (this.isClose) {
373             cfg.cls += ' close';
374             
375             cfg["aria-hidden"] = true;
376             
377             cfg.html = "&times;";
378             
379             return cfg;
380         }
381         
382          
383         if (this.theme==='default') {
384             cfg.cls = 'btn roo-button';
385             
386             if (this.parentType != 'Navbar') {
387                 this.weight = this.weight.length ?  this.weight : 'default';
388             }
389             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
390                 
391                 cfg.cls += ' btn-' + this.weight;
392             }
393         } else if (this.theme==='glow') {
394             
395             cfg.tag = 'a';
396             cfg.cls = 'btn-glow roo-button';
397             
398             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
399                 
400                 cfg.cls += ' ' + this.weight;
401             }
402         }
403    
404         
405         if (this.inverse) {
406             this.cls += ' inverse';
407         }
408         
409         
410         if (this.active) {
411             cfg.cls += ' active';
412         }
413         
414         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
415          
416         //gsRoo.log(this.parentType);
417         if (this.parentType === 'Navbar') {
418             cfg.tag = 'li';
419             
420             cfg.cls = '';
421             cfg.cn =  [{
422                 tag : 'a',
423                 cls : 'roo-button',
424                 html : this.html,
425                 href : this.href || '#'
426             }];
427             if (this.menu) {
428                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
429                 cfg.cls += ' dropdown';
430             }   
431             
432             delete cfg.html;
433             
434         } else if (this.menu) {
435             cfg.tag = 'a';
436             cfg.cls += ' dropdown test';
437         }
438         
439         
440         
441         if (this.disabled) {
442             cfg.disabled = 'disabled';
443         }
444         //????
445         if (this.items) {
446             Roo.log('changing to ul' );
447             cfg.tag = 'ul';
448             this.glyphicon = 'caret';
449         }
450         
451         if (this.glyphicon) {
452             cfg.html = ' ' + cfg.html;
453             
454             cfg.cn = [
455                 {
456                     tag: 'span',
457                     cls: 'glyphicon glyphicon-' + this.glyphicon
458                 }
459             ];
460         }
461         
462         if (this.badge) {
463             cfg.html += ' ';
464             
465             cfg.tag = 'a';
466             
467             cfg.cls='btn roo-button';
468             
469             cfg.href=this.href;
470             
471             cfg.cn = [
472                 cfg.html,
473                 {
474                     tag: 'span',
475                     cls: 'badge',
476                     html: this.badge
477                 }
478             ];
479             
480             cfg.html='';
481         }
482         
483         if (cfg.tag !== 'a' && this.href !== '') {
484             throw "Tag must be a to set href.";
485         } else if (this.href.length > 0) {
486             cfg.href = this.href;
487         }
488         
489         return cfg;
490     },
491     initEvents: function() {
492        // Roo.log('init events?');
493        // Roo.log(this.el.dom);
494        if (this.el.hasClass('roo-button')) {
495             this.el.on('click', this.onClick, this);
496        } else {
497             this.el.select('.roo-button').on('click', this.onClick, this);
498        }
499        
500        
501         
502     },
503     onClick : function(e)
504     {
505         Roo.log('button on click ');
506         e.preventDefault();
507         this.fireEvent('click', this, e);
508     }
509     
510     
511 });
512
513  /*
514  * - LGPL
515  *
516  * column
517  * 
518  */
519
520 /**
521  * @class Roo.bootstrap.Column
522  * @extends Roo.bootstrap.Component
523  * Bootstrap Column class
524  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
525  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
526  * @cfg {Number} md colspan out of 12 for computer-sized screens
527  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
528  * @cfg {String} html content of column.
529  * 
530  * @constructor
531  * Create a new Column
532  * @param {Object} config The config object
533  */
534
535 Roo.bootstrap.Column = function(config){
536     Roo.bootstrap.Column.superclass.constructor.call(this, config);
537 };
538
539 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
540     
541     xs: null,
542     sm: null,
543     md: null,
544     lg: null,
545     html: '',
546     offset: 0,
547     
548     getAutoCreate : function(){
549         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
550         
551         cfg = {
552             tag: 'div',
553             cls: 'column'
554         };
555         
556         var settings=this;
557         ['xs','sm','md','lg'].map(function(size){
558             if (settings[size]) {
559                 cfg.cls += ' col-' + size + '-' + settings[size];
560             }
561         });
562         if (this.html.length) {
563             cfg.html = this.html;
564         }
565         
566         return cfg;
567     }
568    
569 });
570
571  
572
573  /*
574  * - LGPL
575  *
576  * page container.
577  * 
578  */
579
580
581 /**
582  * @class Roo.bootstrap.Container
583  * @extends Roo.bootstrap.Component
584  * Bootstrap Container class
585  * @cfg {Boolean} jumbotron is it a jumbotron element
586  * @cfg {String} html content of element
587  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
588  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
589  * @cfg {String} header content of header (for panel)
590  * @cfg {String} footer content of footer (for panel)
591  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
592  *     
593  * @constructor
594  * Create a new Container
595  * @param {Object} config The config object
596  */
597
598 Roo.bootstrap.Container = function(config){
599     Roo.bootstrap.Container.superclass.constructor.call(this, config);
600 };
601
602 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
603     
604     jumbotron : false,
605     well: '',
606     panel : '',
607     header: '',
608     footer : '',
609     sticky: '',
610   
611      
612     getChildContainer : function() {
613         if (this.panel.length) {
614             return this.el.select('.panel-body',true).first();
615         }
616         
617         return this.el;
618     },
619     
620     
621     getAutoCreate : function(){
622         
623         var cfg = {
624             html : '',
625             cls : ''
626         };
627         if (this.jumbotron) {
628             cfg.cls = 'jumbotron';
629         }
630         if (this.cls) {
631             cfg.cls = this.cls + '';
632         }
633         
634         if (this.sticky.length) {
635             var bd = Roo.get(document.body);
636             if (!bd.hasClass('bootstrap-sticky')) {
637                 bd.addClass('bootstrap-sticky');
638                 Roo.select('html',true).setStyle('height', '100%');
639             }
640              
641             cfg.cls += 'bootstrap-sticky-' + this.sticky;
642         }
643         
644         
645         if (this.well.length) {
646             switch (this.well) {
647                 case 'lg':
648                 case 'sm':
649                     cfg.cls +=' well well-' +this.well;
650                     break;
651                 default:
652                     cfg.cls +=' well';
653                     break;
654             }
655         }
656         
657         var body = cfg;
658         
659         if (this.panel.length) {
660             cfg.cls += 'panel panel-' + this.panel;
661             cfg.cn = [];
662             if (this.header.length) {
663                 cfg.cn.push({
664                     
665                     cls : 'panel-heading',
666                     cn : [{
667                         tag: 'h3',
668                         cls : 'panel-title',
669                         html : this.header
670                     }]
671                     
672                 });
673             }
674             body = false;
675             cfg.cn.push({
676                 cls : 'panel-body',
677                 html : this.html
678             });
679             
680             
681             if (this.footer.length) {
682                 cfg.cn.push({
683                     cls : 'panel-footer',
684                     html : this.footer
685                     
686                 });
687             }
688             
689         }
690         if (body) {
691             body.html = this.html || cfg.html;
692         }
693         if (!cfg.cls.length) {
694             cfg.cls =  'container';
695         }
696         
697         return cfg;
698     }
699    
700 });
701
702  /*
703  * - LGPL
704  *
705  * image
706  * 
707  */
708
709
710 /**
711  * @class Roo.bootstrap.Img
712  * @extends Roo.bootstrap.Component
713  * Bootstrap Img class
714  * @cfg {Boolean} imgResponsive false | true
715  * @cfg {String} border rounded | circle | thumbnail
716  * @cfg {String} src image source
717  * @cfg {String} alt image alternative text
718  * 
719  * @constructor
720  * Create a new Input
721  * @param {Object} config The config object
722  */
723
724 Roo.bootstrap.Img = function(config){
725     Roo.bootstrap.Img.superclass.constructor.call(this, config);
726 };
727
728 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
729     
730     imgResponsive: true,
731     border: '',
732     src: '',
733
734     getAutoCreate : function(){
735         
736         cfg = {
737             tag: 'img',
738             cls: 'img-responsive',
739             html : null
740         }
741         
742         cfg.html = this.html || cfg.html;
743         
744         cfg.src = this.src || cfg.src;
745         
746         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
747             cfg.cls += ' img-' + this.border;
748         }
749         
750         if(this.alt){
751             cfg.alt = this.alt;
752         }
753         
754         return cfg;
755     }
756    
757 });
758
759  /*
760  * - LGPL
761  *
762  * header
763  * 
764  */
765
766 /**
767  * @class Roo.bootstrap.Header
768  * @extends Roo.bootstrap.Component
769  * Bootstrap Header class
770  * @cfg {String} html content of header
771  * @cfg {Number} level (1|2|3|4|5|6) default 1
772  * 
773  * @constructor
774  * Create a new Header
775  * @param {Object} config The config object
776  */
777
778
779 Roo.bootstrap.Header  = function(config){
780     Roo.bootstrap.Header.superclass.constructor.call(this, config);
781 };
782
783 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
784     
785     //href : false,
786     html : false,
787     level : 1,
788     
789     
790     
791     getAutoCreate : function(){
792         
793         var cfg = {
794             tag: 'h' + (1 *this.level),
795             html: this.html || 'fill in html'
796         } ;
797         
798         return cfg;
799     }
800    
801 });
802
803  
804
805  /*
806  * - LGPL
807  *
808  * menu
809  * 
810  */
811
812 /**
813  * @class Roo.bootstrap.Menu
814  * @extends Roo.bootstrap.Component
815  * Bootstrap Menu class - container for MenuItems
816  * @cfg {String} type type of menu
817  * 
818  * @constructor
819  * Create a new Menu
820  * @param {Object} config The config object
821  */
822
823
824 Roo.bootstrap.Menu = function(config){
825     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
826 };
827
828 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
829     
830    /// html : false,
831     //align : '',
832     triggerEl : false,
833     type: false,
834     
835     
836     getChildContainer : function() {
837         return this.el;  
838     },
839     
840     getAutoCreate : function(){
841          
842         //if (['right'].indexOf(this.align)!==-1) {
843         //    cfg.cn[1].cls += ' pull-right'
844         //}
845         var cfg = {
846             tag : 'ul',
847             cls : 'dropdown-menu' 
848             
849         }
850         
851         if (this.type==='submenu') {
852             cfg.cls='submenu active'
853         }
854         
855         return cfg;
856     },
857     initEvents : function() {
858        // Roo.log("ADD event");
859        // Roo.log(this.triggerEl.dom);
860         this.triggerEl.on('click', this.toggle, this);
861         this.triggerEl.addClass('dropdown-toggle');
862         
863     },
864     toggle  : function(e)
865     {
866         //Roo.log(e.getTarget());
867        // Roo.log(this.triggerEl.dom);
868         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
869             return;
870         }
871         var isActive = this.triggerEl.hasClass('open');
872         // if disabled.. ingore
873         this.clearMenus(e);
874         //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
875          // if mobile we use a backdrop because click events don't delegate
876         // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
877         // }
878  
879        //var relatedTarget = { relatedTarget: this }
880        //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
881  
882        //if (e.isDefaultPrevented()) return;
883         
884        this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
885        
886        //  .trigger('shown.bs.dropdown', relatedTarget)
887  
888        this.triggerEl.focus();
889        Roo.log(e);
890        e.preventDefault(); 
891         
892         
893     },
894     clearMenus : function()
895     {
896         //$(backdrop).remove()
897         Roo.select('.dropdown-toggle',true).each(function(aa) {
898             if (!aa.hasClass('open')) {
899                 return;
900             }
901             // triger close...
902             aa.removeClass('open');
903           //var parent = getParent($(this))
904           //var relatedTarget = { relatedTarget: this }
905           
906            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
907           //if (e.isDefaultPrevented()) return
908            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
909         })
910     }
911     
912    
913 });
914
915  
916
917  /*
918  * - LGPL
919  *
920  * menu item
921  * 
922  */
923
924
925 /**
926  * @class Roo.bootstrap.MenuItem
927  * @extends Roo.bootstrap.Component
928  * Bootstrap MenuItem class
929  * @cfg {String} html the menu label
930  * @cfg {String} href the link
931  * 
932  * 
933  * @constructor
934  * Create a new MenuItem
935  * @param {Object} config The config object
936  */
937
938
939 Roo.bootstrap.MenuItem = function(config){
940     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
941 };
942
943 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
944     
945     href : false,
946     html : false,
947     
948     getAutoCreate : function(){
949         var cfg= {
950             tag: 'li',
951             cn: [
952                 {
953                     tag : 'a',
954                     href : '#',
955                     html : 'Link'
956                 }
957             ]
958         };
959         
960         cfg.cn[0].href = this.href || cfg.cn[0].href ;
961         cfg.cn[0].html = this.html || cfg.cn[0].html ;
962         return cfg;
963     }
964    
965 });
966
967  
968
969  /*
970  * - LGPL
971  *
972  * menu separator
973  * 
974  */
975
976
977 /**
978  * @class Roo.bootstrap.MenuSeparator
979  * @extends Roo.bootstrap.Component
980  * Bootstrap MenuSeparator class
981  * 
982  * @constructor
983  * Create a new MenuItem
984  * @param {Object} config The config object
985  */
986
987
988 Roo.bootstrap.MenuSeparator = function(config){
989     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
990 };
991
992 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
993     
994     getAutoCreate : function(){
995         var cfg = {
996             cls: 'divider',
997             tag : 'li'
998         };
999         
1000         return cfg;
1001     }
1002    
1003 });
1004
1005  
1006
1007  
1008 /*
1009 <div class="modal fade">
1010   <div class="modal-dialog">
1011     <div class="modal-content">
1012       <div class="modal-header">
1013         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1014         <h4 class="modal-title">Modal title</h4>
1015       </div>
1016       <div class="modal-body">
1017         <p>One fine body&hellip;</p>
1018       </div>
1019       <div class="modal-footer">
1020         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1021         <button type="button" class="btn btn-primary">Save changes</button>
1022       </div>
1023     </div><!-- /.modal-content -->
1024   </div><!-- /.modal-dialog -->
1025 </div><!-- /.modal -->
1026 */
1027 /*
1028  * - LGPL
1029  *
1030  * page contgainer.
1031  * 
1032  */
1033
1034 /**
1035  * @class Roo.bootstrap.Modal
1036  * @extends Roo.bootstrap.Component
1037  * Bootstrap Modal class
1038  * @cfg {String} title Title of dialog
1039  * @cfg {Array} buttons Array of buttons or standard button set..
1040  * 
1041  * @constructor
1042  * Create a new Modal Dialog
1043  * @param {Object} config The config object
1044  */
1045
1046 Roo.bootstrap.Modal = function(config){
1047     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1048     this.addEvents({
1049         // raw events
1050         /**
1051          * @event click
1052          * The raw click event for the entire grid.
1053          * @param {Roo.EventObject} e
1054          */
1055         "btnclick" : true
1056     });
1057 };
1058
1059 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
1060     
1061     title : 'test dialog',
1062    
1063     buttons : false,
1064
1065     onRender : function(ct, position)
1066     {
1067         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1068         if(!this.el){
1069             var cfg = Roo.apply({},  this.getAutoCreate());
1070             cfg.id = Roo.id();
1071             //if(!cfg.name){
1072             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1073             //}
1074             //if (!cfg.name.length) {
1075             //    delete cfg.name;
1076            // }
1077             if (this.cls) {
1078                 cfg.cls += ' ' + this.cls;
1079             }
1080             if (this.style) {
1081                 cfg.style = this.style;
1082             }
1083             this.el = Roo.get(document.body).createChild(cfg, position);
1084         }
1085         //var type = this.el.dom.type;
1086          
1087         if(this.tabIndex !== undefined){
1088             this.el.dom.setAttribute('tabIndex', this.tabIndex);
1089         }
1090         
1091         
1092         
1093         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1094         this.maskEl.enableDisplayMode("block");
1095         this.maskEl.hide();
1096         //this.el.addClass("x-dlg-modal");
1097     
1098         
1099         if (this.buttons) {
1100             Roo.each(this.buttons, function(bb) {
1101                 b = Roo.apply({}, bb);
1102                 b.xns = b.xns || Roo.bootstrap;
1103                 b.xtype = b.xtype || 'Button';
1104                 if (typeof(b.listeners) == 'undefined') {
1105                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
1106                 }
1107                 
1108                 var btn = Roo.factory(b);
1109                 
1110                 btn.onRender(this.el.select('.modal-footer').first());
1111                 
1112             },this);
1113         }
1114         
1115         
1116         
1117         this.initEvents();
1118         //this.el.addClass([this.fieldClass, this.cls]);
1119         
1120     },
1121     getAutoCreate : function(){
1122         
1123         
1124         var bdy = {
1125                 cls : 'modal-body',
1126                 html : this.html || ''
1127         };
1128         
1129          
1130         return {
1131             cls: "modal fade",
1132             cn : [
1133                 {
1134                     cls: "modal-dialog",
1135                     cn : [
1136                         {
1137                             cls : "modal-content",
1138                             cn : [
1139                                 {
1140                                     cls : 'modal-header',
1141                                     cn : [
1142                                         {
1143                                             tag: 'button',
1144                                             cls : 'close',
1145                                             html : '&times'
1146                                         },
1147                                         {
1148                                             tag: 'h4',
1149                                             cls : 'modal-title',
1150                                             html : this.title
1151                                         }
1152                                     
1153                                     ]
1154                                 },
1155                                 bdy,
1156                                 {
1157                                     cls : 'modal-footer' 
1158                                 }
1159                                 
1160                                 
1161                             ]
1162                             
1163                         }
1164                     ]
1165                         
1166                 }
1167             ]
1168             
1169             
1170         };
1171           
1172     },
1173     getChildContainer : function() {
1174          
1175          return this.el.select('.modal-body',true).first();
1176         
1177     },
1178     getButtonContainer : function() {
1179          return this.el.select('.modal-footer',true).first();
1180         
1181     },
1182     initEvents : function()
1183     {
1184         this.el.select('.modal-header .close').on('click', this.hide, this);
1185     },
1186     show : function() {
1187         if (!this.rendered) {
1188             this.render();
1189         }
1190        
1191         this.el.addClass('on');
1192         this.el.removeClass('fade');
1193         this.el.setStyle('display', 'block');
1194         Roo.get(document.body).addClass("x-body-masked");
1195         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1196         this.maskEl.show();
1197         this.el.setStyle('zIndex', '10001');
1198         
1199         
1200     },
1201     hide : function()
1202     {
1203         this.maskEl.hide();
1204         this.el.removeClass('on');
1205         this.el.addClass('fade');
1206         this.el.setStyle('display', 'none');
1207     },
1208     onButtonClick: function(btn,e)
1209     {
1210         //Roo.log([a,b,c]);
1211         this.fireEvent('btnclick', btn.name, e);
1212     }
1213 });
1214
1215
1216 Roo.apply(Roo.bootstrap.Modal,  {
1217     /**
1218          * Button config that displays a single OK button
1219          * @type Object
1220          */
1221         OK :  [{
1222             name : 'ok',
1223             weight : 'primary',
1224             html : 'OK'
1225         }], 
1226         /**
1227          * Button config that displays Yes and No buttons
1228          * @type Object
1229          */
1230         YESNO : [
1231             {
1232                 name  :'yes',
1233                 weight : 'primary',
1234                 html : 'Yes'
1235             },
1236             {
1237                 name  : 'no',
1238                 html : 'No'
1239             }
1240         ],
1241         
1242         /**
1243          * Button config that displays OK and Cancel buttons
1244          * @type Object
1245          */
1246         OKCANCEL : [
1247             {
1248                 name : 'ok',
1249                 weight : 'primary',
1250                 html : 'OK'
1251             },
1252             {
1253                name : 'cancel',
1254                 html : 'Cancel'
1255             }
1256         ],
1257         /**
1258          * Button config that displays Yes, No and Cancel buttons
1259          * @type Object
1260          */
1261         YESNOCANCEL : [
1262             {
1263                 name : 'yes',
1264                 weight : 'primary',
1265                 html : 'Yes'
1266             },
1267             {
1268                 name : 'no',
1269                 html : 'No'
1270             },
1271             {
1272                 name : 'cancel',
1273                 html : 'Cancel'
1274             }
1275         ]
1276 });
1277
1278  /*
1279  * - LGPL
1280  *
1281  * navbar
1282  * 
1283  */
1284
1285 /**
1286  * @class Roo.bootstrap.Navbar
1287  * @extends Roo.bootstrap.Component
1288  * Bootstrap Navbar class
1289  * @cfg {Boolean} sidebar has side bar
1290  * @cfg {Boolean} bar is a bar?
1291  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1292  * @cfg {String} brand what is brand
1293  * @cfg {Boolean} inverse is inverted color
1294  * @cfg {String} type (nav | pills | tabs)
1295  * @cfg {Boolean} arrangement stacked | justified
1296  * @cfg {String} align (left | right) alignment
1297  *
1298  * 
1299  * @constructor
1300  * Create a new Navbar
1301  * @param {Object} config The config object
1302  */
1303
1304
1305 Roo.bootstrap.Navbar = function(config){
1306     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1307 };
1308
1309 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
1310     
1311     sidebar: false,
1312     
1313     bar: false,
1314     brand: '',
1315     inverse: false,
1316     position: '',
1317     align : false,
1318     type: 'nav',
1319     arrangement: '',
1320     
1321     getAutoCreate : function(){
1322         var cfg = {
1323             cls : 'navbar'
1324         };
1325         
1326         if (this.sidebar === true) {
1327             cfg = {
1328                 tag: 'div',
1329                 cls: 'sidebar-nav'
1330             };
1331             return cfg;
1332         }
1333         
1334         if (this.bar === true) {
1335             cfg = {
1336                 tag: 'nav',
1337                 cls: 'navbar',
1338                 role: 'navigation',
1339                 cn: [
1340                     {
1341                         tag: 'div',
1342                         cls: 'navbar-header',
1343                         cn: [
1344                             {
1345                             tag: 'button',
1346                             type: 'button',
1347                             cls: 'navbar-toggle',
1348                             'data-toggle': 'collapse',
1349                             cn: [
1350                                 {
1351                                     tag: 'span',
1352                                     cls: 'sr-only',
1353                                     html: 'Toggle navigation'
1354                                 },
1355                                 {
1356                                     tag: 'span',
1357                                     cls: 'icon-bar'
1358                                 },
1359                                 {
1360                                     tag: 'span',
1361                                     cls: 'icon-bar'
1362                                 },
1363                                 {
1364                                     tag: 'span',
1365                                     cls: 'icon-bar'
1366                                 }
1367                             ]
1368                             }
1369                         ]
1370                     },
1371                     {
1372                     tag: 'div',
1373                     cls: 'collapse navbar-collapse'
1374                     }
1375                 ]
1376             };
1377             
1378             cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1379             
1380             if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1381             cfg.cls += ' navbar-' + this.position;
1382             cfg.tag = this.position  == 'fixed-bottom' ? 'footer' : 'header';
1383             }
1384             
1385             if (this.brand !== '') {
1386                 cfg.cn[0].cn.push({
1387                     tag: 'a',
1388                     href: '#',
1389                     cls: 'navbar-brand',
1390                     cn: [
1391                     this.brand
1392                     ]
1393                 });
1394             }
1395             
1396             return cfg;
1397         
1398         } else if (this.bar === false) {
1399             
1400         } else {
1401             Roo.log('Property \'bar\' in of Navbar must be either true or false')
1402         }
1403         
1404         cfg.cn = [
1405             {
1406                 cls: 'nav',
1407                 tag : 'ul'
1408             }
1409         ];
1410         
1411         if (['tabs','pills'].indexOf(this.type)!==-1) {
1412             cfg.cn[0].cls += ' nav-' + this.type
1413         } else {
1414             if (this.type!=='nav') {
1415             Roo.log('nav type must be nav/tabs/pills')
1416             }
1417             cfg.cn[0].cls += ' navbar-nav'
1418         }
1419         
1420         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1421             cfg.cn[0].cls += ' nav-' + this.arrangement;
1422         }
1423         
1424         if (this.align === 'right') {
1425             cfg.cn[0].cls += ' navbar-right';
1426         }
1427         if (this.inverse) {
1428             cfg.cls += ' navbar-inverse';
1429             
1430         }
1431         
1432         
1433         return cfg;
1434     },
1435     
1436     initEvents :function ()
1437     {
1438         //Roo.log(this.el.select('.navbar-toggle',true));
1439         this.el.select('.navbar-toggle',true).on('click', function() {
1440            // Roo.log('click');
1441             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
1442         }, this);
1443     },
1444     
1445     
1446     getChildContainer : function()
1447     {
1448         if (this.bar === true) {
1449             return this.el.select('.collapse',true).first();
1450         }
1451         console.log(this);
1452         return this.el;
1453     }
1454    
1455 });
1456
1457  
1458
1459  /*
1460  * - LGPL
1461  *
1462  * nav group
1463  * 
1464  */
1465
1466 /**
1467  * @class Roo.bootstrap.NavGroup
1468  * @extends Roo.bootstrap.Component
1469  * Bootstrap NavGroup class
1470  * @cfg {String} align left | right
1471  * @cfg {Boolean} inverse false | true
1472  * 
1473  * @constructor
1474  * Create a new nav group
1475  * @param {Object} config The config object
1476  */
1477
1478 Roo.bootstrap.NavGroup = function(config){
1479     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1480 };
1481
1482 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
1483     
1484     align: '',
1485     inverse: false,
1486     form: false,
1487     
1488     getAutoCreate : function(){
1489         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1490         
1491         cfg = {
1492             tag : 'ul',
1493             cls: 'nav navbar-nav' 
1494         }
1495         
1496         if (this.parent().sidebar === true) {
1497             cfg = {
1498                 tag: 'ul',
1499                 cls: 'dashboard-menu'
1500             }
1501             
1502             return cfg;
1503         }
1504         
1505         if (this.form === true) {
1506             cfg = {
1507                 tag: 'form',
1508                 cls: 'navbar-form'
1509             }
1510             
1511             if (this.align === 'right') {
1512                 cfg.cls += ' navbar-right';
1513             } else {
1514                 cfg.cls += ' navbar-left';
1515             }
1516         }
1517         
1518         
1519         if (this.align === 'right') {
1520             cfg.cls += ' navbar-right';
1521         }
1522         
1523         if (this.inverse) {
1524             cfg.cls += ' navbar-inverse';
1525             
1526         }
1527         
1528         
1529         return cfg;
1530     }
1531    
1532 });
1533
1534  
1535
1536  /*
1537  * - LGPL
1538  *
1539  * row
1540  * 
1541  */
1542
1543 /**
1544  * @class Roo.bootstrap.Navbar.Item
1545  * @extends Roo.bootstrap.Component
1546  * Bootstrap Navbar.Button class
1547  * @cfg {String} href  link to
1548  * @cfg {String} html content of button
1549  * @cfg {String} badge text inside badge
1550  * @cfg {String} glyphicon name of glyphicon
1551   
1552  * @constructor
1553  * Create a new Navbar Button
1554  * @param {Object} config The config object
1555  */
1556 Roo.bootstrap.Navbar.Item = function(config){
1557     Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1558 };
1559
1560 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component,  {
1561     
1562     href: false,
1563     html: '',
1564     badge: '',
1565     icon: false,
1566     glyphicon: false,
1567     
1568     getAutoCreate : function(){
1569         
1570         var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1571         
1572         if (this.parent().parent().sidebar === true) {
1573             cfg = {
1574                 tag: 'li',
1575                 cls: '',
1576                 cn: [
1577                     {
1578                         tag: 'p',
1579                         cls: ''
1580                     }
1581                 ]
1582             }
1583             
1584             if (this.html) {
1585                 cfg.cn[0].html = this.html;
1586             }
1587             
1588             if (this.active) {
1589                 this.cls += ' active';
1590             }
1591             
1592             if (this.menu) {
1593                 cfg.cn[0].cls += ' dropdown-toggle';
1594                 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1595             }
1596             
1597             if (this.href) {
1598                 cfg.cn[0].tag = 'a',
1599                 cfg.cn[0].href = this.href;
1600             }
1601             
1602             if (this.glyphicon) {
1603                 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1604             }
1605             
1606             return cfg;
1607         }
1608         
1609         cfg = {
1610             tag: 'li'
1611         }
1612         cfg.cn = [
1613             {
1614                 tag: 'p',
1615                 html: 'Text'
1616             }
1617         ];
1618         
1619         if (this.glyphicon) {
1620             if(cfg.html){cfg.html = ' ' + this.html};
1621             cfg.cn=[
1622                 {
1623                     tag: 'span',
1624                     cls: 'glyphicon glyphicon-' + this.glyphicon
1625                 }
1626             ];
1627         }
1628         
1629         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1630         if (this.menu) {
1631             cfg.cn[0].tag='a';
1632             cfg.cn[0].href='#';
1633             cfg.cn[0].html += " <span class='caret'></span>";
1634         //}else if (!this.href) {
1635         //    cfg.cn[0].tag='p';
1636         //    cfg.cn[0].cls='navbar-text';
1637         } else {
1638             cfg.cn[0].tag='a';
1639             cfg.cn[0].href=this.href||'#';
1640             cfg.cn[0].html=this.html;
1641         }
1642         
1643         if (this.badge !== '') {
1644             
1645             cfg.cn[0].cn=[
1646                 cfg.cn[0].html + ' ',
1647                 {
1648                     tag: 'span',
1649                     cls: 'badge',
1650                     html: this.badge
1651                 }
1652             ];
1653             cfg.cn[0].html=''
1654         }
1655          
1656         
1657         return cfg;
1658     },
1659     initEvents: function() {
1660        // Roo.log('init events?');
1661        // Roo.log(this.el.dom);
1662         this.el.select('a',true).on('click',
1663                 function(e) {
1664                     this.fireEvent('click', this);
1665                 },
1666                 this
1667         );
1668     }
1669    
1670 });
1671  
1672
1673  /*
1674  * - LGPL
1675  *
1676  * row
1677  * 
1678  */
1679
1680 /**
1681  * @class Roo.bootstrap.Row
1682  * @extends Roo.bootstrap.Component
1683  * Bootstrap Row class (contains columns...)
1684  * 
1685  * @constructor
1686  * Create a new Row
1687  * @param {Object} config The config object
1688  */
1689
1690 Roo.bootstrap.Row = function(config){
1691     Roo.bootstrap.Row.superclass.constructor.call(this, config);
1692 };
1693
1694 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
1695     
1696     getAutoCreate : function(){
1697        return {
1698             cls: 'row clearfix'
1699        };
1700     }
1701     
1702     
1703 });
1704
1705  
1706
1707  /*
1708  * - LGPL
1709  *
1710  * element
1711  * 
1712  */
1713
1714 /**
1715  * @class Roo.bootstrap.Element
1716  * @extends Roo.bootstrap.Component
1717  * Bootstrap Element class
1718  * @cfg {String} html contents of the element
1719  * @cfg {String} tag tag of the element
1720  * @cfg {String} cls class of the element
1721  * 
1722  * @constructor
1723  * Create a new Element
1724  * @param {Object} config The config object
1725  */
1726
1727 Roo.bootstrap.Element = function(config){
1728     Roo.bootstrap.Element.superclass.constructor.call(this, config);
1729 };
1730
1731 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
1732     
1733     tag: 'div',
1734     cls: '',
1735     html: '',
1736      
1737     
1738     getAutoCreate : function(){
1739         
1740         var cfg = {
1741             tag: this.tag,
1742             cls: '',
1743             html: this.html
1744         }
1745         
1746         return cfg;
1747     }
1748    
1749 });
1750
1751  
1752
1753  /*
1754  * - LGPL
1755  *
1756  * pagination
1757  * 
1758  */
1759
1760 /**
1761  * @class Roo.bootstrap.Pagination
1762  * @extends Roo.bootstrap.Component
1763  * Bootstrap Pagination class
1764  * @cfg {String} size xs | sm | md | lg
1765  * @cfg {Boolean} inverse false | true
1766  * @cfg {Number} from pagination starting number
1767  * @cfg {Number} to pagination ending number
1768  * @cfg {String} align empty or left | right
1769  * @cfg {Number} active active page number
1770  * 
1771  * @constructor
1772  * Create a new Pagination
1773  * @param {Object} config The config object
1774  */
1775
1776 Roo.bootstrap.Pagination = function(config){
1777     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1778 };
1779
1780 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
1781     
1782     cls: false,
1783     size: false,
1784     inverse: false,
1785     from: 1,
1786     to: 4,
1787     align: false,
1788     active: 1,
1789     
1790     getAutoCreate : function(){
1791         cfg = {
1792             tag: 'ul',
1793                 cls: 'pagination',
1794                 cn: []
1795         };
1796         if (this.inverse) {
1797             cfg.cls += ' inverse';
1798         }
1799         if (this.html) {
1800             cfg.html=this.html;
1801         }
1802         if (this.cls) {
1803             cfg.cls=this.cls;
1804         }
1805         cfg.cn[0]={
1806             tag: 'li',
1807             cn: [
1808                 {
1809                     tag: 'a',
1810                     href:'#',
1811                     html: '&laquo;'
1812                 }
1813             ]
1814         };
1815         var from=this.from>0?this.from:1;
1816         var to=this.to-from<=10?this.to:from+10;
1817         var active=this.active>=from&&this.active<=to?this.active:null;
1818         for (var i=from;i<=to;i++) {
1819             cfg.cn.push(
1820                 {
1821                     tag: 'li',
1822                     cls: active===i?'active':'',
1823                     cn: [
1824                         {
1825                             tag: 'a',
1826                             href: '#',
1827                             html: i
1828                         }
1829                     ]
1830                 }
1831             );
1832         }
1833         
1834         cfg.cn.push(
1835             {
1836                 tag: 'li',
1837                 cn: [
1838                     {
1839                        tag: 'a',
1840                        href: '#',
1841                        html: '&raquo;'
1842                     }
1843                 ]
1844             }
1845         );
1846         
1847         return cfg;
1848     }
1849    
1850 });
1851
1852  
1853
1854  /*
1855  * - LGPL
1856  *
1857  * slider
1858  * 
1859  */
1860
1861
1862 /**
1863  * @class Roo.bootstrap.Slider
1864  * @extends Roo.bootstrap.Component
1865  * Bootstrap Slider class
1866  *    
1867  * @constructor
1868  * Create a new Slider
1869  * @param {Object} config The config object
1870  */
1871
1872 Roo.bootstrap.Slider = function(config){
1873     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1874 };
1875
1876 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
1877     
1878     getAutoCreate : function(){
1879         
1880         var cfg = {
1881             tag: 'div',
1882             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1883             cn: [
1884                 {
1885                     tag: 'a',
1886                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
1887                 }
1888             ]
1889         }
1890         
1891         return cfg;
1892     }
1893    
1894 });
1895
1896  /*
1897  * - LGPL
1898  *
1899  * table
1900  * 
1901  */
1902
1903 /**
1904  * @class Roo.bootstrap.Table
1905  * @extends Roo.bootstrap.Component
1906  * Bootstrap Table class
1907  * 
1908  * @constructor
1909  * Create a new Table
1910  * @param {Object} config The config object
1911  */
1912
1913 Roo.bootstrap.Table = function(config){
1914     Roo.bootstrap.Table.superclass.constructor.call(this, config);
1915 };
1916
1917 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
1918     
1919     html: false,
1920     cls: false,
1921     
1922     getAutoCreate : function(){
1923         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
1924         
1925         cfg = {
1926             tag: 'table',
1927             cn: [
1928                 {
1929                     tag: 'tbody'
1930                 }
1931             ]
1932         }
1933         if (this.html) {
1934             cfg.html=this.html
1935         }
1936         if (this.cls) {
1937             cfg.cls=this.cls
1938         }
1939         
1940         return cfg;
1941     }
1942    
1943 });
1944
1945  
1946
1947  /*
1948  * - LGPL
1949  *
1950  * table cell
1951  * 
1952  */
1953
1954 /**
1955  * @class Roo.bootstrap.TableCell
1956  * @extends Roo.bootstrap.Component
1957  * Bootstrap TableCell class
1958  * 
1959  * @constructor
1960  * Create a new TableCell
1961  * @param {Object} config The config object
1962  */
1963
1964 Roo.bootstrap.TableCell = function(config){
1965     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
1966 };
1967
1968 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
1969     
1970     getAutoCreate : function(){
1971         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
1972         
1973         cfg = {
1974             tag: 'td'
1975         }
1976         if (this.html) {
1977             cfg.html=this.html
1978         }
1979         if (this.cls) {
1980             cfg.cls=this.cls
1981         }
1982         
1983         return cfg;
1984     }
1985    
1986 });
1987
1988  
1989
1990  /*
1991  * - LGPL
1992  *
1993  * table row
1994  * 
1995  */
1996
1997 /**
1998  * @class Roo.bootstrap.TableRow
1999  * @extends Roo.bootstrap.Component
2000  * Bootstrap TableRow class
2001  * 
2002  * @constructor
2003  * Create a new TableRow
2004  * @param {Object} config The config object
2005  */
2006
2007 Roo.bootstrap.TableRow = function(config){
2008     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2009 };
2010
2011 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
2012     
2013     getAutoCreate : function(){
2014         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2015         
2016         cfg = {
2017             tag: 'tr'
2018         }
2019         
2020         return cfg;
2021     }
2022    
2023 });
2024
2025  
2026
2027  /*
2028  * Based on:
2029  * Ext JS Library 1.1.1
2030  * Copyright(c) 2006-2007, Ext JS, LLC.
2031  *
2032  * Originally Released Under LGPL - original licence link has changed is not relivant.
2033  *
2034  * Fork - LGPL
2035  * <script type="text/javascript">
2036  */
2037
2038 // as we use this in bootstrap.
2039 Roo.namespace('Roo.form');
2040  /**
2041  * @class Roo.form.Action
2042  * Internal Class used to handle form actions
2043  * @constructor
2044  * @param {Roo.form.BasicForm} el The form element or its id
2045  * @param {Object} config Configuration options
2046  */
2047
2048  
2049  
2050 // define the action interface
2051 Roo.form.Action = function(form, options){
2052     this.form = form;
2053     this.options = options || {};
2054 };
2055 /**
2056  * Client Validation Failed
2057  * @const 
2058  */
2059 Roo.form.Action.CLIENT_INVALID = 'client';
2060 /**
2061  * Server Validation Failed
2062  * @const 
2063  */
2064 Roo.form.Action.SERVER_INVALID = 'server';
2065  /**
2066  * Connect to Server Failed
2067  * @const 
2068  */
2069 Roo.form.Action.CONNECT_FAILURE = 'connect';
2070 /**
2071  * Reading Data from Server Failed
2072  * @const 
2073  */
2074 Roo.form.Action.LOAD_FAILURE = 'load';
2075
2076 Roo.form.Action.prototype = {
2077     type : 'default',
2078     failureType : undefined,
2079     response : undefined,
2080     result : undefined,
2081
2082     // interface method
2083     run : function(options){
2084
2085     },
2086
2087     // interface method
2088     success : function(response){
2089
2090     },
2091
2092     // interface method
2093     handleResponse : function(response){
2094
2095     },
2096
2097     // default connection failure
2098     failure : function(response){
2099         
2100         this.response = response;
2101         this.failureType = Roo.form.Action.CONNECT_FAILURE;
2102         this.form.afterAction(this, false);
2103     },
2104
2105     processResponse : function(response){
2106         this.response = response;
2107         if(!response.responseText){
2108             return true;
2109         }
2110         this.result = this.handleResponse(response);
2111         return this.result;
2112     },
2113
2114     // utility functions used internally
2115     getUrl : function(appendParams){
2116         var url = this.options.url || this.form.url || this.form.el.dom.action;
2117         if(appendParams){
2118             var p = this.getParams();
2119             if(p){
2120                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2121             }
2122         }
2123         return url;
2124     },
2125
2126     getMethod : function(){
2127         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2128     },
2129
2130     getParams : function(){
2131         var bp = this.form.baseParams;
2132         var p = this.options.params;
2133         if(p){
2134             if(typeof p == "object"){
2135                 p = Roo.urlEncode(Roo.applyIf(p, bp));
2136             }else if(typeof p == 'string' && bp){
2137                 p += '&' + Roo.urlEncode(bp);
2138             }
2139         }else if(bp){
2140             p = Roo.urlEncode(bp);
2141         }
2142         return p;
2143     },
2144
2145     createCallback : function(){
2146         return {
2147             success: this.success,
2148             failure: this.failure,
2149             scope: this,
2150             timeout: (this.form.timeout*1000),
2151             upload: this.form.fileUpload ? this.success : undefined
2152         };
2153     }
2154 };
2155
2156 Roo.form.Action.Submit = function(form, options){
2157     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2158 };
2159
2160 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2161     type : 'submit',
2162
2163     haveProgress : false,
2164     uploadComplete : false,
2165     
2166     // uploadProgress indicator.
2167     uploadProgress : function()
2168     {
2169         if (!this.form.progressUrl) {
2170             return;
2171         }
2172         
2173         if (!this.haveProgress) {
2174             Roo.MessageBox.progress("Uploading", "Uploading");
2175         }
2176         if (this.uploadComplete) {
2177            Roo.MessageBox.hide();
2178            return;
2179         }
2180         
2181         this.haveProgress = true;
2182    
2183         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2184         
2185         var c = new Roo.data.Connection();
2186         c.request({
2187             url : this.form.progressUrl,
2188             params: {
2189                 id : uid
2190             },
2191             method: 'GET',
2192             success : function(req){
2193                //console.log(data);
2194                 var rdata = false;
2195                 var edata;
2196                 try  {
2197                    rdata = Roo.decode(req.responseText)
2198                 } catch (e) {
2199                     Roo.log("Invalid data from server..");
2200                     Roo.log(edata);
2201                     return;
2202                 }
2203                 if (!rdata || !rdata.success) {
2204                     Roo.log(rdata);
2205                     Roo.MessageBox.alert(Roo.encode(rdata));
2206                     return;
2207                 }
2208                 var data = rdata.data;
2209                 
2210                 if (this.uploadComplete) {
2211                    Roo.MessageBox.hide();
2212                    return;
2213                 }
2214                    
2215                 if (data){
2216                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2217                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2218                     );
2219                 }
2220                 this.uploadProgress.defer(2000,this);
2221             },
2222        
2223             failure: function(data) {
2224                 Roo.log('progress url failed ');
2225                 Roo.log(data);
2226             },
2227             scope : this
2228         });
2229            
2230     },
2231     
2232     
2233     run : function()
2234     {
2235         // run get Values on the form, so it syncs any secondary forms.
2236         this.form.getValues();
2237         
2238         var o = this.options;
2239         var method = this.getMethod();
2240         var isPost = method == 'POST';
2241         if(o.clientValidation === false || this.form.isValid()){
2242             
2243             if (this.form.progressUrl) {
2244                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2245                     (new Date() * 1) + '' + Math.random());
2246                     
2247             } 
2248             
2249             
2250             Roo.Ajax.request(Roo.apply(this.createCallback(), {
2251                 form:this.form.el.dom,
2252                 url:this.getUrl(!isPost),
2253                 method: method,
2254                 params:isPost ? this.getParams() : null,
2255                 isUpload: this.form.fileUpload
2256             }));
2257             
2258             this.uploadProgress();
2259
2260         }else if (o.clientValidation !== false){ // client validation failed
2261             this.failureType = Roo.form.Action.CLIENT_INVALID;
2262             this.form.afterAction(this, false);
2263         }
2264     },
2265
2266     success : function(response)
2267     {
2268         this.uploadComplete= true;
2269         if (this.haveProgress) {
2270             Roo.MessageBox.hide();
2271         }
2272         
2273         
2274         var result = this.processResponse(response);
2275         if(result === true || result.success){
2276             this.form.afterAction(this, true);
2277             return;
2278         }
2279         if(result.errors){
2280             this.form.markInvalid(result.errors);
2281             this.failureType = Roo.form.Action.SERVER_INVALID;
2282         }
2283         this.form.afterAction(this, false);
2284     },
2285     failure : function(response)
2286     {
2287         this.uploadComplete= true;
2288         if (this.haveProgress) {
2289             Roo.MessageBox.hide();
2290         }
2291         
2292         this.response = response;
2293         this.failureType = Roo.form.Action.CONNECT_FAILURE;
2294         this.form.afterAction(this, false);
2295     },
2296     
2297     handleResponse : function(response){
2298         if(this.form.errorReader){
2299             var rs = this.form.errorReader.read(response);
2300             var errors = [];
2301             if(rs.records){
2302                 for(var i = 0, len = rs.records.length; i < len; i++) {
2303                     var r = rs.records[i];
2304                     errors[i] = r.data;
2305                 }
2306             }
2307             if(errors.length < 1){
2308                 errors = null;
2309             }
2310             return {
2311                 success : rs.success,
2312                 errors : errors
2313             };
2314         }
2315         var ret = false;
2316         try {
2317             ret = Roo.decode(response.responseText);
2318         } catch (e) {
2319             ret = {
2320                 success: false,
2321                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2322                 errors : []
2323             };
2324         }
2325         return ret;
2326         
2327     }
2328 });
2329
2330
2331 Roo.form.Action.Load = function(form, options){
2332     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2333     this.reader = this.form.reader;
2334 };
2335
2336 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2337     type : 'load',
2338
2339     run : function(){
2340         
2341         Roo.Ajax.request(Roo.apply(
2342                 this.createCallback(), {
2343                     method:this.getMethod(),
2344                     url:this.getUrl(false),
2345                     params:this.getParams()
2346         }));
2347     },
2348
2349     success : function(response){
2350         
2351         var result = this.processResponse(response);
2352         if(result === true || !result.success || !result.data){
2353             this.failureType = Roo.form.Action.LOAD_FAILURE;
2354             this.form.afterAction(this, false);
2355             return;
2356         }
2357         this.form.clearInvalid();
2358         this.form.setValues(result.data);
2359         this.form.afterAction(this, true);
2360     },
2361
2362     handleResponse : function(response){
2363         if(this.form.reader){
2364             var rs = this.form.reader.read(response);
2365             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2366             return {
2367                 success : rs.success,
2368                 data : data
2369             };
2370         }
2371         return Roo.decode(response.responseText);
2372     }
2373 });
2374
2375 Roo.form.Action.ACTION_TYPES = {
2376     'load' : Roo.form.Action.Load,
2377     'submit' : Roo.form.Action.Submit
2378 };/*
2379  * - LGPL
2380  *
2381  * form
2382  * 
2383  */
2384
2385 /**
2386  * @class Roo.bootstrap.Form
2387  * @extends Roo.bootstrap.Component
2388  * Bootstrap Form class
2389  * @cfg {String} method  GET | POST (default POST)
2390  * @cfg {String} labelAlign top | left (default top)
2391   * @cfg {String} align left  | right - for navbars
2392
2393  * 
2394  * @constructor
2395  * Create a new Form
2396  * @param {Object} config The config object
2397  */
2398
2399
2400 Roo.bootstrap.Form = function(config){
2401     Roo.bootstrap.Form.superclass.constructor.call(this, config);
2402     this.addEvents({
2403         /**
2404          * @event clientvalidation
2405          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2406          * @param {Form} this
2407          * @param {Boolean} valid true if the form has passed client-side validation
2408          */
2409         clientvalidation: true,
2410         /**
2411          * @event beforeaction
2412          * Fires before any action is performed. Return false to cancel the action.
2413          * @param {Form} this
2414          * @param {Action} action The action to be performed
2415          */
2416         beforeaction: true,
2417         /**
2418          * @event actionfailed
2419          * Fires when an action fails.
2420          * @param {Form} this
2421          * @param {Action} action The action that failed
2422          */
2423         actionfailed : true,
2424         /**
2425          * @event actioncomplete
2426          * Fires when an action is completed.
2427          * @param {Form} this
2428          * @param {Action} action The action that completed
2429          */
2430         actioncomplete : true
2431     });
2432     
2433 };
2434
2435 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
2436       
2437      /**
2438      * @cfg {String} method
2439      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2440      */
2441     method : 'POST',
2442     /**
2443      * @cfg {String} url
2444      * The URL to use for form actions if one isn't supplied in the action options.
2445      */
2446     /**
2447      * @cfg {Boolean} fileUpload
2448      * Set to true if this form is a file upload.
2449      */
2450      
2451     /**
2452      * @cfg {Object} baseParams
2453      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2454      */
2455       
2456     /**
2457      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2458      */
2459     timeout: 30,
2460     /**
2461      * @cfg {Sting} align (left|right) for navbar forms
2462      */
2463     align : 'left',
2464
2465     // private
2466     activeAction : null,
2467  
2468     /**
2469      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2470      * element by passing it or its id or mask the form itself by passing in true.
2471      * @type Mixed
2472      */
2473     waitMsgTarget : false,
2474     
2475      
2476     
2477     /**
2478      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2479      * element by passing it or its id or mask the form itself by passing in true.
2480      * @type Mixed
2481      */
2482     
2483     getAutoCreate : function(){
2484         
2485         var cfg = {
2486             tag: 'form',
2487             method : this.method || 'POST',
2488             id : this.id || Roo.id(),
2489             cls : ''
2490         }
2491         if (this.parent().xtype.match(/^Nav/)) {
2492             cfg.cls = 'navbar-form navbar-' + this.align;
2493             
2494         }
2495         
2496         if (this.labelAlign == 'left' ) {
2497             cfg.cls += ' form-horizontal';
2498         }
2499         
2500         
2501         return cfg;
2502     },
2503     initEvents : function()
2504     {
2505         this.el.on('submit', this.onSubmit, this);
2506         
2507         
2508     },
2509     // private
2510     onSubmit : function(e){
2511         e.stopEvent();
2512     },
2513     
2514      /**
2515      * Returns true if client-side validation on the form is successful.
2516      * @return Boolean
2517      */
2518     isValid : function(){
2519         var items = this.getItems();
2520         var valid = true;
2521         items.each(function(f){
2522            if(!f.validate()){
2523                valid = false;
2524                
2525            }
2526         });
2527         return valid;
2528     },
2529     /**
2530      * Returns true if any fields in this form have changed since their original load.
2531      * @return Boolean
2532      */
2533     isDirty : function(){
2534         var dirty = false;
2535         var items = this.getItems();
2536         items.each(function(f){
2537            if(f.isDirty()){
2538                dirty = true;
2539                return false;
2540            }
2541            return true;
2542         });
2543         return dirty;
2544     },
2545      /**
2546      * Performs a predefined action (submit or load) or custom actions you define on this form.
2547      * @param {String} actionName The name of the action type
2548      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
2549      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2550      * accept other config options):
2551      * <pre>
2552 Property          Type             Description
2553 ----------------  ---------------  ----------------------------------------------------------------------------------
2554 url               String           The url for the action (defaults to the form's url)
2555 method            String           The form method to use (defaults to the form's method, or POST if not defined)
2556 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
2557 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
2558                                    validate the form on the client (defaults to false)
2559      * </pre>
2560      * @return {BasicForm} this
2561      */
2562     doAction : function(action, options){
2563         if(typeof action == 'string'){
2564             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2565         }
2566         if(this.fireEvent('beforeaction', this, action) !== false){
2567             this.beforeAction(action);
2568             action.run.defer(100, action);
2569         }
2570         return this;
2571     },
2572     
2573     // private
2574     beforeAction : function(action){
2575         var o = action.options;
2576         
2577         // not really supported yet.. ??
2578         
2579         //if(this.waitMsgTarget === true){
2580             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2581         //}else if(this.waitMsgTarget){
2582         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2583         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2584         //}else {
2585         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2586        // }
2587          
2588     },
2589
2590     // private
2591     afterAction : function(action, success){
2592         this.activeAction = null;
2593         var o = action.options;
2594         
2595         //if(this.waitMsgTarget === true){
2596             this.el.unmask();
2597         //}else if(this.waitMsgTarget){
2598         //    this.waitMsgTarget.unmask();
2599         //}else{
2600         //    Roo.MessageBox.updateProgress(1);
2601         //    Roo.MessageBox.hide();
2602        // }
2603         // 
2604         if(success){
2605             if(o.reset){
2606                 this.reset();
2607             }
2608             Roo.callback(o.success, o.scope, [this, action]);
2609             this.fireEvent('actioncomplete', this, action);
2610             
2611         }else{
2612             
2613             // failure condition..
2614             // we have a scenario where updates need confirming.
2615             // eg. if a locking scenario exists..
2616             // we look for { errors : { needs_confirm : true }} in the response.
2617             if (
2618                 (typeof(action.result) != 'undefined')  &&
2619                 (typeof(action.result.errors) != 'undefined')  &&
2620                 (typeof(action.result.errors.needs_confirm) != 'undefined')
2621            ){
2622                 var _t = this;
2623                 Roo.log("not supported yet");
2624                  /*
2625                 
2626                 Roo.MessageBox.confirm(
2627                     "Change requires confirmation",
2628                     action.result.errorMsg,
2629                     function(r) {
2630                         if (r != 'yes') {
2631                             return;
2632                         }
2633                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
2634                     }
2635                     
2636                 );
2637                 */
2638                 
2639                 
2640                 return;
2641             }
2642             
2643             Roo.callback(o.failure, o.scope, [this, action]);
2644             // show an error message if no failed handler is set..
2645             if (!this.hasListener('actionfailed')) {
2646                 Roo.log("need to add dialog support");
2647                 /*
2648                 Roo.MessageBox.alert("Error",
2649                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2650                         action.result.errorMsg :
2651                         "Saving Failed, please check your entries or try again"
2652                 );
2653                 */
2654             }
2655             
2656             this.fireEvent('actionfailed', this, action);
2657         }
2658         
2659     },
2660     /**
2661      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2662      * @param {String} id The value to search for
2663      * @return Field
2664      */
2665     findField : function(id){
2666         var items = this.getItems();
2667         var field = items.get(id);
2668         if(!field){
2669              items.each(function(f){
2670                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2671                     field = f;
2672                     return false;
2673                 }
2674                 return true;
2675             });
2676         }
2677         return field || null;
2678     },
2679      /**
2680      * Mark fields in this form invalid in bulk.
2681      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2682      * @return {BasicForm} this
2683      */
2684     markInvalid : function(errors){
2685         if(errors instanceof Array){
2686             for(var i = 0, len = errors.length; i < len; i++){
2687                 var fieldError = errors[i];
2688                 var f = this.findField(fieldError.id);
2689                 if(f){
2690                     f.markInvalid(fieldError.msg);
2691                 }
2692             }
2693         }else{
2694             var field, id;
2695             for(id in errors){
2696                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2697                     field.markInvalid(errors[id]);
2698                 }
2699             }
2700         }
2701         //Roo.each(this.childForms || [], function (f) {
2702         //    f.markInvalid(errors);
2703         //});
2704         
2705         return this;
2706     },
2707
2708     /**
2709      * Set values for fields in this form in bulk.
2710      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2711      * @return {BasicForm} this
2712      */
2713     setValues : function(values){
2714         if(values instanceof Array){ // array of objects
2715             for(var i = 0, len = values.length; i < len; i++){
2716                 var v = values[i];
2717                 var f = this.findField(v.id);
2718                 if(f){
2719                     f.setValue(v.value);
2720                     if(this.trackResetOnLoad){
2721                         f.originalValue = f.getValue();
2722                     }
2723                 }
2724             }
2725         }else{ // object hash
2726             var field, id;
2727             for(id in values){
2728                 if(typeof values[id] != 'function' && (field = this.findField(id))){
2729                     
2730                     if (field.setFromData && 
2731                         field.valueField && 
2732                         field.displayField &&
2733                         // combos' with local stores can 
2734                         // be queried via setValue()
2735                         // to set their value..
2736                         (field.store && !field.store.isLocal)
2737                         ) {
2738                         // it's a combo
2739                         var sd = { };
2740                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2741                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2742                         field.setFromData(sd);
2743                         
2744                     } else {
2745                         field.setValue(values[id]);
2746                     }
2747                     
2748                     
2749                     if(this.trackResetOnLoad){
2750                         field.originalValue = field.getValue();
2751                     }
2752                 }
2753             }
2754         }
2755          
2756         //Roo.each(this.childForms || [], function (f) {
2757         //    f.setValues(values);
2758         //});
2759                 
2760         return this;
2761     },
2762
2763     /**
2764      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2765      * they are returned as an array.
2766      * @param {Boolean} asString
2767      * @return {Object}
2768      */
2769     getValues : function(asString){
2770         //if (this.childForms) {
2771             // copy values from the child forms
2772         //    Roo.each(this.childForms, function (f) {
2773         //        this.setValues(f.getValues());
2774         //    }, this);
2775         //}
2776         
2777         
2778         
2779         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2780         if(asString === true){
2781             return fs;
2782         }
2783         return Roo.urlDecode(fs);
2784     },
2785     
2786     /**
2787      * Returns the fields in this form as an object with key/value pairs. 
2788      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2789      * @return {Object}
2790      */
2791     getFieldValues : function(with_hidden)
2792     {
2793         var items = this.getItems();
2794         var ret = {};
2795         items.each(function(f){
2796             if (!f.getName()) {
2797                 return;
2798             }
2799             var v = f.getValue();
2800             if (f.inputType =='radio') {
2801                 if (typeof(ret[f.getName()]) == 'undefined') {
2802                     ret[f.getName()] = ''; // empty..
2803                 }
2804                 
2805                 if (!f.el.dom.checked) {
2806                     return;
2807                     
2808                 }
2809                 v = f.el.dom.value;
2810                 
2811             }
2812             
2813             // not sure if this supported any more..
2814             if ((typeof(v) == 'object') && f.getRawValue) {
2815                 v = f.getRawValue() ; // dates..
2816             }
2817             // combo boxes where name != hiddenName...
2818             if (f.name != f.getName()) {
2819                 ret[f.name] = f.getRawValue();
2820             }
2821             ret[f.getName()] = v;
2822         });
2823         
2824         return ret;
2825     },
2826
2827     /**
2828      * Clears all invalid messages in this form.
2829      * @return {BasicForm} this
2830      */
2831     clearInvalid : function(){
2832         var items = this.getItems();
2833         
2834         items.each(function(f){
2835            f.clearInvalid();
2836         });
2837         
2838         
2839         
2840         return this;
2841     },
2842
2843     /**
2844      * Resets this form.
2845      * @return {BasicForm} this
2846      */
2847     reset : function(){
2848         var items = this.getItems();
2849         items.each(function(f){
2850             f.reset();
2851         });
2852         
2853         Roo.each(this.childForms || [], function (f) {
2854             f.reset();
2855         });
2856        
2857         
2858         return this;
2859     },
2860     getItems : function()
2861     {
2862         var r=new Roo.util.MixedCollection(false, function(o){
2863             return o.id || (o.id = Roo.id());
2864         });
2865         var iter = function(el) {
2866             if (el.inputEl) {
2867                 r.add(el);
2868             }
2869             if (!el.items) {
2870                 return;
2871             }
2872             Roo.each(el.items,function(e) {
2873                 iter(e);
2874             });
2875             
2876             
2877         };
2878         iter(this);
2879         return r;
2880         
2881         
2882         
2883         
2884     }
2885     
2886 });
2887
2888  
2889 /*
2890  * Based on:
2891  * Ext JS Library 1.1.1
2892  * Copyright(c) 2006-2007, Ext JS, LLC.
2893  *
2894  * Originally Released Under LGPL - original licence link has changed is not relivant.
2895  *
2896  * Fork - LGPL
2897  * <script type="text/javascript">
2898  */
2899 /**
2900  * @class Roo.form.VTypes
2901  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2902  * @singleton
2903  */
2904 Roo.form.VTypes = function(){
2905     // closure these in so they are only created once.
2906     var alpha = /^[a-zA-Z_]+$/;
2907     var alphanum = /^[a-zA-Z0-9_]+$/;
2908     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2909     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2910
2911     // All these messages and functions are configurable
2912     return {
2913         /**
2914          * The function used to validate email addresses
2915          * @param {String} value The email address
2916          */
2917         'email' : function(v){
2918             return email.test(v);
2919         },
2920         /**
2921          * The error text to display when the email validation function returns false
2922          * @type String
2923          */
2924         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2925         /**
2926          * The keystroke filter mask to be applied on email input
2927          * @type RegExp
2928          */
2929         'emailMask' : /[a-z0-9_\.\-@]/i,
2930
2931         /**
2932          * The function used to validate URLs
2933          * @param {String} value The URL
2934          */
2935         'url' : function(v){
2936             return url.test(v);
2937         },
2938         /**
2939          * The error text to display when the url validation function returns false
2940          * @type String
2941          */
2942         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2943         
2944         /**
2945          * The function used to validate alpha values
2946          * @param {String} value The value
2947          */
2948         'alpha' : function(v){
2949             return alpha.test(v);
2950         },
2951         /**
2952          * The error text to display when the alpha validation function returns false
2953          * @type String
2954          */
2955         'alphaText' : 'This field should only contain letters and _',
2956         /**
2957          * The keystroke filter mask to be applied on alpha input
2958          * @type RegExp
2959          */
2960         'alphaMask' : /[a-z_]/i,
2961
2962         /**
2963          * The function used to validate alphanumeric values
2964          * @param {String} value The value
2965          */
2966         'alphanum' : function(v){
2967             return alphanum.test(v);
2968         },
2969         /**
2970          * The error text to display when the alphanumeric validation function returns false
2971          * @type String
2972          */
2973         'alphanumText' : 'This field should only contain letters, numbers and _',
2974         /**
2975          * The keystroke filter mask to be applied on alphanumeric input
2976          * @type RegExp
2977          */
2978         'alphanumMask' : /[a-z0-9_]/i
2979     };
2980 }();/*
2981  * - LGPL
2982  *
2983  * Input
2984  * 
2985  */
2986
2987 /**
2988  * @class Roo.bootstrap.Input
2989  * @extends Roo.bootstrap.Component
2990  * Bootstrap Input class
2991  * @cfg {Boolean} disabled is it disabled
2992  * @cfg {String} fieldLabel - the label associated
2993  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
2994  * @cfg {String} name name of the input
2995  * @cfg {string} fieldLabel - the label associated
2996  * @cfg {string}  inputType - input / file submit ...
2997  * @cfg {string} placeholder - placeholder to put in text.
2998  * @cfg {string}  before - input group add on before
2999  * @cfg {string} after - input group add on after
3000  * @cfg {string} size - (lg|sm) or leave empty..
3001  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3002  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3003  * @cfg {Number} md colspan out of 12 for computer-sized screens
3004  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3005  * 
3006  * 
3007  * @constructor
3008  * Create a new Input
3009  * @param {Object} config The config object
3010  */
3011
3012 Roo.bootstrap.Input = function(config){
3013     Roo.bootstrap.Input.superclass.constructor.call(this, config);
3014    
3015         this.addEvents({
3016             /**
3017              * @event focus
3018              * Fires when this field receives input focus.
3019              * @param {Roo.form.Field} this
3020              */
3021             focus : true,
3022             /**
3023              * @event blur
3024              * Fires when this field loses input focus.
3025              * @param {Roo.form.Field} this
3026              */
3027             blur : true,
3028             /**
3029              * @event specialkey
3030              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
3031              * {@link Roo.EventObject#getKey} to determine which key was pressed.
3032              * @param {Roo.form.Field} this
3033              * @param {Roo.EventObject} e The event object
3034              */
3035             specialkey : true,
3036             /**
3037              * @event change
3038              * Fires just before the field blurs if the field value has changed.
3039              * @param {Roo.form.Field} this
3040              * @param {Mixed} newValue The new value
3041              * @param {Mixed} oldValue The original value
3042              */
3043             change : true,
3044             /**
3045              * @event invalid
3046              * Fires after the field has been marked as invalid.
3047              * @param {Roo.form.Field} this
3048              * @param {String} msg The validation message
3049              */
3050             invalid : true,
3051             /**
3052              * @event valid
3053              * Fires after the field has been validated with no errors.
3054              * @param {Roo.form.Field} this
3055              */
3056             valid : true,
3057              /**
3058              * @event keyup
3059              * Fires after the key up
3060              * @param {Roo.form.Field} this
3061              * @param {Roo.EventObject}  e The event Object
3062              */
3063             keyup : true
3064         });
3065 };
3066
3067 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
3068      /**
3069      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3070       automatic validation (defaults to "keyup").
3071      */
3072     validationEvent : "keyup",
3073      /**
3074      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3075      */
3076     validateOnBlur : true,
3077     /**
3078      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3079      */
3080     validationDelay : 250,
3081      /**
3082      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3083      */
3084     focusClass : "x-form-focus",  // not needed???
3085     
3086        
3087     /**
3088      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3089      */
3090     invalidClass : "has-error",
3091     
3092     /**
3093      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3094      */
3095     selectOnFocus : false,
3096     
3097      /**
3098      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3099      */
3100     maskRe : null,
3101        /**
3102      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3103      */
3104     vtype : null,
3105     
3106       /**
3107      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3108      */
3109     disableKeyFilter : false,
3110     
3111        /**
3112      * @cfg {Boolean} disabled True to disable the field (defaults to false).
3113      */
3114     disabled : false,
3115      /**
3116      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3117      */
3118     allowBlank : true,
3119     /**
3120      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3121      */
3122     blankText : "This field is required",
3123     
3124      /**
3125      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3126      */
3127     minLength : 0,
3128     /**
3129      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3130      */
3131     maxLength : Number.MAX_VALUE,
3132     /**
3133      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3134      */
3135     minLengthText : "The minimum length for this field is {0}",
3136     /**
3137      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3138      */
3139     maxLengthText : "The maximum length for this field is {0}",
3140   
3141     
3142     /**
3143      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3144      * If available, this function will be called only after the basic validators all return true, and will be passed the
3145      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3146      */
3147     validator : null,
3148     /**
3149      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3150      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3151      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
3152      */
3153     regex : null,
3154     /**
3155      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3156      */
3157     regexText : "",
3158     
3159     
3160     
3161     fieldLabel : '',
3162     inputType : 'text',
3163     
3164     name : false,
3165     placeholder: false,
3166     before : false,
3167     after : false,
3168     size : false,
3169     // private
3170     hasFocus : false,
3171     preventMark: false,
3172     isFormField : true,
3173     
3174     getAutoCreate : function(){
3175         
3176         var parent = this.parent();
3177         
3178         var align = parent.labelAlign;
3179         
3180         var id = Roo.id();
3181         
3182         var cfg = {
3183             cls: 'form-group' //input-group
3184         };
3185         
3186         var input =  {
3187             tag: 'input',
3188             id : id,
3189             type : this.inputType,
3190             cls : 'form-control',
3191             placeholder : this.placeholder || '' 
3192             
3193         };
3194         if (this.name) {
3195             input.name = this.name;
3196         }
3197         if (this.size) {
3198             input.cls += ' input-' + this.size;
3199         }
3200         var settings=this;
3201         ['xs','sm','md','lg'].map(function(size){
3202             if (settings[size]) {
3203                 cfg.cls += ' col-' + size + '-' + settings[size];
3204             }
3205         });
3206         
3207         var inputblock = input;
3208         
3209         if (this.before || this.after) {
3210             
3211             inputblock = {
3212                 cls : 'input-group',
3213                 cn :  [] 
3214             };
3215             if (this.before) {
3216                 inputblock.cn.push({
3217                     tag :'span',
3218                     cls : 'input-group-addon',
3219                     html : this.before
3220                 });
3221             }
3222             inputblock.cn.push(input);
3223             if (this.after) {
3224                 inputblock.cn.push({
3225                     tag :'span',
3226                     cls : 'input-group-addon',
3227                     html : this.after
3228                 });
3229             }
3230             
3231         }
3232         
3233         Roo.log(align);
3234         Roo.log(this.fieldLabel.length);
3235         
3236         if (align ==='left' && this.fieldLabel.length) {
3237                 Roo.log("left and has label");
3238                 cfg.cn = [
3239                     
3240                     {
3241                         tag: 'label',
3242                         'for' :  id,
3243                         cls : 'col-sm-2 control-label',
3244                         html : this.fieldLabel
3245                         
3246                     },
3247                     {
3248                         cls : "col-sm-10", 
3249                         cn: [
3250                             inputblock
3251                         ]
3252                     }
3253                     
3254                 ];
3255         } else if ( this.fieldLabel.length) {
3256                 Roo.log(" label");
3257                  cfg.cn = [
3258                    
3259                     {
3260                         tag: 'label',
3261                         //cls : 'input-group-addon',
3262                         html : this.fieldLabel
3263                         
3264                     },
3265                     
3266                     inputblock
3267                     
3268                 ];
3269
3270         } else {
3271             
3272                    Roo.log(" no label && no align");
3273                 cfg.cn = [
3274                     
3275                         inputblock
3276                     
3277                 ];
3278                 
3279                 
3280         }
3281          
3282         
3283         
3284         
3285         if (this.disabled) {
3286             input.disabled=true;
3287         }
3288         return cfg;
3289         
3290     },
3291     /**
3292      * return the real input element.
3293      */
3294     inputEl: function ()
3295     {
3296         return this.el.select('input.form-control',true).first();
3297     },
3298     setDisabled : function(v)
3299     {
3300         var i  = this.inputEl().dom;
3301         if (v) {
3302             i.removeAttribute('disabled');
3303             return;
3304             
3305         }
3306         i.setAttribute('disabled','true');
3307     },
3308     initEvents : function()
3309     {
3310         
3311         this.inputEl().on("keydown" , this.fireKey,  this);
3312         this.inputEl().on("focus", this.onFocus,  this);
3313         this.inputEl().on("blur", this.onBlur,  this);
3314         this.inputEl().relayEvent('keyup', this);
3315
3316         // reference to original value for reset
3317         this.originalValue = this.getValue();
3318         //Roo.form.TextField.superclass.initEvents.call(this);
3319         if(this.validationEvent == 'keyup'){
3320             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3321             this.inputEl().on('keyup', this.filterValidation, this);
3322         }
3323         else if(this.validationEvent !== false){
3324             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3325         }
3326         
3327         if(this.selectOnFocus){
3328             this.on("focus", this.preFocus, this);
3329             
3330         }
3331         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3332             this.inputEl().on("keypress", this.filterKeys, this);
3333         }
3334        /* if(this.grow){
3335             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
3336             this.el.on("click", this.autoSize,  this);
3337         }
3338         */
3339         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3340             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3341         }
3342         
3343     },
3344     filterValidation : function(e){
3345         if(!e.isNavKeyPress()){
3346             this.validationTask.delay(this.validationDelay);
3347         }
3348     },
3349      /**
3350      * Validates the field value
3351      * @return {Boolean} True if the value is valid, else false
3352      */
3353     validate : function(){
3354         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3355         if(this.disabled || this.validateValue(this.getRawValue())){
3356             this.clearInvalid();
3357             return true;
3358         }
3359         return false;
3360     },
3361     
3362     
3363     /**
3364      * Validates a value according to the field's validation rules and marks the field as invalid
3365      * if the validation fails
3366      * @param {Mixed} value The value to validate
3367      * @return {Boolean} True if the value is valid, else false
3368      */
3369     validateValue : function(value){
3370         if(value.length < 1)  { // if it's blank
3371              if(this.allowBlank){
3372                 this.clearInvalid();
3373                 return true;
3374              }else{
3375                 this.markInvalid(this.blankText);
3376                 return false;
3377              }
3378         }
3379         if(value.length < this.minLength){
3380             this.markInvalid(String.format(this.minLengthText, this.minLength));
3381             return false;
3382         }
3383         if(value.length > this.maxLength){
3384             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3385             return false;
3386         }
3387         if(this.vtype){
3388             var vt = Roo.form.VTypes;
3389             if(!vt[this.vtype](value, this)){
3390                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3391                 return false;
3392             }
3393         }
3394         if(typeof this.validator == "function"){
3395             var msg = this.validator(value);
3396             if(msg !== true){
3397                 this.markInvalid(msg);
3398                 return false;
3399             }
3400         }
3401         if(this.regex && !this.regex.test(value)){
3402             this.markInvalid(this.regexText);
3403             return false;
3404         }
3405         return true;
3406     },
3407
3408     
3409     
3410      // private
3411     fireKey : function(e){
3412         //Roo.log('field ' + e.getKey());
3413         if(e.isNavKeyPress()){
3414             this.fireEvent("specialkey", this, e);
3415         }
3416     },
3417     focus : function (selectText){
3418         if(this.rendered){
3419             this.inputEl().focus();
3420             if(selectText === true){
3421                 this.inputEl().dom.select();
3422             }
3423         }
3424         return this;
3425     } ,
3426     
3427     onFocus : function(){
3428         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3429            // this.el.addClass(this.focusClass);
3430         }
3431         if(!this.hasFocus){
3432             this.hasFocus = true;
3433             this.startValue = this.getValue();
3434             this.fireEvent("focus", this);
3435         }
3436     },
3437     
3438     beforeBlur : Roo.emptyFn,
3439
3440     
3441     // private
3442     onBlur : function(){
3443         this.beforeBlur();
3444         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3445             //this.el.removeClass(this.focusClass);
3446         }
3447         this.hasFocus = false;
3448         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3449             this.validate();
3450         }
3451         var v = this.getValue();
3452         if(String(v) !== String(this.startValue)){
3453             this.fireEvent('change', this, v, this.startValue);
3454         }
3455         this.fireEvent("blur", this);
3456     },
3457     
3458     /**
3459      * Resets the current field value to the originally loaded value and clears any validation messages
3460      */
3461     reset : function(){
3462         this.setValue(this.originalValue);
3463         this.clearInvalid();
3464     },
3465      /**
3466      * Returns the name of the field
3467      * @return {Mixed} name The name field
3468      */
3469     getName: function(){
3470         return this.name;
3471     },
3472      /**
3473      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
3474      * @return {Mixed} value The field value
3475      */
3476     getValue : function(){
3477         var v = this.inputEl().getValue();
3478         return v;
3479     },
3480     /**
3481      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
3482      * @return {Mixed} value The field value
3483      */
3484     getRawValue : function(){
3485         var v = this.inputEl().getValue();
3486         
3487         return v;
3488     },
3489     /**
3490      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
3491      * @param {Mixed} value The value to set
3492      */
3493     setValue : function(v){
3494         this.value = v;
3495         if(this.rendered){
3496             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3497             this.validate();
3498         }
3499     },
3500     
3501     /*
3502     processValue : function(value){
3503         if(this.stripCharsRe){
3504             var newValue = value.replace(this.stripCharsRe, '');
3505             if(newValue !== value){
3506                 this.setRawValue(newValue);
3507                 return newValue;
3508             }
3509         }
3510         return value;
3511     },
3512   */
3513     preFocus : function(){
3514         
3515         if(this.selectOnFocus){
3516             this.inputEl().dom.select();
3517         }
3518     },
3519     filterKeys : function(e){
3520         var k = e.getKey();
3521         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3522             return;
3523         }
3524         var c = e.getCharCode(), cc = String.fromCharCode(c);
3525         if(Roo.isIE && (e.isSpecialKey() || !cc)){
3526             return;
3527         }
3528         if(!this.maskRe.test(cc)){
3529             e.stopEvent();
3530         }
3531     },
3532      /**
3533      * Clear any invalid styles/messages for this field
3534      */
3535     clearInvalid : function(){
3536         
3537         if(!this.el || this.preventMark){ // not rendered
3538             return;
3539         }
3540         this.el.removeClass(this.invalidClass);
3541         /*
3542         switch(this.msgTarget){
3543             case 'qtip':
3544                 this.el.dom.qtip = '';
3545                 break;
3546             case 'title':
3547                 this.el.dom.title = '';
3548                 break;
3549             case 'under':
3550                 if(this.errorEl){
3551                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3552                 }
3553                 break;
3554             case 'side':
3555                 if(this.errorIcon){
3556                     this.errorIcon.dom.qtip = '';
3557                     this.errorIcon.hide();
3558                     this.un('resize', this.alignErrorIcon, this);
3559                 }
3560                 break;
3561             default:
3562                 var t = Roo.getDom(this.msgTarget);
3563                 t.innerHTML = '';
3564                 t.style.display = 'none';
3565                 break;
3566         }
3567         */
3568         this.fireEvent('valid', this);
3569     },
3570      /**
3571      * Mark this field as invalid
3572      * @param {String} msg The validation message
3573      */
3574     markInvalid : function(msg){
3575         if(!this.el  || this.preventMark){ // not rendered
3576             return;
3577         }
3578         this.el.addClass(this.invalidClass);
3579         /*
3580         msg = msg || this.invalidText;
3581         switch(this.msgTarget){
3582             case 'qtip':
3583                 this.el.dom.qtip = msg;
3584                 this.el.dom.qclass = 'x-form-invalid-tip';
3585                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3586                     Roo.QuickTips.enable();
3587                 }
3588                 break;
3589             case 'title':
3590                 this.el.dom.title = msg;
3591                 break;
3592             case 'under':
3593                 if(!this.errorEl){
3594                     var elp = this.el.findParent('.x-form-element', 5, true);
3595                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3596                     this.errorEl.setWidth(elp.getWidth(true)-20);
3597                 }
3598                 this.errorEl.update(msg);
3599                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3600                 break;
3601             case 'side':
3602                 if(!this.errorIcon){
3603                     var elp = this.el.findParent('.x-form-element', 5, true);
3604                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3605                 }
3606                 this.alignErrorIcon();
3607                 this.errorIcon.dom.qtip = msg;
3608                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3609                 this.errorIcon.show();
3610                 this.on('resize', this.alignErrorIcon, this);
3611                 break;
3612             default:
3613                 var t = Roo.getDom(this.msgTarget);
3614                 t.innerHTML = msg;
3615                 t.style.display = this.msgDisplay;
3616                 break;
3617         }
3618         */
3619         this.fireEvent('invalid', this, msg);
3620     },
3621     // private
3622     SafariOnKeyDown : function(event)
3623     {
3624         // this is a workaround for a password hang bug on chrome/ webkit.
3625         
3626         var isSelectAll = false;
3627         
3628         if(this.inputEl().dom.selectionEnd > 0){
3629             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3630         }
3631         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3632             event.preventDefault();
3633             this.setValue('');
3634             return;
3635         }
3636         
3637         if(isSelectAll){ // backspace and delete key
3638             
3639             event.preventDefault();
3640             // this is very hacky as keydown always get's upper case.
3641             //
3642             var cc = String.fromCharCode(event.getCharCode());
3643             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
3644             
3645         }
3646         
3647         
3648     }
3649 });
3650
3651  
3652 /*
3653  * - LGPL
3654  *
3655  * trigger field - base class for combo..
3656  * 
3657  */
3658  
3659 /**
3660  * @class Roo.bootstrap.TriggerField
3661  * @extends Roo.bootstrap.Input
3662  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3663  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3664  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3665  * for which you can provide a custom implementation.  For example:
3666  * <pre><code>
3667 var trigger = new Roo.bootstrap.TriggerField();
3668 trigger.onTriggerClick = myTriggerFn;
3669 trigger.applyTo('my-field');
3670 </code></pre>
3671  *
3672  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3673  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3674  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
3675  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3676  * @constructor
3677  * Create a new TriggerField.
3678  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3679  * to the base TextField)
3680  */
3681 Roo.bootstrap.TriggerField = function(config){
3682     this.mimicing = false;
3683     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3684 };
3685
3686 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
3687     /**
3688      * @cfg {String} triggerClass A CSS class to apply to the trigger
3689      */
3690      /**
3691      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3692      */
3693     hideTrigger:false,
3694
3695     /** @cfg {Boolean} grow @hide */
3696     /** @cfg {Number} growMin @hide */
3697     /** @cfg {Number} growMax @hide */
3698
3699     /**
3700      * @hide 
3701      * @method
3702      */
3703     autoSize: Roo.emptyFn,
3704     // private
3705     monitorTab : true,
3706     // private
3707     deferHeight : true,
3708
3709     
3710     actionMode : 'wrap',
3711     
3712     
3713     
3714     getAutoCreate : function(){
3715        
3716         var parent = this.parent();
3717         
3718         var align = parent.labelAlign;
3719         
3720         var id = Roo.id();
3721         
3722         var cfg = {
3723             cls: 'form-group' //input-group
3724         };
3725         
3726         
3727         var input =  {
3728             tag: 'input',
3729             id : id,
3730             type : this.inputType,
3731             cls : 'form-control',
3732             autocomplete: 'off',
3733             placeholder : this.placeholder || '' 
3734             
3735         };
3736         if (this.name) {
3737             input.name = this.name;
3738         }
3739         if (this.size) {
3740             input.cls += ' input-' + this.size;
3741         }
3742         var inputblock = {
3743             cls: 'combobox-container input-group',
3744             cn: [
3745                 {
3746                     tag: 'input',
3747                     type : 'hidden',
3748                     cls: 'form-hidden-field'
3749                 },
3750                 input,
3751                 {
3752                     tag: 'ul',
3753                     cls : 'typeahead typeahead-long dropdown-menu',
3754                     style : 'display:none'
3755                 },
3756                 {
3757                     tag :'span',
3758                     cls : 'input-group-addon btn dropdown-toggle',
3759                     cn : [
3760                         {
3761                             tag: 'span',
3762                             cls: 'caret'
3763                         },
3764                         {
3765                             tag: 'span',
3766                             cls: 'combobox-clear',
3767                             cn  : [
3768                                 {
3769                                     tag : 'i',
3770                                     cls: 'icon-remove'
3771                                 }
3772                             ]
3773                         }
3774                     ]
3775                         
3776                 }
3777             ]
3778         };
3779         
3780         
3781         
3782         
3783         if (align ==='left' && this.fieldLabel.length) {
3784                 
3785             
3786             
3787                 Roo.log("left and has label");
3788                 cfg.cn = [
3789                     
3790                     {
3791                         tag: 'label',
3792                         'for' :  id,
3793                         cls : 'col-sm-2 control-label',
3794                         html : this.fieldLabel
3795                         
3796                     },
3797                     {
3798                         cls : "col-sm-10", 
3799                         cn: [
3800                             inputblock
3801                         ]
3802                     }
3803                     
3804                 ];
3805         } else if ( this.fieldLabel.length) {
3806                 Roo.log(" label");
3807                  cfg.cn = [
3808                    
3809                     {
3810                         tag: 'label',
3811                         //cls : 'input-group-addon',
3812                         html : this.fieldLabel
3813                         
3814                     },
3815                     
3816                     inputblock
3817                     
3818                 ];
3819
3820         } else {
3821             
3822                 Roo.log(" no label && no align");
3823                 cfg = inputblock
3824                      
3825                 
3826         }
3827          
3828         var settings=this;
3829         ['xs','sm','md','lg'].map(function(size){
3830             if (settings[size]) {
3831                 cfg.cls += ' col-' + size + '-' + settings[size];
3832             }
3833         });
3834         
3835         
3836         
3837         if (this.disabled) {
3838             input.disabled=true;
3839         }
3840         return cfg;
3841         
3842     },
3843     
3844     
3845     
3846     // private
3847     onResize : function(w, h){
3848         Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3849         if(typeof w == 'number'){
3850             var x = w - this.trigger.getWidth();
3851             this.inputEl().setWidth(this.adjustWidth('input', x));
3852             this.trigger.setStyle('left', x+'px');
3853         }
3854     },
3855
3856     // private
3857     adjustSize : Roo.BoxComponent.prototype.adjustSize,
3858
3859     // private
3860     getResizeEl : function(){
3861         return this.inputEl();
3862     },
3863
3864     // private
3865     getPositionEl : function(){
3866         return this.inputEl();
3867     },
3868
3869     // private
3870     alignErrorIcon : function(){
3871         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3872     },
3873
3874     // private
3875     initEvents : function(){
3876         
3877         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3878         
3879         this.trigger = this.el.select('span.dropdown-toggle',true).first();
3880         if(this.hideTrigger){
3881             this.trigger.setDisplayed(false);
3882         }
3883         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3884         //this.trigger.addClassOnOver('x-form-trigger-over');
3885         //this.trigger.addClassOnClick('x-form-trigger-click');
3886         
3887         //if(!this.width){
3888         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3889         //}
3890     },
3891
3892     // private
3893     initTrigger : function(){
3894        
3895     },
3896
3897     // private
3898     onDestroy : function(){
3899         if(this.trigger){
3900             this.trigger.removeAllListeners();
3901           //  this.trigger.remove();
3902         }
3903         //if(this.wrap){
3904         //    this.wrap.remove();
3905         //}
3906         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3907     },
3908
3909     // private
3910     onFocus : function(){
3911         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3912         /*
3913         if(!this.mimicing){
3914             this.wrap.addClass('x-trigger-wrap-focus');
3915             this.mimicing = true;
3916             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3917             if(this.monitorTab){
3918                 this.el.on("keydown", this.checkTab, this);
3919             }
3920         }
3921         */
3922     },
3923
3924     // private
3925     checkTab : function(e){
3926         if(e.getKey() == e.TAB){
3927             this.triggerBlur();
3928         }
3929     },
3930
3931     // private
3932     onBlur : function(){
3933         // do nothing
3934     },
3935
3936     // private
3937     mimicBlur : function(e, t){
3938         /*
3939         if(!this.wrap.contains(t) && this.validateBlur()){
3940             this.triggerBlur();
3941         }
3942         */
3943     },
3944
3945     // private
3946     triggerBlur : function(){
3947         this.mimicing = false;
3948         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
3949         if(this.monitorTab){
3950             this.el.un("keydown", this.checkTab, this);
3951         }
3952         //this.wrap.removeClass('x-trigger-wrap-focus');
3953         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
3954     },
3955
3956     // private
3957     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
3958     validateBlur : function(e, t){
3959         return true;
3960     },
3961
3962     // private
3963     onDisable : function(){
3964         Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
3965         //if(this.wrap){
3966         //    this.wrap.addClass('x-item-disabled');
3967         //}
3968     },
3969
3970     // private
3971     onEnable : function(){
3972         Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
3973         //if(this.wrap){
3974         //    this.el.removeClass('x-item-disabled');
3975         //}
3976     },
3977
3978     // private
3979     onShow : function(){
3980         var ae = this.getActionEl();
3981         
3982         if(ae){
3983             ae.dom.style.display = '';
3984             ae.dom.style.visibility = 'visible';
3985         }
3986     },
3987
3988     // private
3989     
3990     onHide : function(){
3991         var ae = this.getActionEl();
3992         ae.dom.style.display = 'none';
3993     },
3994
3995     /**
3996      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
3997      * by an implementing function.
3998      * @method
3999      * @param {EventObject} e
4000      */
4001     onTriggerClick : Roo.emptyFn
4002 });
4003  /*
4004  * Based on:
4005  * Ext JS Library 1.1.1
4006  * Copyright(c) 2006-2007, Ext JS, LLC.
4007  *
4008  * Originally Released Under LGPL - original licence link has changed is not relivant.
4009  *
4010  * Fork - LGPL
4011  * <script type="text/javascript">
4012  */
4013
4014
4015 /**
4016  * @class Roo.data.SortTypes
4017  * @singleton
4018  * Defines the default sorting (casting?) comparison functions used when sorting data.
4019  */
4020 Roo.data.SortTypes = {
4021     /**
4022      * Default sort that does nothing
4023      * @param {Mixed} s The value being converted
4024      * @return {Mixed} The comparison value
4025      */
4026     none : function(s){
4027         return s;
4028     },
4029     
4030     /**
4031      * The regular expression used to strip tags
4032      * @type {RegExp}
4033      * @property
4034      */
4035     stripTagsRE : /<\/?[^>]+>/gi,
4036     
4037     /**
4038      * Strips all HTML tags to sort on text only
4039      * @param {Mixed} s The value being converted
4040      * @return {String} The comparison value
4041      */
4042     asText : function(s){
4043         return String(s).replace(this.stripTagsRE, "");
4044     },
4045     
4046     /**
4047      * Strips all HTML tags to sort on text only - Case insensitive
4048      * @param {Mixed} s The value being converted
4049      * @return {String} The comparison value
4050      */
4051     asUCText : function(s){
4052         return String(s).toUpperCase().replace(this.stripTagsRE, "");
4053     },
4054     
4055     /**
4056      * Case insensitive string
4057      * @param {Mixed} s The value being converted
4058      * @return {String} The comparison value
4059      */
4060     asUCString : function(s) {
4061         return String(s).toUpperCase();
4062     },
4063     
4064     /**
4065      * Date sorting
4066      * @param {Mixed} s The value being converted
4067      * @return {Number} The comparison value
4068      */
4069     asDate : function(s) {
4070         if(!s){
4071             return 0;
4072         }
4073         if(s instanceof Date){
4074             return s.getTime();
4075         }
4076         return Date.parse(String(s));
4077     },
4078     
4079     /**
4080      * Float sorting
4081      * @param {Mixed} s The value being converted
4082      * @return {Float} The comparison value
4083      */
4084     asFloat : function(s) {
4085         var val = parseFloat(String(s).replace(/,/g, ""));
4086         if(isNaN(val)) val = 0;
4087         return val;
4088     },
4089     
4090     /**
4091      * Integer sorting
4092      * @param {Mixed} s The value being converted
4093      * @return {Number} The comparison value
4094      */
4095     asInt : function(s) {
4096         var val = parseInt(String(s).replace(/,/g, ""));
4097         if(isNaN(val)) val = 0;
4098         return val;
4099     }
4100 };/*
4101  * Based on:
4102  * Ext JS Library 1.1.1
4103  * Copyright(c) 2006-2007, Ext JS, LLC.
4104  *
4105  * Originally Released Under LGPL - original licence link has changed is not relivant.
4106  *
4107  * Fork - LGPL
4108  * <script type="text/javascript">
4109  */
4110
4111 /**
4112 * @class Roo.data.Record
4113  * Instances of this class encapsulate both record <em>definition</em> information, and record
4114  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4115  * to access Records cached in an {@link Roo.data.Store} object.<br>
4116  * <p>
4117  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4118  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4119  * objects.<br>
4120  * <p>
4121  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4122  * @constructor
4123  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4124  * {@link #create}. The parameters are the same.
4125  * @param {Array} data An associative Array of data values keyed by the field name.
4126  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4127  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4128  * not specified an integer id is generated.
4129  */
4130 Roo.data.Record = function(data, id){
4131     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4132     this.data = data;
4133 };
4134
4135 /**
4136  * Generate a constructor for a specific record layout.
4137  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4138  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4139  * Each field definition object may contain the following properties: <ul>
4140  * <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,
4141  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4142  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4143  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4144  * is being used, then this is a string containing the javascript expression to reference the data relative to 
4145  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4146  * to the data item relative to the record element. If the mapping expression is the same as the field name,
4147  * this may be omitted.</p></li>
4148  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4149  * <ul><li>auto (Default, implies no conversion)</li>
4150  * <li>string</li>
4151  * <li>int</li>
4152  * <li>float</li>
4153  * <li>boolean</li>
4154  * <li>date</li></ul></p></li>
4155  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4156  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4157  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4158  * by the Reader into an object that will be stored in the Record. It is passed the
4159  * following parameters:<ul>
4160  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4161  * </ul></p></li>
4162  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4163  * </ul>
4164  * <br>usage:<br><pre><code>
4165 var TopicRecord = Roo.data.Record.create(
4166     {name: 'title', mapping: 'topic_title'},
4167     {name: 'author', mapping: 'username'},
4168     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4169     {name: 'lastPost', mapping: 'post_time', type: 'date'},
4170     {name: 'lastPoster', mapping: 'user2'},
4171     {name: 'excerpt', mapping: 'post_text'}
4172 );
4173
4174 var myNewRecord = new TopicRecord({
4175     title: 'Do my job please',
4176     author: 'noobie',
4177     totalPosts: 1,
4178     lastPost: new Date(),
4179     lastPoster: 'Animal',
4180     excerpt: 'No way dude!'
4181 });
4182 myStore.add(myNewRecord);
4183 </code></pre>
4184  * @method create
4185  * @static
4186  */
4187 Roo.data.Record.create = function(o){
4188     var f = function(){
4189         f.superclass.constructor.apply(this, arguments);
4190     };
4191     Roo.extend(f, Roo.data.Record);
4192     var p = f.prototype;
4193     p.fields = new Roo.util.MixedCollection(false, function(field){
4194         return field.name;
4195     });
4196     for(var i = 0, len = o.length; i < len; i++){
4197         p.fields.add(new Roo.data.Field(o[i]));
4198     }
4199     f.getField = function(name){
4200         return p.fields.get(name);  
4201     };
4202     return f;
4203 };
4204
4205 Roo.data.Record.AUTO_ID = 1000;
4206 Roo.data.Record.EDIT = 'edit';
4207 Roo.data.Record.REJECT = 'reject';
4208 Roo.data.Record.COMMIT = 'commit';
4209
4210 Roo.data.Record.prototype = {
4211     /**
4212      * Readonly flag - true if this record has been modified.
4213      * @type Boolean
4214      */
4215     dirty : false,
4216     editing : false,
4217     error: null,
4218     modified: null,
4219
4220     // private
4221     join : function(store){
4222         this.store = store;
4223     },
4224
4225     /**
4226      * Set the named field to the specified value.
4227      * @param {String} name The name of the field to set.
4228      * @param {Object} value The value to set the field to.
4229      */
4230     set : function(name, value){
4231         if(this.data[name] == value){
4232             return;
4233         }
4234         this.dirty = true;
4235         if(!this.modified){
4236             this.modified = {};
4237         }
4238         if(typeof this.modified[name] == 'undefined'){
4239             this.modified[name] = this.data[name];
4240         }
4241         this.data[name] = value;
4242         if(!this.editing && this.store){
4243             this.store.afterEdit(this);
4244         }       
4245     },
4246
4247     /**
4248      * Get the value of the named field.
4249      * @param {String} name The name of the field to get the value of.
4250      * @return {Object} The value of the field.
4251      */
4252     get : function(name){
4253         return this.data[name]; 
4254     },
4255
4256     // private
4257     beginEdit : function(){
4258         this.editing = true;
4259         this.modified = {}; 
4260     },
4261
4262     // private
4263     cancelEdit : function(){
4264         this.editing = false;
4265         delete this.modified;
4266     },
4267
4268     // private
4269     endEdit : function(){
4270         this.editing = false;
4271         if(this.dirty && this.store){
4272             this.store.afterEdit(this);
4273         }
4274     },
4275
4276     /**
4277      * Usually called by the {@link Roo.data.Store} which owns the Record.
4278      * Rejects all changes made to the Record since either creation, or the last commit operation.
4279      * Modified fields are reverted to their original values.
4280      * <p>
4281      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4282      * of reject operations.
4283      */
4284     reject : function(){
4285         var m = this.modified;
4286         for(var n in m){
4287             if(typeof m[n] != "function"){
4288                 this.data[n] = m[n];
4289             }
4290         }
4291         this.dirty = false;
4292         delete this.modified;
4293         this.editing = false;
4294         if(this.store){
4295             this.store.afterReject(this);
4296         }
4297     },
4298
4299     /**
4300      * Usually called by the {@link Roo.data.Store} which owns the Record.
4301      * Commits all changes made to the Record since either creation, or the last commit operation.
4302      * <p>
4303      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4304      * of commit operations.
4305      */
4306     commit : function(){
4307         this.dirty = false;
4308         delete this.modified;
4309         this.editing = false;
4310         if(this.store){
4311             this.store.afterCommit(this);
4312         }
4313     },
4314
4315     // private
4316     hasError : function(){
4317         return this.error != null;
4318     },
4319
4320     // private
4321     clearError : function(){
4322         this.error = null;
4323     },
4324
4325     /**
4326      * Creates a copy of this record.
4327      * @param {String} id (optional) A new record id if you don't want to use this record's id
4328      * @return {Record}
4329      */
4330     copy : function(newId) {
4331         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4332     }
4333 };/*
4334  * Based on:
4335  * Ext JS Library 1.1.1
4336  * Copyright(c) 2006-2007, Ext JS, LLC.
4337  *
4338  * Originally Released Under LGPL - original licence link has changed is not relivant.
4339  *
4340  * Fork - LGPL
4341  * <script type="text/javascript">
4342  */
4343
4344
4345
4346 /**
4347  * @class Roo.data.Store
4348  * @extends Roo.util.Observable
4349  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4350  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4351  * <p>
4352  * 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
4353  * has no knowledge of the format of the data returned by the Proxy.<br>
4354  * <p>
4355  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4356  * instances from the data object. These records are cached and made available through accessor functions.
4357  * @constructor
4358  * Creates a new Store.
4359  * @param {Object} config A config object containing the objects needed for the Store to access data,
4360  * and read the data into Records.
4361  */
4362 Roo.data.Store = function(config){
4363     this.data = new Roo.util.MixedCollection(false);
4364     this.data.getKey = function(o){
4365         return o.id;
4366     };
4367     this.baseParams = {};
4368     // private
4369     this.paramNames = {
4370         "start" : "start",
4371         "limit" : "limit",
4372         "sort" : "sort",
4373         "dir" : "dir",
4374         "multisort" : "_multisort"
4375     };
4376
4377     if(config && config.data){
4378         this.inlineData = config.data;
4379         delete config.data;
4380     }
4381
4382     Roo.apply(this, config);
4383     
4384     if(this.reader){ // reader passed
4385         this.reader = Roo.factory(this.reader, Roo.data);
4386         this.reader.xmodule = this.xmodule || false;
4387         if(!this.recordType){
4388             this.recordType = this.reader.recordType;
4389         }
4390         if(this.reader.onMetaChange){
4391             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4392         }
4393     }
4394
4395     if(this.recordType){
4396         this.fields = this.recordType.prototype.fields;
4397     }
4398     this.modified = [];
4399
4400     this.addEvents({
4401         /**
4402          * @event datachanged
4403          * Fires when the data cache has changed, and a widget which is using this Store
4404          * as a Record cache should refresh its view.
4405          * @param {Store} this
4406          */
4407         datachanged : true,
4408         /**
4409          * @event metachange
4410          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4411          * @param {Store} this
4412          * @param {Object} meta The JSON metadata
4413          */
4414         metachange : true,
4415         /**
4416          * @event add
4417          * Fires when Records have been added to the Store
4418          * @param {Store} this
4419          * @param {Roo.data.Record[]} records The array of Records added
4420          * @param {Number} index The index at which the record(s) were added
4421          */
4422         add : true,
4423         /**
4424          * @event remove
4425          * Fires when a Record has been removed from the Store
4426          * @param {Store} this
4427          * @param {Roo.data.Record} record The Record that was removed
4428          * @param {Number} index The index at which the record was removed
4429          */
4430         remove : true,
4431         /**
4432          * @event update
4433          * Fires when a Record has been updated
4434          * @param {Store} this
4435          * @param {Roo.data.Record} record The Record that was updated
4436          * @param {String} operation The update operation being performed.  Value may be one of:
4437          * <pre><code>
4438  Roo.data.Record.EDIT
4439  Roo.data.Record.REJECT
4440  Roo.data.Record.COMMIT
4441          * </code></pre>
4442          */
4443         update : true,
4444         /**
4445          * @event clear
4446          * Fires when the data cache has been cleared.
4447          * @param {Store} this
4448          */
4449         clear : true,
4450         /**
4451          * @event beforeload
4452          * Fires before a request is made for a new data object.  If the beforeload handler returns false
4453          * the load action will be canceled.
4454          * @param {Store} this
4455          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4456          */
4457         beforeload : true,
4458         /**
4459          * @event beforeloadadd
4460          * Fires after a new set of Records has been loaded.
4461          * @param {Store} this
4462          * @param {Roo.data.Record[]} records The Records that were loaded
4463          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4464          */
4465         beforeloadadd : true,
4466         /**
4467          * @event load
4468          * Fires after a new set of Records has been loaded, before they are added to the store.
4469          * @param {Store} this
4470          * @param {Roo.data.Record[]} records The Records that were loaded
4471          * @param {Object} options The loading options that were specified (see {@link #load} for details)
4472          * @params {Object} return from reader
4473          */
4474         load : true,
4475         /**
4476          * @event loadexception
4477          * Fires if an exception occurs in the Proxy during loading.
4478          * Called with the signature of the Proxy's "loadexception" event.
4479          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4480          * 
4481          * @param {Proxy} 
4482          * @param {Object} return from JsonData.reader() - success, totalRecords, records
4483          * @param {Object} load options 
4484          * @param {Object} jsonData from your request (normally this contains the Exception)
4485          */
4486         loadexception : true
4487     });
4488     
4489     if(this.proxy){
4490         this.proxy = Roo.factory(this.proxy, Roo.data);
4491         this.proxy.xmodule = this.xmodule || false;
4492         this.relayEvents(this.proxy,  ["loadexception"]);
4493     }
4494     this.sortToggle = {};
4495     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4496
4497     Roo.data.Store.superclass.constructor.call(this);
4498
4499     if(this.inlineData){
4500         this.loadData(this.inlineData);
4501         delete this.inlineData;
4502     }
4503 };
4504
4505 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4506      /**
4507     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
4508     * without a remote query - used by combo/forms at present.
4509     */
4510     
4511     /**
4512     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4513     */
4514     /**
4515     * @cfg {Array} data Inline data to be loaded when the store is initialized.
4516     */
4517     /**
4518     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4519     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4520     */
4521     /**
4522     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4523     * on any HTTP request
4524     */
4525     /**
4526     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4527     */
4528     /**
4529     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4530     */
4531     multiSort: false,
4532     /**
4533     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4534     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4535     */
4536     remoteSort : false,
4537
4538     /**
4539     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4540      * loaded or when a record is removed. (defaults to false).
4541     */
4542     pruneModifiedRecords : false,
4543
4544     // private
4545     lastOptions : null,
4546
4547     /**
4548      * Add Records to the Store and fires the add event.
4549      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4550      */
4551     add : function(records){
4552         records = [].concat(records);
4553         for(var i = 0, len = records.length; i < len; i++){
4554             records[i].join(this);
4555         }
4556         var index = this.data.length;
4557         this.data.addAll(records);
4558         this.fireEvent("add", this, records, index);
4559     },
4560
4561     /**
4562      * Remove a Record from the Store and fires the remove event.
4563      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4564      */
4565     remove : function(record){
4566         var index = this.data.indexOf(record);
4567         this.data.removeAt(index);
4568         if(this.pruneModifiedRecords){
4569             this.modified.remove(record);
4570         }
4571         this.fireEvent("remove", this, record, index);
4572     },
4573
4574     /**
4575      * Remove all Records from the Store and fires the clear event.
4576      */
4577     removeAll : function(){
4578         this.data.clear();
4579         if(this.pruneModifiedRecords){
4580             this.modified = [];
4581         }
4582         this.fireEvent("clear", this);
4583     },
4584
4585     /**
4586      * Inserts Records to the Store at the given index and fires the add event.
4587      * @param {Number} index The start index at which to insert the passed Records.
4588      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4589      */
4590     insert : function(index, records){
4591         records = [].concat(records);
4592         for(var i = 0, len = records.length; i < len; i++){
4593             this.data.insert(index, records[i]);
4594             records[i].join(this);
4595         }
4596         this.fireEvent("add", this, records, index);
4597     },
4598
4599     /**
4600      * Get the index within the cache of the passed Record.
4601      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4602      * @return {Number} The index of the passed Record. Returns -1 if not found.
4603      */
4604     indexOf : function(record){
4605         return this.data.indexOf(record);
4606     },
4607
4608     /**
4609      * Get the index within the cache of the Record with the passed id.
4610      * @param {String} id The id of the Record to find.
4611      * @return {Number} The index of the Record. Returns -1 if not found.
4612      */
4613     indexOfId : function(id){
4614         return this.data.indexOfKey(id);
4615     },
4616
4617     /**
4618      * Get the Record with the specified id.
4619      * @param {String} id The id of the Record to find.
4620      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4621      */
4622     getById : function(id){
4623         return this.data.key(id);
4624     },
4625
4626     /**
4627      * Get the Record at the specified index.
4628      * @param {Number} index The index of the Record to find.
4629      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4630      */
4631     getAt : function(index){
4632         return this.data.itemAt(index);
4633     },
4634
4635     /**
4636      * Returns a range of Records between specified indices.
4637      * @param {Number} startIndex (optional) The starting index (defaults to 0)
4638      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4639      * @return {Roo.data.Record[]} An array of Records
4640      */
4641     getRange : function(start, end){
4642         return this.data.getRange(start, end);
4643     },
4644
4645     // private
4646     storeOptions : function(o){
4647         o = Roo.apply({}, o);
4648         delete o.callback;
4649         delete o.scope;
4650         this.lastOptions = o;
4651     },
4652
4653     /**
4654      * Loads the Record cache from the configured Proxy using the configured Reader.
4655      * <p>
4656      * If using remote paging, then the first load call must specify the <em>start</em>
4657      * and <em>limit</em> properties in the options.params property to establish the initial
4658      * position within the dataset, and the number of Records to cache on each read from the Proxy.
4659      * <p>
4660      * <strong>It is important to note that for remote data sources, loading is asynchronous,
4661      * and this call will return before the new data has been loaded. Perform any post-processing
4662      * in a callback function, or in a "load" event handler.</strong>
4663      * <p>
4664      * @param {Object} options An object containing properties which control loading options:<ul>
4665      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4666      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4667      * passed the following arguments:<ul>
4668      * <li>r : Roo.data.Record[]</li>
4669      * <li>options: Options object from the load call</li>
4670      * <li>success: Boolean success indicator</li></ul></li>
4671      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4672      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4673      * </ul>
4674      */
4675     load : function(options){
4676         options = options || {};
4677         if(this.fireEvent("beforeload", this, options) !== false){
4678             this.storeOptions(options);
4679             var p = Roo.apply(options.params || {}, this.baseParams);
4680             // if meta was not loaded from remote source.. try requesting it.
4681             if (!this.reader.metaFromRemote) {
4682                 p._requestMeta = 1;
4683             }
4684             if(this.sortInfo && this.remoteSort){
4685                 var pn = this.paramNames;
4686                 p[pn["sort"]] = this.sortInfo.field;
4687                 p[pn["dir"]] = this.sortInfo.direction;
4688             }
4689             if (this.multiSort) {
4690                 var pn = this.paramNames;
4691                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
4692             }
4693             
4694             this.proxy.load(p, this.reader, this.loadRecords, this, options);
4695         }
4696     },
4697
4698     /**
4699      * Reloads the Record cache from the configured Proxy using the configured Reader and
4700      * the options from the last load operation performed.
4701      * @param {Object} options (optional) An object containing properties which may override the options
4702      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
4703      * the most recently used options are reused).
4704      */
4705     reload : function(options){
4706         this.load(Roo.applyIf(options||{}, this.lastOptions));
4707     },
4708
4709     // private
4710     // Called as a callback by the Reader during a load operation.
4711     loadRecords : function(o, options, success){
4712         if(!o || success === false){
4713             if(success !== false){
4714                 this.fireEvent("load", this, [], options, o);
4715             }
4716             if(options.callback){
4717                 options.callback.call(options.scope || this, [], options, false);
4718             }
4719             return;
4720         }
4721         // if data returned failure - throw an exception.
4722         if (o.success === false) {
4723             // show a message if no listener is registered.
4724             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
4725                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
4726             }
4727             // loadmask wil be hooked into this..
4728             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
4729             return;
4730         }
4731         var r = o.records, t = o.totalRecords || r.length;
4732         
4733         this.fireEvent("beforeloadadd", this, r, options, o);
4734         
4735         if(!options || options.add !== true){
4736             if(this.pruneModifiedRecords){
4737                 this.modified = [];
4738             }
4739             for(var i = 0, len = r.length; i < len; i++){
4740                 r[i].join(this);
4741             }
4742             if(this.snapshot){
4743                 this.data = this.snapshot;
4744                 delete this.snapshot;
4745             }
4746             this.data.clear();
4747             this.data.addAll(r);
4748             this.totalLength = t;
4749             this.applySort();
4750             this.fireEvent("datachanged", this);
4751         }else{
4752             this.totalLength = Math.max(t, this.data.length+r.length);
4753             this.add(r);
4754         }
4755         this.fireEvent("load", this, r, options, o);
4756         if(options.callback){
4757             options.callback.call(options.scope || this, r, options, true);
4758         }
4759     },
4760
4761
4762     /**
4763      * Loads data from a passed data block. A Reader which understands the format of the data
4764      * must have been configured in the constructor.
4765      * @param {Object} data The data block from which to read the Records.  The format of the data expected
4766      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
4767      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
4768      */
4769     loadData : function(o, append){
4770         var r = this.reader.readRecords(o);
4771         this.loadRecords(r, {add: append}, true);
4772     },
4773
4774     /**
4775      * Gets the number of cached records.
4776      * <p>
4777      * <em>If using paging, this may not be the total size of the dataset. If the data object
4778      * used by the Reader contains the dataset size, then the getTotalCount() function returns
4779      * the data set size</em>
4780      */
4781     getCount : function(){
4782         return this.data.length || 0;
4783     },
4784
4785     /**
4786      * Gets the total number of records in the dataset as returned by the server.
4787      * <p>
4788      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
4789      * the dataset size</em>
4790      */
4791     getTotalCount : function(){
4792         return this.totalLength || 0;
4793     },
4794
4795     /**
4796      * Returns the sort state of the Store as an object with two properties:
4797      * <pre><code>
4798  field {String} The name of the field by which the Records are sorted
4799  direction {String} The sort order, "ASC" or "DESC"
4800      * </code></pre>
4801      */
4802     getSortState : function(){
4803         return this.sortInfo;
4804     },
4805
4806     // private
4807     applySort : function(){
4808         if(this.sortInfo && !this.remoteSort){
4809             var s = this.sortInfo, f = s.field;
4810             var st = this.fields.get(f).sortType;
4811             var fn = function(r1, r2){
4812                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
4813                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
4814             };
4815             this.data.sort(s.direction, fn);
4816             if(this.snapshot && this.snapshot != this.data){
4817                 this.snapshot.sort(s.direction, fn);
4818             }
4819         }
4820     },
4821
4822     /**
4823      * Sets the default sort column and order to be used by the next load operation.
4824      * @param {String} fieldName The name of the field to sort by.
4825      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4826      */
4827     setDefaultSort : function(field, dir){
4828         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
4829     },
4830
4831     /**
4832      * Sort the Records.
4833      * If remote sorting is used, the sort is performed on the server, and the cache is
4834      * reloaded. If local sorting is used, the cache is sorted internally.
4835      * @param {String} fieldName The name of the field to sort by.
4836      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
4837      */
4838     sort : function(fieldName, dir){
4839         var f = this.fields.get(fieldName);
4840         if(!dir){
4841             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
4842             
4843             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
4844                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
4845             }else{
4846                 dir = f.sortDir;
4847             }
4848         }
4849         this.sortToggle[f.name] = dir;
4850         this.sortInfo = {field: f.name, direction: dir};
4851         if(!this.remoteSort){
4852             this.applySort();
4853             this.fireEvent("datachanged", this);
4854         }else{
4855             this.load(this.lastOptions);
4856         }
4857     },
4858
4859     /**
4860      * Calls the specified function for each of the Records in the cache.
4861      * @param {Function} fn The function to call. The Record is passed as the first parameter.
4862      * Returning <em>false</em> aborts and exits the iteration.
4863      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
4864      */
4865     each : function(fn, scope){
4866         this.data.each(fn, scope);
4867     },
4868
4869     /**
4870      * Gets all records modified since the last commit.  Modified records are persisted across load operations
4871      * (e.g., during paging).
4872      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
4873      */
4874     getModifiedRecords : function(){
4875         return this.modified;
4876     },
4877
4878     // private
4879     createFilterFn : function(property, value, anyMatch){
4880         if(!value.exec){ // not a regex
4881             value = String(value);
4882             if(value.length == 0){
4883                 return false;
4884             }
4885             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
4886         }
4887         return function(r){
4888             return value.test(r.data[property]);
4889         };
4890     },
4891
4892     /**
4893      * Sums the value of <i>property</i> for each record between start and end and returns the result.
4894      * @param {String} property A field on your records
4895      * @param {Number} start The record index to start at (defaults to 0)
4896      * @param {Number} end The last record index to include (defaults to length - 1)
4897      * @return {Number} The sum
4898      */
4899     sum : function(property, start, end){
4900         var rs = this.data.items, v = 0;
4901         start = start || 0;
4902         end = (end || end === 0) ? end : rs.length-1;
4903
4904         for(var i = start; i <= end; i++){
4905             v += (rs[i].data[property] || 0);
4906         }
4907         return v;
4908     },
4909
4910     /**
4911      * Filter the records by a specified property.
4912      * @param {String} field A field on your records
4913      * @param {String/RegExp} value Either a string that the field
4914      * should start with or a RegExp to test against the field
4915      * @param {Boolean} anyMatch True to match any part not just the beginning
4916      */
4917     filter : function(property, value, anyMatch){
4918         var fn = this.createFilterFn(property, value, anyMatch);
4919         return fn ? this.filterBy(fn) : this.clearFilter();
4920     },
4921
4922     /**
4923      * Filter by a function. The specified function will be called with each
4924      * record in this data source. If the function returns true the record is included,
4925      * otherwise it is filtered.
4926      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4927      * @param {Object} scope (optional) The scope of the function (defaults to this)
4928      */
4929     filterBy : function(fn, scope){
4930         this.snapshot = this.snapshot || this.data;
4931         this.data = this.queryBy(fn, scope||this);
4932         this.fireEvent("datachanged", this);
4933     },
4934
4935     /**
4936      * Query the records by a specified property.
4937      * @param {String} field A field on your records
4938      * @param {String/RegExp} value Either a string that the field
4939      * should start with or a RegExp to test against the field
4940      * @param {Boolean} anyMatch True to match any part not just the beginning
4941      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4942      */
4943     query : function(property, value, anyMatch){
4944         var fn = this.createFilterFn(property, value, anyMatch);
4945         return fn ? this.queryBy(fn) : this.data.clone();
4946     },
4947
4948     /**
4949      * Query by a function. The specified function will be called with each
4950      * record in this data source. If the function returns true the record is included
4951      * in the results.
4952      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
4953      * @param {Object} scope (optional) The scope of the function (defaults to this)
4954       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
4955      **/
4956     queryBy : function(fn, scope){
4957         var data = this.snapshot || this.data;
4958         return data.filterBy(fn, scope||this);
4959     },
4960
4961     /**
4962      * Collects unique values for a particular dataIndex from this store.
4963      * @param {String} dataIndex The property to collect
4964      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
4965      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
4966      * @return {Array} An array of the unique values
4967      **/
4968     collect : function(dataIndex, allowNull, bypassFilter){
4969         var d = (bypassFilter === true && this.snapshot) ?
4970                 this.snapshot.items : this.data.items;
4971         var v, sv, r = [], l = {};
4972         for(var i = 0, len = d.length; i < len; i++){
4973             v = d[i].data[dataIndex];
4974             sv = String(v);
4975             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
4976                 l[sv] = true;
4977                 r[r.length] = v;
4978             }
4979         }
4980         return r;
4981     },
4982
4983     /**
4984      * Revert to a view of the Record cache with no filtering applied.
4985      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
4986      */
4987     clearFilter : function(suppressEvent){
4988         if(this.snapshot && this.snapshot != this.data){
4989             this.data = this.snapshot;
4990             delete this.snapshot;
4991             if(suppressEvent !== true){
4992                 this.fireEvent("datachanged", this);
4993             }
4994         }
4995     },
4996
4997     // private
4998     afterEdit : function(record){
4999         if(this.modified.indexOf(record) == -1){
5000             this.modified.push(record);
5001         }
5002         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5003     },
5004     
5005     // private
5006     afterReject : function(record){
5007         this.modified.remove(record);
5008         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5009     },
5010
5011     // private
5012     afterCommit : function(record){
5013         this.modified.remove(record);
5014         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5015     },
5016
5017     /**
5018      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5019      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5020      */
5021     commitChanges : function(){
5022         var m = this.modified.slice(0);
5023         this.modified = [];
5024         for(var i = 0, len = m.length; i < len; i++){
5025             m[i].commit();
5026         }
5027     },
5028
5029     /**
5030      * Cancel outstanding changes on all changed records.
5031      */
5032     rejectChanges : function(){
5033         var m = this.modified.slice(0);
5034         this.modified = [];
5035         for(var i = 0, len = m.length; i < len; i++){
5036             m[i].reject();
5037         }
5038     },
5039
5040     onMetaChange : function(meta, rtype, o){
5041         this.recordType = rtype;
5042         this.fields = rtype.prototype.fields;
5043         delete this.snapshot;
5044         this.sortInfo = meta.sortInfo || this.sortInfo;
5045         this.modified = [];
5046         this.fireEvent('metachange', this, this.reader.meta);
5047     }
5048 });/*
5049  * Based on:
5050  * Ext JS Library 1.1.1
5051  * Copyright(c) 2006-2007, Ext JS, LLC.
5052  *
5053  * Originally Released Under LGPL - original licence link has changed is not relivant.
5054  *
5055  * Fork - LGPL
5056  * <script type="text/javascript">
5057  */
5058
5059 /**
5060  * @class Roo.data.SimpleStore
5061  * @extends Roo.data.Store
5062  * Small helper class to make creating Stores from Array data easier.
5063  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5064  * @cfg {Array} fields An array of field definition objects, or field name strings.
5065  * @cfg {Array} data The multi-dimensional array of data
5066  * @constructor
5067  * @param {Object} config
5068  */
5069 Roo.data.SimpleStore = function(config){
5070     Roo.data.SimpleStore.superclass.constructor.call(this, {
5071         isLocal : true,
5072         reader: new Roo.data.ArrayReader({
5073                 id: config.id
5074             },
5075             Roo.data.Record.create(config.fields)
5076         ),
5077         proxy : new Roo.data.MemoryProxy(config.data)
5078     });
5079     this.load();
5080 };
5081 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5082  * Based on:
5083  * Ext JS Library 1.1.1
5084  * Copyright(c) 2006-2007, Ext JS, LLC.
5085  *
5086  * Originally Released Under LGPL - original licence link has changed is not relivant.
5087  *
5088  * Fork - LGPL
5089  * <script type="text/javascript">
5090  */
5091
5092 /**
5093 /**
5094  * @extends Roo.data.Store
5095  * @class Roo.data.JsonStore
5096  * Small helper class to make creating Stores for JSON data easier. <br/>
5097 <pre><code>
5098 var store = new Roo.data.JsonStore({
5099     url: 'get-images.php',
5100     root: 'images',
5101     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5102 });
5103 </code></pre>
5104  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5105  * JsonReader and HttpProxy (unless inline data is provided).</b>
5106  * @cfg {Array} fields An array of field definition objects, or field name strings.
5107  * @constructor
5108  * @param {Object} config
5109  */
5110 Roo.data.JsonStore = function(c){
5111     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5112         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5113         reader: new Roo.data.JsonReader(c, c.fields)
5114     }));
5115 };
5116 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5117  * Based on:
5118  * Ext JS Library 1.1.1
5119  * Copyright(c) 2006-2007, Ext JS, LLC.
5120  *
5121  * Originally Released Under LGPL - original licence link has changed is not relivant.
5122  *
5123  * Fork - LGPL
5124  * <script type="text/javascript">
5125  */
5126
5127  
5128 Roo.data.Field = function(config){
5129     if(typeof config == "string"){
5130         config = {name: config};
5131     }
5132     Roo.apply(this, config);
5133     
5134     if(!this.type){
5135         this.type = "auto";
5136     }
5137     
5138     var st = Roo.data.SortTypes;
5139     // named sortTypes are supported, here we look them up
5140     if(typeof this.sortType == "string"){
5141         this.sortType = st[this.sortType];
5142     }
5143     
5144     // set default sortType for strings and dates
5145     if(!this.sortType){
5146         switch(this.type){
5147             case "string":
5148                 this.sortType = st.asUCString;
5149                 break;
5150             case "date":
5151                 this.sortType = st.asDate;
5152                 break;
5153             default:
5154                 this.sortType = st.none;
5155         }
5156     }
5157
5158     // define once
5159     var stripRe = /[\$,%]/g;
5160
5161     // prebuilt conversion function for this field, instead of
5162     // switching every time we're reading a value
5163     if(!this.convert){
5164         var cv, dateFormat = this.dateFormat;
5165         switch(this.type){
5166             case "":
5167             case "auto":
5168             case undefined:
5169                 cv = function(v){ return v; };
5170                 break;
5171             case "string":
5172                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5173                 break;
5174             case "int":
5175                 cv = function(v){
5176                     return v !== undefined && v !== null && v !== '' ?
5177                            parseInt(String(v).replace(stripRe, ""), 10) : '';
5178                     };
5179                 break;
5180             case "float":
5181                 cv = function(v){
5182                     return v !== undefined && v !== null && v !== '' ?
5183                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
5184                     };
5185                 break;
5186             case "bool":
5187             case "boolean":
5188                 cv = function(v){ return v === true || v === "true" || v == 1; };
5189                 break;
5190             case "date":
5191                 cv = function(v){
5192                     if(!v){
5193                         return '';
5194                     }
5195                     if(v instanceof Date){
5196                         return v;
5197                     }
5198                     if(dateFormat){
5199                         if(dateFormat == "timestamp"){
5200                             return new Date(v*1000);
5201                         }
5202                         return Date.parseDate(v, dateFormat);
5203                     }
5204                     var parsed = Date.parse(v);
5205                     return parsed ? new Date(parsed) : null;
5206                 };
5207              break;
5208             
5209         }
5210         this.convert = cv;
5211     }
5212 };
5213
5214 Roo.data.Field.prototype = {
5215     dateFormat: null,
5216     defaultValue: "",
5217     mapping: null,
5218     sortType : null,
5219     sortDir : "ASC"
5220 };/*
5221  * Based on:
5222  * Ext JS Library 1.1.1
5223  * Copyright(c) 2006-2007, Ext JS, LLC.
5224  *
5225  * Originally Released Under LGPL - original licence link has changed is not relivant.
5226  *
5227  * Fork - LGPL
5228  * <script type="text/javascript">
5229  */
5230  
5231 // Base class for reading structured data from a data source.  This class is intended to be
5232 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5233
5234 /**
5235  * @class Roo.data.DataReader
5236  * Base class for reading structured data from a data source.  This class is intended to be
5237  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5238  */
5239
5240 Roo.data.DataReader = function(meta, recordType){
5241     
5242     this.meta = meta;
5243     
5244     this.recordType = recordType instanceof Array ? 
5245         Roo.data.Record.create(recordType) : recordType;
5246 };
5247
5248 Roo.data.DataReader.prototype = {
5249      /**
5250      * Create an empty record
5251      * @param {Object} data (optional) - overlay some values
5252      * @return {Roo.data.Record} record created.
5253      */
5254     newRow :  function(d) {
5255         var da =  {};
5256         this.recordType.prototype.fields.each(function(c) {
5257             switch( c.type) {
5258                 case 'int' : da[c.name] = 0; break;
5259                 case 'date' : da[c.name] = new Date(); break;
5260                 case 'float' : da[c.name] = 0.0; break;
5261                 case 'boolean' : da[c.name] = false; break;
5262                 default : da[c.name] = ""; break;
5263             }
5264             
5265         });
5266         return new this.recordType(Roo.apply(da, d));
5267     }
5268     
5269 };/*
5270  * Based on:
5271  * Ext JS Library 1.1.1
5272  * Copyright(c) 2006-2007, Ext JS, LLC.
5273  *
5274  * Originally Released Under LGPL - original licence link has changed is not relivant.
5275  *
5276  * Fork - LGPL
5277  * <script type="text/javascript">
5278  */
5279
5280 /**
5281  * @class Roo.data.DataProxy
5282  * @extends Roo.data.Observable
5283  * This class is an abstract base class for implementations which provide retrieval of
5284  * unformatted data objects.<br>
5285  * <p>
5286  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5287  * (of the appropriate type which knows how to parse the data object) to provide a block of
5288  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5289  * <p>
5290  * Custom implementations must implement the load method as described in
5291  * {@link Roo.data.HttpProxy#load}.
5292  */
5293 Roo.data.DataProxy = function(){
5294     this.addEvents({
5295         /**
5296          * @event beforeload
5297          * Fires before a network request is made to retrieve a data object.
5298          * @param {Object} This DataProxy object.
5299          * @param {Object} params The params parameter to the load function.
5300          */
5301         beforeload : true,
5302         /**
5303          * @event load
5304          * Fires before the load method's callback is called.
5305          * @param {Object} This DataProxy object.
5306          * @param {Object} o The data object.
5307          * @param {Object} arg The callback argument object passed to the load function.
5308          */
5309         load : true,
5310         /**
5311          * @event loadexception
5312          * Fires if an Exception occurs during data retrieval.
5313          * @param {Object} This DataProxy object.
5314          * @param {Object} o The data object.
5315          * @param {Object} arg The callback argument object passed to the load function.
5316          * @param {Object} e The Exception.
5317          */
5318         loadexception : true
5319     });
5320     Roo.data.DataProxy.superclass.constructor.call(this);
5321 };
5322
5323 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5324
5325     /**
5326      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5327      */
5328 /*
5329  * Based on:
5330  * Ext JS Library 1.1.1
5331  * Copyright(c) 2006-2007, Ext JS, LLC.
5332  *
5333  * Originally Released Under LGPL - original licence link has changed is not relivant.
5334  *
5335  * Fork - LGPL
5336  * <script type="text/javascript">
5337  */
5338 /**
5339  * @class Roo.data.MemoryProxy
5340  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5341  * to the Reader when its load method is called.
5342  * @constructor
5343  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5344  */
5345 Roo.data.MemoryProxy = function(data){
5346     if (data.data) {
5347         data = data.data;
5348     }
5349     Roo.data.MemoryProxy.superclass.constructor.call(this);
5350     this.data = data;
5351 };
5352
5353 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5354     /**
5355      * Load data from the requested source (in this case an in-memory
5356      * data object passed to the constructor), read the data object into
5357      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5358      * process that block using the passed callback.
5359      * @param {Object} params This parameter is not used by the MemoryProxy class.
5360      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5361      * object into a block of Roo.data.Records.
5362      * @param {Function} callback The function into which to pass the block of Roo.data.records.
5363      * The function must be passed <ul>
5364      * <li>The Record block object</li>
5365      * <li>The "arg" argument from the load function</li>
5366      * <li>A boolean success indicator</li>
5367      * </ul>
5368      * @param {Object} scope The scope in which to call the callback
5369      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5370      */
5371     load : function(params, reader, callback, scope, arg){
5372         params = params || {};
5373         var result;
5374         try {
5375             result = reader.readRecords(this.data);
5376         }catch(e){
5377             this.fireEvent("loadexception", this, arg, null, e);
5378             callback.call(scope, null, arg, false);
5379             return;
5380         }
5381         callback.call(scope, result, arg, true);
5382     },
5383     
5384     // private
5385     update : function(params, records){
5386         
5387     }
5388 });/*
5389  * Based on:
5390  * Ext JS Library 1.1.1
5391  * Copyright(c) 2006-2007, Ext JS, LLC.
5392  *
5393  * Originally Released Under LGPL - original licence link has changed is not relivant.
5394  *
5395  * Fork - LGPL
5396  * <script type="text/javascript">
5397  */
5398 /**
5399  * @class Roo.data.HttpProxy
5400  * @extends Roo.data.DataProxy
5401  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5402  * configured to reference a certain URL.<br><br>
5403  * <p>
5404  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5405  * from which the running page was served.<br><br>
5406  * <p>
5407  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5408  * <p>
5409  * Be aware that to enable the browser to parse an XML document, the server must set
5410  * the Content-Type header in the HTTP response to "text/xml".
5411  * @constructor
5412  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5413  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
5414  * will be used to make the request.
5415  */
5416 Roo.data.HttpProxy = function(conn){
5417     Roo.data.HttpProxy.superclass.constructor.call(this);
5418     // is conn a conn config or a real conn?
5419     this.conn = conn;
5420     this.useAjax = !conn || !conn.events;
5421   
5422 };
5423
5424 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5425     // thse are take from connection...
5426     
5427     /**
5428      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5429      */
5430     /**
5431      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5432      * extra parameters to each request made by this object. (defaults to undefined)
5433      */
5434     /**
5435      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5436      *  to each request made by this object. (defaults to undefined)
5437      */
5438     /**
5439      * @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)
5440      */
5441     /**
5442      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5443      */
5444      /**
5445      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5446      * @type Boolean
5447      */
5448   
5449
5450     /**
5451      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5452      * @type Boolean
5453      */
5454     /**
5455      * Return the {@link Roo.data.Connection} object being used by this Proxy.
5456      * @return {Connection} The Connection object. This object may be used to subscribe to events on
5457      * a finer-grained basis than the DataProxy events.
5458      */
5459     getConnection : function(){
5460         return this.useAjax ? Roo.Ajax : this.conn;
5461     },
5462
5463     /**
5464      * Load data from the configured {@link Roo.data.Connection}, read the data object into
5465      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5466      * process that block using the passed callback.
5467      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5468      * for the request to the remote server.
5469      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5470      * object into a block of Roo.data.Records.
5471      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5472      * The function must be passed <ul>
5473      * <li>The Record block object</li>
5474      * <li>The "arg" argument from the load function</li>
5475      * <li>A boolean success indicator</li>
5476      * </ul>
5477      * @param {Object} scope The scope in which to call the callback
5478      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5479      */
5480     load : function(params, reader, callback, scope, arg){
5481         if(this.fireEvent("beforeload", this, params) !== false){
5482             var  o = {
5483                 params : params || {},
5484                 request: {
5485                     callback : callback,
5486                     scope : scope,
5487                     arg : arg
5488                 },
5489                 reader: reader,
5490                 callback : this.loadResponse,
5491                 scope: this
5492             };
5493             if(this.useAjax){
5494                 Roo.applyIf(o, this.conn);
5495                 if(this.activeRequest){
5496                     Roo.Ajax.abort(this.activeRequest);
5497                 }
5498                 this.activeRequest = Roo.Ajax.request(o);
5499             }else{
5500                 this.conn.request(o);
5501             }
5502         }else{
5503             callback.call(scope||this, null, arg, false);
5504         }
5505     },
5506
5507     // private
5508     loadResponse : function(o, success, response){
5509         delete this.activeRequest;
5510         if(!success){
5511             this.fireEvent("loadexception", this, o, response);
5512             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5513             return;
5514         }
5515         var result;
5516         try {
5517             result = o.reader.read(response);
5518         }catch(e){
5519             this.fireEvent("loadexception", this, o, response, e);
5520             o.request.callback.call(o.request.scope, null, o.request.arg, false);
5521             return;
5522         }
5523         
5524         this.fireEvent("load", this, o, o.request.arg);
5525         o.request.callback.call(o.request.scope, result, o.request.arg, true);
5526     },
5527
5528     // private
5529     update : function(dataSet){
5530
5531     },
5532
5533     // private
5534     updateResponse : function(dataSet){
5535
5536     }
5537 });/*
5538  * Based on:
5539  * Ext JS Library 1.1.1
5540  * Copyright(c) 2006-2007, Ext JS, LLC.
5541  *
5542  * Originally Released Under LGPL - original licence link has changed is not relivant.
5543  *
5544  * Fork - LGPL
5545  * <script type="text/javascript">
5546  */
5547
5548 /**
5549  * @class Roo.data.ScriptTagProxy
5550  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5551  * other than the originating domain of the running page.<br><br>
5552  * <p>
5553  * <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
5554  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5555  * <p>
5556  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5557  * source code that is used as the source inside a &lt;script> tag.<br><br>
5558  * <p>
5559  * In order for the browser to process the returned data, the server must wrap the data object
5560  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5561  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5562  * depending on whether the callback name was passed:
5563  * <p>
5564  * <pre><code>
5565 boolean scriptTag = false;
5566 String cb = request.getParameter("callback");
5567 if (cb != null) {
5568     scriptTag = true;
5569     response.setContentType("text/javascript");
5570 } else {
5571     response.setContentType("application/x-json");
5572 }
5573 Writer out = response.getWriter();
5574 if (scriptTag) {
5575     out.write(cb + "(");
5576 }
5577 out.print(dataBlock.toJsonString());
5578 if (scriptTag) {
5579     out.write(");");
5580 }
5581 </pre></code>
5582  *
5583  * @constructor
5584  * @param {Object} config A configuration object.
5585  */
5586 Roo.data.ScriptTagProxy = function(config){
5587     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5588     Roo.apply(this, config);
5589     this.head = document.getElementsByTagName("head")[0];
5590 };
5591
5592 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5593
5594 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5595     /**
5596      * @cfg {String} url The URL from which to request the data object.
5597      */
5598     /**
5599      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5600      */
5601     timeout : 30000,
5602     /**
5603      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5604      * the server the name of the callback function set up by the load call to process the returned data object.
5605      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5606      * javascript output which calls this named function passing the data object as its only parameter.
5607      */
5608     callbackParam : "callback",
5609     /**
5610      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5611      * name to the request.
5612      */
5613     nocache : true,
5614
5615     /**
5616      * Load data from the configured URL, read the data object into
5617      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5618      * process that block using the passed callback.
5619      * @param {Object} params An object containing properties which are to be used as HTTP parameters
5620      * for the request to the remote server.
5621      * @param {Roo.data.DataReader} reader The Reader object which converts the data
5622      * object into a block of Roo.data.Records.
5623      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5624      * The function must be passed <ul>
5625      * <li>The Record block object</li>
5626      * <li>The "arg" argument from the load function</li>
5627      * <li>A boolean success indicator</li>
5628      * </ul>
5629      * @param {Object} scope The scope in which to call the callback
5630      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5631      */
5632     load : function(params, reader, callback, scope, arg){
5633         if(this.fireEvent("beforeload", this, params) !== false){
5634
5635             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5636
5637             var url = this.url;
5638             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5639             if(this.nocache){
5640                 url += "&_dc=" + (new Date().getTime());
5641             }
5642             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5643             var trans = {
5644                 id : transId,
5645                 cb : "stcCallback"+transId,
5646                 scriptId : "stcScript"+transId,
5647                 params : params,
5648                 arg : arg,
5649                 url : url,
5650                 callback : callback,
5651                 scope : scope,
5652                 reader : reader
5653             };
5654             var conn = this;
5655
5656             window[trans.cb] = function(o){
5657                 conn.handleResponse(o, trans);
5658             };
5659
5660             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5661
5662             if(this.autoAbort !== false){
5663                 this.abort();
5664             }
5665
5666             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5667
5668             var script = document.createElement("script");
5669             script.setAttribute("src", url);
5670             script.setAttribute("type", "text/javascript");
5671             script.setAttribute("id", trans.scriptId);
5672             this.head.appendChild(script);
5673
5674             this.trans = trans;
5675         }else{
5676             callback.call(scope||this, null, arg, false);
5677         }
5678     },
5679
5680     // private
5681     isLoading : function(){
5682         return this.trans ? true : false;
5683     },
5684
5685     /**
5686      * Abort the current server request.
5687      */
5688     abort : function(){
5689         if(this.isLoading()){
5690             this.destroyTrans(this.trans);
5691         }
5692     },
5693
5694     // private
5695     destroyTrans : function(trans, isLoaded){
5696         this.head.removeChild(document.getElementById(trans.scriptId));
5697         clearTimeout(trans.timeoutId);
5698         if(isLoaded){
5699             window[trans.cb] = undefined;
5700             try{
5701                 delete window[trans.cb];
5702             }catch(e){}
5703         }else{
5704             // if hasn't been loaded, wait for load to remove it to prevent script error
5705             window[trans.cb] = function(){
5706                 window[trans.cb] = undefined;
5707                 try{
5708                     delete window[trans.cb];
5709                 }catch(e){}
5710             };
5711         }
5712     },
5713
5714     // private
5715     handleResponse : function(o, trans){
5716         this.trans = false;
5717         this.destroyTrans(trans, true);
5718         var result;
5719         try {
5720             result = trans.reader.readRecords(o);
5721         }catch(e){
5722             this.fireEvent("loadexception", this, o, trans.arg, e);
5723             trans.callback.call(trans.scope||window, null, trans.arg, false);
5724             return;
5725         }
5726         this.fireEvent("load", this, o, trans.arg);
5727         trans.callback.call(trans.scope||window, result, trans.arg, true);
5728     },
5729
5730     // private
5731     handleFailure : function(trans){
5732         this.trans = false;
5733         this.destroyTrans(trans, false);
5734         this.fireEvent("loadexception", this, null, trans.arg);
5735         trans.callback.call(trans.scope||window, null, trans.arg, false);
5736     }
5737 });/*
5738  * Based on:
5739  * Ext JS Library 1.1.1
5740  * Copyright(c) 2006-2007, Ext JS, LLC.
5741  *
5742  * Originally Released Under LGPL - original licence link has changed is not relivant.
5743  *
5744  * Fork - LGPL
5745  * <script type="text/javascript">
5746  */
5747
5748 /**
5749  * @class Roo.data.JsonReader
5750  * @extends Roo.data.DataReader
5751  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
5752  * based on mappings in a provided Roo.data.Record constructor.
5753  * 
5754  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
5755  * in the reply previously. 
5756  * 
5757  * <p>
5758  * Example code:
5759  * <pre><code>
5760 var RecordDef = Roo.data.Record.create([
5761     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
5762     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
5763 ]);
5764 var myReader = new Roo.data.JsonReader({
5765     totalProperty: "results",    // The property which contains the total dataset size (optional)
5766     root: "rows",                // The property which contains an Array of row objects
5767     id: "id"                     // The property within each row object that provides an ID for the record (optional)
5768 }, RecordDef);
5769 </code></pre>
5770  * <p>
5771  * This would consume a JSON file like this:
5772  * <pre><code>
5773 { 'results': 2, 'rows': [
5774     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
5775     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
5776 }
5777 </code></pre>
5778  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
5779  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
5780  * paged from the remote server.
5781  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
5782  * @cfg {String} root name of the property which contains the Array of row objects.
5783  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
5784  * @constructor
5785  * Create a new JsonReader
5786  * @param {Object} meta Metadata configuration options
5787  * @param {Object} recordType Either an Array of field definition objects,
5788  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
5789  */
5790 Roo.data.JsonReader = function(meta, recordType){
5791     
5792     meta = meta || {};
5793     // set some defaults:
5794     Roo.applyIf(meta, {
5795         totalProperty: 'total',
5796         successProperty : 'success',
5797         root : 'data',
5798         id : 'id'
5799     });
5800     
5801     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
5802 };
5803 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
5804     
5805     /**
5806      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
5807      * Used by Store query builder to append _requestMeta to params.
5808      * 
5809      */
5810     metaFromRemote : false,
5811     /**
5812      * This method is only used by a DataProxy which has retrieved data from a remote server.
5813      * @param {Object} response The XHR object which contains the JSON data in its responseText.
5814      * @return {Object} data A data block which is used by an Roo.data.Store object as
5815      * a cache of Roo.data.Records.
5816      */
5817     read : function(response){
5818         var json = response.responseText;
5819        
5820         var o = /* eval:var:o */ eval("("+json+")");
5821         if(!o) {
5822             throw {message: "JsonReader.read: Json object not found"};
5823         }
5824         
5825         if(o.metaData){
5826             
5827             delete this.ef;
5828             this.metaFromRemote = true;
5829             this.meta = o.metaData;
5830             this.recordType = Roo.data.Record.create(o.metaData.fields);
5831             this.onMetaChange(this.meta, this.recordType, o);
5832         }
5833         return this.readRecords(o);
5834     },
5835
5836     // private function a store will implement
5837     onMetaChange : function(meta, recordType, o){
5838
5839     },
5840
5841     /**
5842          * @ignore
5843          */
5844     simpleAccess: function(obj, subsc) {
5845         return obj[subsc];
5846     },
5847
5848         /**
5849          * @ignore
5850          */
5851     getJsonAccessor: function(){
5852         var re = /[\[\.]/;
5853         return function(expr) {
5854             try {
5855                 return(re.test(expr))
5856                     ? new Function("obj", "return obj." + expr)
5857                     : function(obj){
5858                         return obj[expr];
5859                     };
5860             } catch(e){}
5861             return Roo.emptyFn;
5862         };
5863     }(),
5864
5865     /**
5866      * Create a data block containing Roo.data.Records from an XML document.
5867      * @param {Object} o An object which contains an Array of row objects in the property specified
5868      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
5869      * which contains the total size of the dataset.
5870      * @return {Object} data A data block which is used by an Roo.data.Store object as
5871      * a cache of Roo.data.Records.
5872      */
5873     readRecords : function(o){
5874         /**
5875          * After any data loads, the raw JSON data is available for further custom processing.
5876          * @type Object
5877          */
5878         this.o = o;
5879         var s = this.meta, Record = this.recordType,
5880             f = Record.prototype.fields, fi = f.items, fl = f.length;
5881
5882 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
5883         if (!this.ef) {
5884             if(s.totalProperty) {
5885                     this.getTotal = this.getJsonAccessor(s.totalProperty);
5886                 }
5887                 if(s.successProperty) {
5888                     this.getSuccess = this.getJsonAccessor(s.successProperty);
5889                 }
5890                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
5891                 if (s.id) {
5892                         var g = this.getJsonAccessor(s.id);
5893                         this.getId = function(rec) {
5894                                 var r = g(rec);
5895                                 return (r === undefined || r === "") ? null : r;
5896                         };
5897                 } else {
5898                         this.getId = function(){return null;};
5899                 }
5900             this.ef = [];
5901             for(var jj = 0; jj < fl; jj++){
5902                 f = fi[jj];
5903                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
5904                 this.ef[jj] = this.getJsonAccessor(map);
5905             }
5906         }
5907
5908         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
5909         if(s.totalProperty){
5910             var vt = parseInt(this.getTotal(o), 10);
5911             if(!isNaN(vt)){
5912                 totalRecords = vt;
5913             }
5914         }
5915         if(s.successProperty){
5916             var vs = this.getSuccess(o);
5917             if(vs === false || vs === 'false'){
5918                 success = false;
5919             }
5920         }
5921         var records = [];
5922             for(var i = 0; i < c; i++){
5923                     var n = root[i];
5924                 var values = {};
5925                 var id = this.getId(n);
5926                 for(var j = 0; j < fl; j++){
5927                     f = fi[j];
5928                 var v = this.ef[j](n);
5929                 if (!f.convert) {
5930                     Roo.log('missing convert for ' + f.name);
5931                     Roo.log(f);
5932                     continue;
5933                 }
5934                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
5935                 }
5936                 var record = new Record(values, id);
5937                 record.json = n;
5938                 records[i] = record;
5939             }
5940             return {
5941             raw : o,
5942                 success : success,
5943                 records : records,
5944                 totalRecords : totalRecords
5945             };
5946     }
5947 });/*
5948  * Based on:
5949  * Ext JS Library 1.1.1
5950  * Copyright(c) 2006-2007, Ext JS, LLC.
5951  *
5952  * Originally Released Under LGPL - original licence link has changed is not relivant.
5953  *
5954  * Fork - LGPL
5955  * <script type="text/javascript">
5956  */
5957
5958 /**
5959  * @class Roo.data.ArrayReader
5960  * @extends Roo.data.DataReader
5961  * Data reader class to create an Array of Roo.data.Record objects from an Array.
5962  * Each element of that Array represents a row of data fields. The
5963  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
5964  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
5965  * <p>
5966  * Example code:.
5967  * <pre><code>
5968 var RecordDef = Roo.data.Record.create([
5969     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
5970     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
5971 ]);
5972 var myReader = new Roo.data.ArrayReader({
5973     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
5974 }, RecordDef);
5975 </code></pre>
5976  * <p>
5977  * This would consume an Array like this:
5978  * <pre><code>
5979 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
5980   </code></pre>
5981  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
5982  * @constructor
5983  * Create a new JsonReader
5984  * @param {Object} meta Metadata configuration options.
5985  * @param {Object} recordType Either an Array of field definition objects
5986  * as specified to {@link Roo.data.Record#create},
5987  * or an {@link Roo.data.Record} object
5988  * created using {@link Roo.data.Record#create}.
5989  */
5990 Roo.data.ArrayReader = function(meta, recordType){
5991     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
5992 };
5993
5994 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
5995     /**
5996      * Create a data block containing Roo.data.Records from an XML document.
5997      * @param {Object} o An Array of row objects which represents the dataset.
5998      * @return {Object} data A data block which is used by an Roo.data.Store object as
5999      * a cache of Roo.data.Records.
6000      */
6001     readRecords : function(o){
6002         var sid = this.meta ? this.meta.id : null;
6003         var recordType = this.recordType, fields = recordType.prototype.fields;
6004         var records = [];
6005         var root = o;
6006             for(var i = 0; i < root.length; i++){
6007                     var n = root[i];
6008                 var values = {};
6009                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6010                 for(var j = 0, jlen = fields.length; j < jlen; j++){
6011                 var f = fields.items[j];
6012                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6013                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6014                 v = f.convert(v);
6015                 values[f.name] = v;
6016             }
6017                 var record = new recordType(values, id);
6018                 record.json = n;
6019                 records[records.length] = record;
6020             }
6021             return {
6022                 records : records,
6023                 totalRecords : records.length
6024             };
6025     }
6026 });/*
6027  * - LGPL
6028  * * 
6029  */
6030
6031 /**
6032  * @class Roo.bootstrap.ComboBox
6033  * @extends Roo.bootstrap.TriggerField
6034  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
6035  * @constructor
6036  * Create a new ComboBox.
6037  * @param {Object} config Configuration options
6038  */
6039 Roo.bootstrap.ComboBox = function(config){
6040     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
6041     this.addEvents({
6042         /**
6043          * @event expand
6044          * Fires when the dropdown list is expanded
6045              * @param {Roo.bootstrap.ComboBox} combo This combo box
6046              */
6047         'expand' : true,
6048         /**
6049          * @event collapse
6050          * Fires when the dropdown list is collapsed
6051              * @param {Roo.bootstrap.ComboBox} combo This combo box
6052              */
6053         'collapse' : true,
6054         /**
6055          * @event beforeselect
6056          * Fires before a list item is selected. Return false to cancel the selection.
6057              * @param {Roo.bootstrap.ComboBox} combo This combo box
6058              * @param {Roo.data.Record} record The data record returned from the underlying store
6059              * @param {Number} index The index of the selected item in the dropdown list
6060              */
6061         'beforeselect' : true,
6062         /**
6063          * @event select
6064          * Fires when a list item is selected
6065              * @param {Roo.bootstrap.ComboBox} combo This combo box
6066              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
6067              * @param {Number} index The index of the selected item in the dropdown list
6068              */
6069         'select' : true,
6070         /**
6071          * @event beforequery
6072          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
6073          * The event object passed has these properties:
6074              * @param {Roo.bootstrap.ComboBox} combo This combo box
6075              * @param {String} query The query
6076              * @param {Boolean} forceAll true to force "all" query
6077              * @param {Boolean} cancel true to cancel the query
6078              * @param {Object} e The query event object
6079              */
6080         'beforequery': true,
6081          /**
6082          * @event add
6083          * Fires when the 'add' icon is pressed (add a listener to enable add button)
6084              * @param {Roo.bootstrap.ComboBox} combo This combo box
6085              */
6086         'add' : true,
6087         /**
6088          * @event edit
6089          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
6090              * @param {Roo.bootstrap.ComboBox} combo This combo box
6091              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
6092              */
6093         'edit' : true
6094         
6095         
6096     });
6097     
6098     
6099     this.selectedIndex = -1;
6100     if(this.mode == 'local'){
6101         if(config.queryDelay === undefined){
6102             this.queryDelay = 10;
6103         }
6104         if(config.minChars === undefined){
6105             this.minChars = 0;
6106         }
6107     }
6108 };
6109
6110 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
6111      
6112     /**
6113      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
6114      * rendering into an Roo.Editor, defaults to false)
6115      */
6116     /**
6117      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
6118      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
6119      */
6120     /**
6121      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
6122      */
6123     /**
6124      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
6125      * the dropdown list (defaults to undefined, with no header element)
6126      */
6127
6128      /**
6129      * @cfg {String/Roo.Template} tpl The template to use to render the output
6130      */
6131      
6132      /**
6133      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
6134      */
6135     listWidth: undefined,
6136     /**
6137      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
6138      * mode = 'remote' or 'text' if mode = 'local')
6139      */
6140     displayField: undefined,
6141     /**
6142      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
6143      * mode = 'remote' or 'value' if mode = 'local'). 
6144      * Note: use of a valueField requires the user make a selection
6145      * in order for a value to be mapped.
6146      */
6147     valueField: undefined,
6148     
6149     
6150     /**
6151      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
6152      * field's data value (defaults to the underlying DOM element's name)
6153      */
6154     hiddenName: undefined,
6155     /**
6156      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
6157      */
6158     listClass: '',
6159     /**
6160      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
6161      */
6162     selectedClass: 'active',
6163     
6164     /**
6165      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
6166      */
6167     shadow:'sides',
6168     /**
6169      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
6170      * anchor positions (defaults to 'tl-bl')
6171      */
6172     listAlign: 'tl-bl?',
6173     /**
6174      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
6175      */
6176     maxHeight: 300,
6177     /**
6178      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
6179      * query specified by the allQuery config option (defaults to 'query')
6180      */
6181     triggerAction: 'query',
6182     /**
6183      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
6184      * (defaults to 4, does not apply if editable = false)
6185      */
6186     minChars : 4,
6187     /**
6188      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
6189      * delay (typeAheadDelay) if it matches a known value (defaults to false)
6190      */
6191     typeAhead: false,
6192     /**
6193      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
6194      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
6195      */
6196     queryDelay: 500,
6197     /**
6198      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
6199      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
6200      */
6201     pageSize: 0,
6202     /**
6203      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
6204      * when editable = true (defaults to false)
6205      */
6206     selectOnFocus:false,
6207     /**
6208      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
6209      */
6210     queryParam: 'query',
6211     /**
6212      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
6213      * when mode = 'remote' (defaults to 'Loading...')
6214      */
6215     loadingText: 'Loading...',
6216     /**
6217      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
6218      */
6219     resizable: false,
6220     /**
6221      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
6222      */
6223     handleHeight : 8,
6224     /**
6225      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
6226      * traditional select (defaults to true)
6227      */
6228     editable: true,
6229     /**
6230      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
6231      */
6232     allQuery: '',
6233     /**
6234      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
6235      */
6236     mode: 'remote',
6237     /**
6238      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
6239      * listWidth has a higher value)
6240      */
6241     minListWidth : 70,
6242     /**
6243      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
6244      * allow the user to set arbitrary text into the field (defaults to false)
6245      */
6246     forceSelection:false,
6247     /**
6248      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
6249      * if typeAhead = true (defaults to 250)
6250      */
6251     typeAheadDelay : 250,
6252     /**
6253      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
6254      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
6255      */
6256     valueNotFoundText : undefined,
6257     /**
6258      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
6259      */
6260     blockFocus : false,
6261     
6262     /**
6263      * @cfg {Boolean} disableClear Disable showing of clear button.
6264      */
6265     disableClear : false,
6266     /**
6267      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
6268      */
6269     alwaysQuery : false,
6270     
6271     //private
6272     addicon : false,
6273     editicon: false,
6274     
6275     // element that contains real text value.. (when hidden is used..)
6276      
6277     // private
6278     initEvents: function(){
6279         
6280         if (!this.store) {
6281             throw "can not find store for combo";
6282         }
6283         this.store = Roo.factory(this.store, Roo.data);
6284         
6285         
6286         
6287         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
6288         
6289         
6290         if(this.hiddenName){
6291             
6292             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
6293             
6294             this.hiddenField.dom.value =
6295                 this.hiddenValue !== undefined ? this.hiddenValue :
6296                 this.value !== undefined ? this.value : '';
6297
6298             // prevent input submission
6299             this.el.dom.removeAttribute('name');
6300             this.hiddenField.dom.setAttribute('name', this.hiddenName);
6301              
6302              
6303         }
6304         //if(Roo.isGecko){
6305         //    this.el.dom.setAttribute('autocomplete', 'off');
6306         //}
6307
6308         var cls = 'x-combo-list';
6309         this.list = this.el.select('ul',true).first();
6310
6311         //this.list = new Roo.Layer({
6312         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
6313         //});
6314         
6315         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
6316         this.list.setWidth(lw);
6317         /*
6318         this.list.swallowEvent('mousewheel');
6319         this.assetHeight = 0;
6320
6321         if(this.title){
6322             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
6323             this.assetHeight += this.header.getHeight();
6324         }
6325
6326         this.innerList = this.list.createChild({cls:cls+'-inner'});
6327         this.innerList.on('mouseover', this.onViewOver, this);
6328         this.innerList.on('mousemove', this.onViewMove, this);
6329         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6330         
6331         if(this.allowBlank && !this.pageSize && !this.disableClear){
6332             this.footer = this.list.createChild({cls:cls+'-ft'});
6333             this.pageTb = new Roo.Toolbar(this.footer);
6334            
6335         }
6336         if(this.pageSize){
6337             this.footer = this.list.createChild({cls:cls+'-ft'});
6338             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
6339                     {pageSize: this.pageSize});
6340             
6341         }
6342         
6343         if (this.pageTb && this.allowBlank && !this.disableClear) {
6344             var _this = this;
6345             this.pageTb.add(new Roo.Toolbar.Fill(), {
6346                 cls: 'x-btn-icon x-btn-clear',
6347                 text: '&#160;',
6348                 handler: function()
6349                 {
6350                     _this.collapse();
6351                     _this.clearValue();
6352                     _this.onSelect(false, -1);
6353                 }
6354             });
6355         }
6356         if (this.footer) {
6357             this.assetHeight += this.footer.getHeight();
6358         }
6359         */
6360             
6361         if(!this.tpl){
6362             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
6363         }
6364
6365         this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
6366             singleSelect:true, store: this.store, selectedClass: this.selectedClass
6367         });
6368         //this.view.wrapEl.setDisplayed(false);
6369         this.view.on('click', this.onViewClick, this);
6370         
6371         
6372         
6373         this.store.on('beforeload', this.onBeforeLoad, this);
6374         this.store.on('load', this.onLoad, this);
6375         this.store.on('loadexception', this.onLoadException, this);
6376         /*
6377         if(this.resizable){
6378             this.resizer = new Roo.Resizable(this.list,  {
6379                pinned:true, handles:'se'
6380             });
6381             this.resizer.on('resize', function(r, w, h){
6382                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
6383                 this.listWidth = w;
6384                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
6385                 this.restrictHeight();
6386             }, this);
6387             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
6388         }
6389         */
6390         if(!this.editable){
6391             this.editable = true;
6392             this.setEditable(false);
6393         }
6394         
6395         /*
6396         
6397         if (typeof(this.events.add.listeners) != 'undefined') {
6398             
6399             this.addicon = this.wrap.createChild(
6400                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
6401        
6402             this.addicon.on('click', function(e) {
6403                 this.fireEvent('add', this);
6404             }, this);
6405         }
6406         if (typeof(this.events.edit.listeners) != 'undefined') {
6407             
6408             this.editicon = this.wrap.createChild(
6409                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
6410             if (this.addicon) {
6411                 this.editicon.setStyle('margin-left', '40px');
6412             }
6413             this.editicon.on('click', function(e) {
6414                 
6415                 // we fire even  if inothing is selected..
6416                 this.fireEvent('edit', this, this.lastData );
6417                 
6418             }, this);
6419         }
6420         */
6421         
6422  
6423         this.keyNav = new Roo.KeyNav(this.inputEl(), {
6424             "up" : function(e){
6425                 this.inKeyMode = true;
6426                 this.selectPrev();
6427             },
6428
6429             "down" : function(e){
6430                 if(!this.isExpanded()){
6431                     this.onTriggerClick();
6432                 }else{
6433                     this.inKeyMode = true;
6434                     this.selectNext();
6435                 }
6436             },
6437
6438             "enter" : function(e){
6439                 this.onViewClick();
6440                 //return true;
6441             },
6442
6443             "esc" : function(e){
6444                 this.collapse();
6445             },
6446
6447             "tab" : function(e){
6448                 this.onViewClick(false);
6449                 this.fireEvent("specialkey", this, e);
6450                 return true;
6451             },
6452
6453             scope : this,
6454
6455             doRelay : function(foo, bar, hname){
6456                 if(hname == 'down' || this.scope.isExpanded()){
6457                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
6458                 }
6459                 return true;
6460             },
6461
6462             forceKeyDown: true
6463         });
6464         
6465         
6466         this.queryDelay = Math.max(this.queryDelay || 10,
6467                 this.mode == 'local' ? 10 : 250);
6468         
6469         
6470         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
6471         
6472         if(this.typeAhead){
6473             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
6474         }
6475         if(this.editable !== false){
6476             this.inputEl().on("keyup", this.onKeyUp, this);
6477         }
6478         if(this.forceSelection){
6479             this.on('blur', this.doForce, this);
6480         }
6481     },
6482
6483     onDestroy : function(){
6484         if(this.view){
6485             this.view.setStore(null);
6486             this.view.el.removeAllListeners();
6487             this.view.el.remove();
6488             this.view.purgeListeners();
6489         }
6490         if(this.list){
6491             this.list.dom.innerHTML  = '';
6492         }
6493         if(this.store){
6494             this.store.un('beforeload', this.onBeforeLoad, this);
6495             this.store.un('load', this.onLoad, this);
6496             this.store.un('loadexception', this.onLoadException, this);
6497         }
6498         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
6499     },
6500
6501     // private
6502     fireKey : function(e){
6503         if(e.isNavKeyPress() && !this.list.isVisible()){
6504             this.fireEvent("specialkey", this, e);
6505         }
6506     },
6507
6508     // private
6509     onResize: function(w, h){
6510         Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
6511         
6512         if(typeof w != 'number'){
6513             // we do not handle it!?!?
6514             return;
6515         }
6516         var tw = this.trigger.getWidth();
6517        // tw += this.addicon ? this.addicon.getWidth() : 0;
6518        // tw += this.editicon ? this.editicon.getWidth() : 0;
6519         var x = w - tw;
6520         this.inputEl().setWidth( this.adjustWidth('input', x));
6521             
6522         //this.trigger.setStyle('left', x+'px');
6523         
6524         if(this.list && this.listWidth === undefined){
6525             var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
6526             this.list.setWidth(lw);
6527             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
6528         }
6529         
6530     
6531         
6532     },
6533
6534     /**
6535      * Allow or prevent the user from directly editing the field text.  If false is passed,
6536      * the user will only be able to select from the items defined in the dropdown list.  This method
6537      * is the runtime equivalent of setting the 'editable' config option at config time.
6538      * @param {Boolean} value True to allow the user to directly edit the field text
6539      */
6540     setEditable : function(value){
6541         if(value == this.editable){
6542             return;
6543         }
6544         this.editable = value;
6545         if(!value){
6546             this.inputEl().dom.setAttribute('readOnly', true);
6547             this.inputEl().on('mousedown', this.onTriggerClick,  this);
6548             this.inputEl().addClass('x-combo-noedit');
6549         }else{
6550             this.inputEl().dom.setAttribute('readOnly', false);
6551             this.inputEl().un('mousedown', this.onTriggerClick,  this);
6552             this.inputEl().removeClass('x-combo-noedit');
6553         }
6554     },
6555
6556     // private
6557     onBeforeLoad : function(){
6558         if(!this.hasFocus){
6559             return;
6560         }
6561         //this.innerList.update(this.loadingText ?
6562         //       '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
6563         this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
6564         
6565         this.restrictHeight();
6566         this.selectedIndex = -1;
6567     },
6568
6569     // private
6570     onLoad : function(){
6571         if(!this.hasFocus){
6572             return;
6573         }
6574         if(this.store.getCount() > 0){
6575             this.expand();
6576             this.restrictHeight();
6577             if(this.lastQuery == this.allQuery){
6578                 if(this.editable){
6579                     this.inputEl().dom.select();
6580                 }
6581                 if(!this.selectByValue(this.value, true)){
6582                     this.select(0, true);
6583                 }
6584             }else{
6585                 this.selectNext();
6586                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
6587                     this.taTask.delay(this.typeAheadDelay);
6588                 }
6589             }
6590         }else{
6591             this.onEmptyResults();
6592         }
6593         //this.el.focus();
6594     },
6595     // private
6596     onLoadException : function()
6597     {
6598         this.collapse();
6599         Roo.log(this.store.reader.jsonData);
6600         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6601             // fixme
6602             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6603         }
6604         
6605         
6606     },
6607     // private
6608     onTypeAhead : function(){
6609         if(this.store.getCount() > 0){
6610             var r = this.store.getAt(0);
6611             var newValue = r.data[this.displayField];
6612             var len = newValue.length;
6613             var selStart = this.getRawValue().length;
6614             if(selStart != len){
6615                 this.setRawValue(newValue);
6616                 this.selectText(selStart, newValue.length);
6617             }
6618         }
6619     },
6620
6621     // private
6622     onSelect : function(record, index){
6623         if(this.fireEvent('beforeselect', this, record, index) !== false){
6624             this.setFromData(index > -1 ? record.data : false);
6625             this.collapse();
6626             this.fireEvent('select', this, record, index);
6627         }
6628     },
6629
6630     /**
6631      * Returns the currently selected field value or empty string if no value is set.
6632      * @return {String} value The selected value
6633      */
6634     getValue : function(){
6635         if(this.valueField){
6636             return typeof this.value != 'undefined' ? this.value : '';
6637         }else{
6638             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
6639         }
6640     },
6641
6642     /**
6643      * Clears any text/value currently set in the field
6644      */
6645     clearValue : function(){
6646         if(this.hiddenField){
6647             this.hiddenField.dom.value = '';
6648         }
6649         this.value = '';
6650         this.setRawValue('');
6651         this.lastSelectionText = '';
6652         
6653     },
6654
6655     /**
6656      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
6657      * will be displayed in the field.  If the value does not match the data value of an existing item,
6658      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
6659      * Otherwise the field will be blank (although the value will still be set).
6660      * @param {String} value The value to match
6661      */
6662     setValue : function(v){
6663         var text = v;
6664         if(this.valueField){
6665             var r = this.findRecord(this.valueField, v);
6666             if(r){
6667                 text = r.data[this.displayField];
6668             }else if(this.valueNotFoundText !== undefined){
6669                 text = this.valueNotFoundText;
6670             }
6671         }
6672         this.lastSelectionText = text;
6673         if(this.hiddenField){
6674             this.hiddenField.dom.value = v;
6675         }
6676         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
6677         this.value = v;
6678     },
6679     /**
6680      * @property {Object} the last set data for the element
6681      */
6682     
6683     lastData : false,
6684     /**
6685      * Sets the value of the field based on a object which is related to the record format for the store.
6686      * @param {Object} value the value to set as. or false on reset?
6687      */
6688     setFromData : function(o){
6689         var dv = ''; // display value
6690         var vv = ''; // value value..
6691         this.lastData = o;
6692         if (this.displayField) {
6693             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
6694         } else {
6695             // this is an error condition!!!
6696             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
6697         }
6698         
6699         if(this.valueField){
6700             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
6701         }
6702         if(this.hiddenField){
6703             this.hiddenField.dom.value = vv;
6704             
6705             this.lastSelectionText = dv;
6706             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6707             this.value = vv;
6708             return;
6709         }
6710         // no hidden field.. - we store the value in 'value', but still display
6711         // display field!!!!
6712         this.lastSelectionText = dv;
6713         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
6714         this.value = vv;
6715         
6716         
6717     },
6718     // private
6719     reset : function(){
6720         // overridden so that last data is reset..
6721         this.setValue(this.originalValue);
6722         this.clearInvalid();
6723         this.lastData = false;
6724         if (this.view) {
6725             this.view.clearSelections();
6726         }
6727     },
6728     // private
6729     findRecord : function(prop, value){
6730         var record;
6731         if(this.store.getCount() > 0){
6732             this.store.each(function(r){
6733                 if(r.data[prop] == value){
6734                     record = r;
6735                     return false;
6736                 }
6737                 return true;
6738             });
6739         }
6740         return record;
6741     },
6742     
6743     getName: function()
6744     {
6745         // returns hidden if it's set..
6746         if (!this.rendered) {return ''};
6747         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
6748         
6749     },
6750     // private
6751     onViewMove : function(e, t){
6752         this.inKeyMode = false;
6753     },
6754
6755     // private
6756     onViewOver : function(e, t){
6757         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
6758             return;
6759         }
6760         var item = this.view.findItemFromChild(t);
6761         if(item){
6762             var index = this.view.indexOf(item);
6763             this.select(index, false);
6764         }
6765     },
6766
6767     // private
6768     onViewClick : function(doFocus)
6769     {
6770         var index = this.view.getSelectedIndexes()[0];
6771         var r = this.store.getAt(index);
6772         if(r){
6773             this.onSelect(r, index);
6774         }
6775         if(doFocus !== false && !this.blockFocus){
6776             this.inputEl().focus();
6777         }
6778     },
6779
6780     // private
6781     restrictHeight : function(){
6782         //this.innerList.dom.style.height = '';
6783         //var inner = this.innerList.dom;
6784         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
6785         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
6786         //this.list.beginUpdate();
6787         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
6788         this.list.alignTo(this.inputEl(), this.listAlign);
6789         //this.list.endUpdate();
6790     },
6791
6792     // private
6793     onEmptyResults : function(){
6794         this.collapse();
6795     },
6796
6797     /**
6798      * Returns true if the dropdown list is expanded, else false.
6799      */
6800     isExpanded : function(){
6801         return this.list.isVisible();
6802     },
6803
6804     /**
6805      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
6806      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6807      * @param {String} value The data value of the item to select
6808      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6809      * selected item if it is not currently in view (defaults to true)
6810      * @return {Boolean} True if the value matched an item in the list, else false
6811      */
6812     selectByValue : function(v, scrollIntoView){
6813         if(v !== undefined && v !== null){
6814             var r = this.findRecord(this.valueField || this.displayField, v);
6815             if(r){
6816                 this.select(this.store.indexOf(r), scrollIntoView);
6817                 return true;
6818             }
6819         }
6820         return false;
6821     },
6822
6823     /**
6824      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
6825      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
6826      * @param {Number} index The zero-based index of the list item to select
6827      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
6828      * selected item if it is not currently in view (defaults to true)
6829      */
6830     select : function(index, scrollIntoView){
6831         this.selectedIndex = index;
6832         this.view.select(index);
6833         if(scrollIntoView !== false){
6834             var el = this.view.getNode(index);
6835             if(el){
6836                 //this.innerList.scrollChildIntoView(el, false);
6837                 
6838             }
6839         }
6840     },
6841
6842     // private
6843     selectNext : function(){
6844         var ct = this.store.getCount();
6845         if(ct > 0){
6846             if(this.selectedIndex == -1){
6847                 this.select(0);
6848             }else if(this.selectedIndex < ct-1){
6849                 this.select(this.selectedIndex+1);
6850             }
6851         }
6852     },
6853
6854     // private
6855     selectPrev : function(){
6856         var ct = this.store.getCount();
6857         if(ct > 0){
6858             if(this.selectedIndex == -1){
6859                 this.select(0);
6860             }else if(this.selectedIndex != 0){
6861                 this.select(this.selectedIndex-1);
6862             }
6863         }
6864     },
6865
6866     // private
6867     onKeyUp : function(e){
6868         if(this.editable !== false && !e.isSpecialKey()){
6869             this.lastKey = e.getKey();
6870             this.dqTask.delay(this.queryDelay);
6871         }
6872     },
6873
6874     // private
6875     validateBlur : function(){
6876         return !this.list || !this.list.isVisible();   
6877     },
6878
6879     // private
6880     initQuery : function(){
6881         this.doQuery(this.getRawValue());
6882     },
6883
6884     // private
6885     doForce : function(){
6886         if(this.el.dom.value.length > 0){
6887             this.el.dom.value =
6888                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
6889              
6890         }
6891     },
6892
6893     /**
6894      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
6895      * query allowing the query action to be canceled if needed.
6896      * @param {String} query The SQL query to execute
6897      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
6898      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
6899      * saved in the current store (defaults to false)
6900      */
6901     doQuery : function(q, forceAll){
6902         if(q === undefined || q === null){
6903             q = '';
6904         }
6905         var qe = {
6906             query: q,
6907             forceAll: forceAll,
6908             combo: this,
6909             cancel:false
6910         };
6911         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
6912             return false;
6913         }
6914         q = qe.query;
6915         forceAll = qe.forceAll;
6916         if(forceAll === true || (q.length >= this.minChars)){
6917             if(this.lastQuery != q || this.alwaysQuery){
6918                 this.lastQuery = q;
6919                 if(this.mode == 'local'){
6920                     this.selectedIndex = -1;
6921                     if(forceAll){
6922                         this.store.clearFilter();
6923                     }else{
6924                         this.store.filter(this.displayField, q);
6925                     }
6926                     this.onLoad();
6927                 }else{
6928                     this.store.baseParams[this.queryParam] = q;
6929                     this.store.load({
6930                         params: this.getParams(q)
6931                     });
6932                     this.expand();
6933                 }
6934             }else{
6935                 this.selectedIndex = -1;
6936                 this.onLoad();   
6937             }
6938         }
6939     },
6940
6941     // private
6942     getParams : function(q){
6943         var p = {};
6944         //p[this.queryParam] = q;
6945         if(this.pageSize){
6946             p.start = 0;
6947             p.limit = this.pageSize;
6948         }
6949         return p;
6950     },
6951
6952     /**
6953      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
6954      */
6955     collapse : function(){
6956         if(!this.isExpanded()){
6957             return;
6958         }
6959         this.list.hide();
6960         Roo.get(document).un('mousedown', this.collapseIf, this);
6961         Roo.get(document).un('mousewheel', this.collapseIf, this);
6962         if (!this.editable) {
6963             Roo.get(document).un('keydown', this.listKeyPress, this);
6964         }
6965         this.fireEvent('collapse', this);
6966     },
6967
6968     // private
6969     collapseIf : function(e){
6970         if(!e.within(this.el) && !e.within(this.el)){
6971             this.collapse();
6972         }
6973     },
6974
6975     /**
6976      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
6977      */
6978     expand : function(){
6979         Roo.log('expand');
6980         if(this.isExpanded() || !this.hasFocus){
6981             return;
6982         }
6983         this.list.alignTo(this.inputEl(), this.listAlign);
6984         this.list.show();
6985         Roo.get(document).on('mousedown', this.collapseIf, this);
6986         Roo.get(document).on('mousewheel', this.collapseIf, this);
6987         if (!this.editable) {
6988             Roo.get(document).on('keydown', this.listKeyPress, this);
6989         }
6990         
6991         this.fireEvent('expand', this);
6992     },
6993
6994     // private
6995     // Implements the default empty TriggerField.onTriggerClick function
6996     onTriggerClick : function()
6997     {
6998         Roo.log('trigger click');
6999         
7000         if(this.disabled){
7001             return;
7002         }
7003         if(this.isExpanded()){
7004             this.collapse();
7005             if (!this.blockFocus) {
7006                 this.inputEl().focus();
7007             }
7008             
7009         }else {
7010             this.hasFocus = true;
7011             if(this.triggerAction == 'all') {
7012                 this.doQuery(this.allQuery, true);
7013             } else {
7014                 this.doQuery(this.getRawValue());
7015             }
7016             if (!this.blockFocus) {
7017                 this.inputEl().focus();
7018             }
7019         }
7020     },
7021     listKeyPress : function(e)
7022     {
7023         //Roo.log('listkeypress');
7024         // scroll to first matching element based on key pres..
7025         if (e.isSpecialKey()) {
7026             return false;
7027         }
7028         var k = String.fromCharCode(e.getKey()).toUpperCase();
7029         //Roo.log(k);
7030         var match  = false;
7031         var csel = this.view.getSelectedNodes();
7032         var cselitem = false;
7033         if (csel.length) {
7034             var ix = this.view.indexOf(csel[0]);
7035             cselitem  = this.store.getAt(ix);
7036             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
7037                 cselitem = false;
7038             }
7039             
7040         }
7041         
7042         this.store.each(function(v) { 
7043             if (cselitem) {
7044                 // start at existing selection.
7045                 if (cselitem.id == v.id) {
7046                     cselitem = false;
7047                 }
7048                 return true;
7049             }
7050                 
7051             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
7052                 match = this.store.indexOf(v);
7053                 return false;
7054             }
7055             return true;
7056         }, this);
7057         
7058         if (match === false) {
7059             return true; // no more action?
7060         }
7061         // scroll to?
7062         this.view.select(match);
7063         var sn = Roo.get(this.view.getSelectedNodes()[0])
7064         //sn.scrollIntoView(sn.dom.parentNode, false);
7065     }
7066
7067     /** 
7068     * @cfg {Boolean} grow 
7069     * @hide 
7070     */
7071     /** 
7072     * @cfg {Number} growMin 
7073     * @hide 
7074     */
7075     /** 
7076     * @cfg {Number} growMax 
7077     * @hide 
7078     */
7079     /**
7080      * @hide
7081      * @method autoSize
7082      */
7083 });/*
7084  * Based on:
7085  * Ext JS Library 1.1.1
7086  * Copyright(c) 2006-2007, Ext JS, LLC.
7087  *
7088  * Originally Released Under LGPL - original licence link has changed is not relivant.
7089  *
7090  * Fork - LGPL
7091  * <script type="text/javascript">
7092  */
7093
7094 /**
7095  * @class Roo.View
7096  * @extends Roo.util.Observable
7097  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
7098  * This class also supports single and multi selection modes. <br>
7099  * Create a data model bound view:
7100  <pre><code>
7101  var store = new Roo.data.Store(...);
7102
7103  var view = new Roo.View({
7104     el : "my-element",
7105     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
7106  
7107     singleSelect: true,
7108     selectedClass: "ydataview-selected",
7109     store: store
7110  });
7111
7112  // listen for node click?
7113  view.on("click", function(vw, index, node, e){
7114  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
7115  });
7116
7117  // load XML data
7118  dataModel.load("foobar.xml");
7119  </code></pre>
7120  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
7121  * <br><br>
7122  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
7123  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
7124  * 
7125  * Note: old style constructor is still suported (container, template, config)
7126  * 
7127  * @constructor
7128  * Create a new View
7129  * @param {Object} config The config object
7130  * 
7131  */
7132 Roo.View = function(config, depreciated_tpl, depreciated_config){
7133     
7134     if (typeof(depreciated_tpl) == 'undefined') {
7135         // new way.. - universal constructor.
7136         Roo.apply(this, config);
7137         this.el  = Roo.get(this.el);
7138     } else {
7139         // old format..
7140         this.el  = Roo.get(config);
7141         this.tpl = depreciated_tpl;
7142         Roo.apply(this, depreciated_config);
7143     }
7144     this.wrapEl  = this.el.wrap().wrap();
7145     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
7146     
7147     
7148     if(typeof(this.tpl) == "string"){
7149         this.tpl = new Roo.Template(this.tpl);
7150     } else {
7151         // support xtype ctors..
7152         this.tpl = new Roo.factory(this.tpl, Roo);
7153     }
7154     
7155     
7156     this.tpl.compile();
7157    
7158   
7159     
7160      
7161     /** @private */
7162     this.addEvents({
7163         /**
7164          * @event beforeclick
7165          * Fires before a click is processed. Returns false to cancel the default action.
7166          * @param {Roo.View} this
7167          * @param {Number} index The index of the target node
7168          * @param {HTMLElement} node The target node
7169          * @param {Roo.EventObject} e The raw event object
7170          */
7171             "beforeclick" : true,
7172         /**
7173          * @event click
7174          * Fires when a template node is clicked.
7175          * @param {Roo.View} this
7176          * @param {Number} index The index of the target node
7177          * @param {HTMLElement} node The target node
7178          * @param {Roo.EventObject} e The raw event object
7179          */
7180             "click" : true,
7181         /**
7182          * @event dblclick
7183          * Fires when a template node is double clicked.
7184          * @param {Roo.View} this
7185          * @param {Number} index The index of the target node
7186          * @param {HTMLElement} node The target node
7187          * @param {Roo.EventObject} e The raw event object
7188          */
7189             "dblclick" : true,
7190         /**
7191          * @event contextmenu
7192          * Fires when a template node is right clicked.
7193          * @param {Roo.View} this
7194          * @param {Number} index The index of the target node
7195          * @param {HTMLElement} node The target node
7196          * @param {Roo.EventObject} e The raw event object
7197          */
7198             "contextmenu" : true,
7199         /**
7200          * @event selectionchange
7201          * Fires when the selected nodes change.
7202          * @param {Roo.View} this
7203          * @param {Array} selections Array of the selected nodes
7204          */
7205             "selectionchange" : true,
7206     
7207         /**
7208          * @event beforeselect
7209          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
7210          * @param {Roo.View} this
7211          * @param {HTMLElement} node The node to be selected
7212          * @param {Array} selections Array of currently selected nodes
7213          */
7214             "beforeselect" : true,
7215         /**
7216          * @event preparedata
7217          * Fires on every row to render, to allow you to change the data.
7218          * @param {Roo.View} this
7219          * @param {Object} data to be rendered (change this)
7220          */
7221           "preparedata" : true
7222           
7223           
7224         });
7225
7226
7227
7228     this.el.on({
7229         "click": this.onClick,
7230         "dblclick": this.onDblClick,
7231         "contextmenu": this.onContextMenu,
7232         scope:this
7233     });
7234
7235     this.selections = [];
7236     this.nodes = [];
7237     this.cmp = new Roo.CompositeElementLite([]);
7238     if(this.store){
7239         this.store = Roo.factory(this.store, Roo.data);
7240         this.setStore(this.store, true);
7241     }
7242     
7243     if ( this.footer && this.footer.xtype) {
7244            
7245          var fctr = this.wrapEl.appendChild(document.createElement("div"));
7246         
7247         this.footer.dataSource = this.store
7248         this.footer.container = fctr;
7249         this.footer = Roo.factory(this.footer, Roo);
7250         fctr.insertFirst(this.el);
7251         
7252         // this is a bit insane - as the paging toolbar seems to detach the el..
7253 //        dom.parentNode.parentNode.parentNode
7254          // they get detached?
7255     }
7256     
7257     
7258     Roo.View.superclass.constructor.call(this);
7259     
7260     
7261 };
7262
7263 Roo.extend(Roo.View, Roo.util.Observable, {
7264     
7265      /**
7266      * @cfg {Roo.data.Store} store Data store to load data from.
7267      */
7268     store : false,
7269     
7270     /**
7271      * @cfg {String|Roo.Element} el The container element.
7272      */
7273     el : '',
7274     
7275     /**
7276      * @cfg {String|Roo.Template} tpl The template used by this View 
7277      */
7278     tpl : false,
7279     /**
7280      * @cfg {String} dataName the named area of the template to use as the data area
7281      *                          Works with domtemplates roo-name="name"
7282      */
7283     dataName: false,
7284     /**
7285      * @cfg {String} selectedClass The css class to add to selected nodes
7286      */
7287     selectedClass : "x-view-selected",
7288      /**
7289      * @cfg {String} emptyText The empty text to show when nothing is loaded.
7290      */
7291     emptyText : "",
7292     
7293     /**
7294      * @cfg {String} text to display on mask (default Loading)
7295      */
7296     mask : false,
7297     /**
7298      * @cfg {Boolean} multiSelect Allow multiple selection
7299      */
7300     multiSelect : false,
7301     /**
7302      * @cfg {Boolean} singleSelect Allow single selection
7303      */
7304     singleSelect:  false,
7305     
7306     /**
7307      * @cfg {Boolean} toggleSelect - selecting 
7308      */
7309     toggleSelect : false,
7310     
7311     /**
7312      * Returns the element this view is bound to.
7313      * @return {Roo.Element}
7314      */
7315     getEl : function(){
7316         return this.wrapEl;
7317     },
7318     
7319     
7320
7321     /**
7322      * Refreshes the view. - called by datachanged on the store. - do not call directly.
7323      */
7324     refresh : function(){
7325         var t = this.tpl;
7326         
7327         // if we are using something like 'domtemplate', then
7328         // the what gets used is:
7329         // t.applySubtemplate(NAME, data, wrapping data..)
7330         // the outer template then get' applied with
7331         //     the store 'extra data'
7332         // and the body get's added to the
7333         //      roo-name="data" node?
7334         //      <span class='roo-tpl-{name}'></span> ?????
7335         
7336         
7337         
7338         this.clearSelections();
7339         this.el.update("");
7340         var html = [];
7341         var records = this.store.getRange();
7342         if(records.length < 1) {
7343             
7344             // is this valid??  = should it render a template??
7345             
7346             this.el.update(this.emptyText);
7347             return;
7348         }
7349         var el = this.el;
7350         if (this.dataName) {
7351             this.el.update(t.apply(this.store.meta)); //????
7352             el = this.el.child('.roo-tpl-' + this.dataName);
7353         }
7354         
7355         for(var i = 0, len = records.length; i < len; i++){
7356             var data = this.prepareData(records[i].data, i, records[i]);
7357             this.fireEvent("preparedata", this, data, i, records[i]);
7358             html[html.length] = Roo.util.Format.trim(
7359                 this.dataName ?
7360                     t.applySubtemplate(this.dataName, data, this.store.meta) :
7361                     t.apply(data)
7362             );
7363         }
7364         
7365         
7366         
7367         el.update(html.join(""));
7368         this.nodes = el.dom.childNodes;
7369         this.updateIndexes(0);
7370     },
7371
7372     /**
7373      * Function to override to reformat the data that is sent to
7374      * the template for each node.
7375      * DEPRICATED - use the preparedata event handler.
7376      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
7377      * a JSON object for an UpdateManager bound view).
7378      */
7379     prepareData : function(data, index, record)
7380     {
7381         this.fireEvent("preparedata", this, data, index, record);
7382         return data;
7383     },
7384
7385     onUpdate : function(ds, record){
7386         this.clearSelections();
7387         var index = this.store.indexOf(record);
7388         var n = this.nodes[index];
7389         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
7390         n.parentNode.removeChild(n);
7391         this.updateIndexes(index, index);
7392     },
7393
7394     
7395     
7396 // --------- FIXME     
7397     onAdd : function(ds, records, index)
7398     {
7399         this.clearSelections();
7400         if(this.nodes.length == 0){
7401             this.refresh();
7402             return;
7403         }
7404         var n = this.nodes[index];
7405         for(var i = 0, len = records.length; i < len; i++){
7406             var d = this.prepareData(records[i].data, i, records[i]);
7407             if(n){
7408                 this.tpl.insertBefore(n, d);
7409             }else{
7410                 
7411                 this.tpl.append(this.el, d);
7412             }
7413         }
7414         this.updateIndexes(index);
7415     },
7416
7417     onRemove : function(ds, record, index){
7418         this.clearSelections();
7419         var el = this.dataName  ?
7420             this.el.child('.roo-tpl-' + this.dataName) :
7421             this.el; 
7422         el.dom.removeChild(this.nodes[index]);
7423         this.updateIndexes(index);
7424     },
7425
7426     /**
7427      * Refresh an individual node.
7428      * @param {Number} index
7429      */
7430     refreshNode : function(index){
7431         this.onUpdate(this.store, this.store.getAt(index));
7432     },
7433
7434     updateIndexes : function(startIndex, endIndex){
7435         var ns = this.nodes;
7436         startIndex = startIndex || 0;
7437         endIndex = endIndex || ns.length - 1;
7438         for(var i = startIndex; i <= endIndex; i++){
7439             ns[i].nodeIndex = i;
7440         }
7441     },
7442
7443     /**
7444      * Changes the data store this view uses and refresh the view.
7445      * @param {Store} store
7446      */
7447     setStore : function(store, initial){
7448         if(!initial && this.store){
7449             this.store.un("datachanged", this.refresh);
7450             this.store.un("add", this.onAdd);
7451             this.store.un("remove", this.onRemove);
7452             this.store.un("update", this.onUpdate);
7453             this.store.un("clear", this.refresh);
7454             this.store.un("beforeload", this.onBeforeLoad);
7455             this.store.un("load", this.onLoad);
7456             this.store.un("loadexception", this.onLoad);
7457         }
7458         if(store){
7459           
7460             store.on("datachanged", this.refresh, this);
7461             store.on("add", this.onAdd, this);
7462             store.on("remove", this.onRemove, this);
7463             store.on("update", this.onUpdate, this);
7464             store.on("clear", this.refresh, this);
7465             store.on("beforeload", this.onBeforeLoad, this);
7466             store.on("load", this.onLoad, this);
7467             store.on("loadexception", this.onLoad, this);
7468         }
7469         
7470         if(store){
7471             this.refresh();
7472         }
7473     },
7474     /**
7475      * onbeforeLoad - masks the loading area.
7476      *
7477      */
7478     onBeforeLoad : function()
7479     {
7480         this.el.update("");
7481         this.el.mask(this.mask ? this.mask : "Loading" ); 
7482     },
7483     onLoad : function ()
7484     {
7485         this.el.unmask();
7486     },
7487     
7488
7489     /**
7490      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
7491      * @param {HTMLElement} node
7492      * @return {HTMLElement} The template node
7493      */
7494     findItemFromChild : function(node){
7495         var el = this.dataName  ?
7496             this.el.child('.roo-tpl-' + this.dataName,true) :
7497             this.el.dom; 
7498         
7499         if(!node || node.parentNode == el){
7500                     return node;
7501             }
7502             var p = node.parentNode;
7503             while(p && p != el){
7504             if(p.parentNode == el){
7505                 return p;
7506             }
7507             p = p.parentNode;
7508         }
7509             return null;
7510     },
7511
7512     /** @ignore */
7513     onClick : function(e){
7514         var item = this.findItemFromChild(e.getTarget());
7515         if(item){
7516             var index = this.indexOf(item);
7517             if(this.onItemClick(item, index, e) !== false){
7518                 this.fireEvent("click", this, index, item, e);
7519             }
7520         }else{
7521             this.clearSelections();
7522         }
7523     },
7524
7525     /** @ignore */
7526     onContextMenu : function(e){
7527         var item = this.findItemFromChild(e.getTarget());
7528         if(item){
7529             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
7530         }
7531     },
7532
7533     /** @ignore */
7534     onDblClick : function(e){
7535         var item = this.findItemFromChild(e.getTarget());
7536         if(item){
7537             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
7538         }
7539     },
7540
7541     onItemClick : function(item, index, e)
7542     {
7543         if(this.fireEvent("beforeclick", this, index, item, e) === false){
7544             return false;
7545         }
7546         if (this.toggleSelect) {
7547             var m = this.isSelected(item) ? 'unselect' : 'select';
7548             Roo.log(m);
7549             var _t = this;
7550             _t[m](item, true, false);
7551             return true;
7552         }
7553         if(this.multiSelect || this.singleSelect){
7554             if(this.multiSelect && e.shiftKey && this.lastSelection){
7555                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
7556             }else{
7557                 this.select(item, this.multiSelect && e.ctrlKey);
7558                 this.lastSelection = item;
7559             }
7560             e.preventDefault();
7561         }
7562         return true;
7563     },
7564
7565     /**
7566      * Get the number of selected nodes.
7567      * @return {Number}
7568      */
7569     getSelectionCount : function(){
7570         return this.selections.length;
7571     },
7572
7573     /**
7574      * Get the currently selected nodes.
7575      * @return {Array} An array of HTMLElements
7576      */
7577     getSelectedNodes : function(){
7578         return this.selections;
7579     },
7580
7581     /**
7582      * Get the indexes of the selected nodes.
7583      * @return {Array}
7584      */
7585     getSelectedIndexes : function(){
7586         var indexes = [], s = this.selections;
7587         for(var i = 0, len = s.length; i < len; i++){
7588             indexes.push(s[i].nodeIndex);
7589         }
7590         return indexes;
7591     },
7592
7593     /**
7594      * Clear all selections
7595      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
7596      */
7597     clearSelections : function(suppressEvent){
7598         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
7599             this.cmp.elements = this.selections;
7600             this.cmp.removeClass(this.selectedClass);
7601             this.selections = [];
7602             if(!suppressEvent){
7603                 this.fireEvent("selectionchange", this, this.selections);
7604             }
7605         }
7606     },
7607
7608     /**
7609      * Returns true if the passed node is selected
7610      * @param {HTMLElement/Number} node The node or node index
7611      * @return {Boolean}
7612      */
7613     isSelected : function(node){
7614         var s = this.selections;
7615         if(s.length < 1){
7616             return false;
7617         }
7618         node = this.getNode(node);
7619         return s.indexOf(node) !== -1;
7620     },
7621
7622     /**
7623      * Selects nodes.
7624      * @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
7625      * @param {Boolean} keepExisting (optional) true to keep existing selections
7626      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7627      */
7628     select : function(nodeInfo, keepExisting, suppressEvent){
7629         if(nodeInfo instanceof Array){
7630             if(!keepExisting){
7631                 this.clearSelections(true);
7632             }
7633             for(var i = 0, len = nodeInfo.length; i < len; i++){
7634                 this.select(nodeInfo[i], true, true);
7635             }
7636             return;
7637         } 
7638         var node = this.getNode(nodeInfo);
7639         if(!node || this.isSelected(node)){
7640             return; // already selected.
7641         }
7642         if(!keepExisting){
7643             this.clearSelections(true);
7644         }
7645         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
7646             Roo.fly(node).addClass(this.selectedClass);
7647             this.selections.push(node);
7648             if(!suppressEvent){
7649                 this.fireEvent("selectionchange", this, this.selections);
7650             }
7651         }
7652         
7653         
7654     },
7655       /**
7656      * Unselects nodes.
7657      * @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
7658      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
7659      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
7660      */
7661     unselect : function(nodeInfo, keepExisting, suppressEvent)
7662     {
7663         if(nodeInfo instanceof Array){
7664             Roo.each(this.selections, function(s) {
7665                 this.unselect(s, nodeInfo);
7666             }, this);
7667             return;
7668         }
7669         var node = this.getNode(nodeInfo);
7670         if(!node || !this.isSelected(node)){
7671             Roo.log("not selected");
7672             return; // not selected.
7673         }
7674         // fireevent???
7675         var ns = [];
7676         Roo.each(this.selections, function(s) {
7677             if (s == node ) {
7678                 Roo.fly(node).removeClass(this.selectedClass);
7679
7680                 return;
7681             }
7682             ns.push(s);
7683         },this);
7684         
7685         this.selections= ns;
7686         this.fireEvent("selectionchange", this, this.selections);
7687     },
7688
7689     /**
7690      * Gets a template node.
7691      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7692      * @return {HTMLElement} The node or null if it wasn't found
7693      */
7694     getNode : function(nodeInfo){
7695         if(typeof nodeInfo == "string"){
7696             return document.getElementById(nodeInfo);
7697         }else if(typeof nodeInfo == "number"){
7698             return this.nodes[nodeInfo];
7699         }
7700         return nodeInfo;
7701     },
7702
7703     /**
7704      * Gets a range template nodes.
7705      * @param {Number} startIndex
7706      * @param {Number} endIndex
7707      * @return {Array} An array of nodes
7708      */
7709     getNodes : function(start, end){
7710         var ns = this.nodes;
7711         start = start || 0;
7712         end = typeof end == "undefined" ? ns.length - 1 : end;
7713         var nodes = [];
7714         if(start <= end){
7715             for(var i = start; i <= end; i++){
7716                 nodes.push(ns[i]);
7717             }
7718         } else{
7719             for(var i = start; i >= end; i--){
7720                 nodes.push(ns[i]);
7721             }
7722         }
7723         return nodes;
7724     },
7725
7726     /**
7727      * Finds the index of the passed node
7728      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
7729      * @return {Number} The index of the node or -1
7730      */
7731     indexOf : function(node){
7732         node = this.getNode(node);
7733         if(typeof node.nodeIndex == "number"){
7734             return node.nodeIndex;
7735         }
7736         var ns = this.nodes;
7737         for(var i = 0, len = ns.length; i < len; i++){
7738             if(ns[i] == node){
7739                 return i;
7740             }
7741         }
7742         return -1;
7743     }
7744 });
7745 /*
7746  * - LGPL
7747  *
7748  * based on jquery fullcalendar
7749  * 
7750  */
7751
7752
7753 /**
7754  * @class Roo.bootstrap.Calendar
7755  * @extends Roo.bootstrap.Component
7756  * Bootstrap Calendar class
7757     
7758  * @constructor
7759  * Create a new Container
7760  * @param {Object} config The config object
7761  */
7762
7763 Roo.bootstrap.Calendar = function(config){
7764     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
7765      this.addEvents({
7766         /**
7767              * @event select
7768              * Fires when a date is selected
7769              * @param {DatePicker} this
7770              * @param {Date} date The selected date
7771              */
7772         'select': true,
7773         /**
7774              * @event monthchange
7775              * Fires when the displayed month changes 
7776              * @param {DatePicker} this
7777              * @param {Date} date The selected month
7778              */
7779         'monthchange': true,
7780         /**
7781              * @event evententer
7782              * Fires when mouse over an event
7783              * @param {Calendar} this
7784              * @param {event} Event
7785              */
7786         'evententer': true,
7787         /**
7788              * @event eventleave
7789              * Fires when the mouse leaves an
7790              * @param {Calendar} this
7791              * @param {event}
7792              */
7793         'eventleave': true
7794         
7795     });
7796
7797 };
7798
7799 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
7800     
7801      /**
7802      * @cfg {Number} startDay
7803      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
7804      */
7805     startDay : 0,
7806       
7807     getAutoCreate : function(){
7808         
7809         
7810         fc_button = function(name, corner, style, content ) {
7811             return Roo.apply({},{
7812                 tag : 'span',
7813                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
7814                          (corner.length ?
7815                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
7816                             ''
7817                         ),
7818                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
7819                 unselectable: 'on'
7820             });
7821         };
7822         
7823         var header = {
7824             tag : 'table',
7825             cls : 'fc-header',
7826             style : 'width:100%',
7827             cn : [
7828                 {
7829                     tag: 'tr',
7830                     cn : [
7831                         {
7832                             tag : 'td',
7833                             cls : 'fc-header-left',
7834                             cn : [
7835                                 fc_button('prev', 'left', 'arrow', '&#8249;' ),
7836                                 fc_button('next', 'right', 'arrow', '&#8250;' ),
7837                                 { tag: 'span', cls: 'fc-header-space' },
7838                                 fc_button('today', 'left right', '', 'today' )  // neds state disabled..
7839                                 
7840                                 
7841                             ]
7842                         },
7843                         
7844                         {
7845                             tag : 'td',
7846                             cls : 'fc-header-center',
7847                             cn : [
7848                                 {
7849                                     tag: 'span',
7850                                     cls: 'fc-header-title',
7851                                     cn : {
7852                                         tag: 'H2',
7853                                         html : 'month / year'
7854                                     }
7855                                 }
7856                                 
7857                             ]
7858                         },
7859                         {
7860                             tag : 'td',
7861                             cls : 'fc-header-right',
7862                             cn : [
7863                           /*      fc_button('month', 'left', '', 'month' ),
7864                                 fc_button('week', '', '', 'week' ),
7865                                 fc_button('day', 'right', '', 'day' )
7866                             */    
7867                                 
7868                             ]
7869                         }
7870                         
7871                     ]
7872                 }
7873             ]
7874         };
7875         
7876        
7877         var cal_heads = function() {
7878             var ret = [];
7879             // fixme - handle this.
7880             
7881             for (var i =0; i < Date.dayNames.length; i++) {
7882                 var d = Date.dayNames[i];
7883                 ret.push({
7884                     tag: 'th',
7885                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
7886                     html : d.substring(0,3)
7887                 });
7888                 
7889             }
7890             ret[0].cls += ' fc-first';
7891             ret[6].cls += ' fc-last';
7892             return ret;
7893         };
7894         var cal_cell = function(n) {
7895             return  {
7896                 tag: 'td',
7897                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
7898                 cn : [
7899                     {
7900                         cn : [
7901                             {
7902                                 cls: 'fc-day-number',
7903                                 html: 'D'
7904                             },
7905                             {
7906                                 cls: 'fc-day-content',
7907                              
7908                                 cn : [
7909                                      {
7910                                         style: 'position: relative;' // height: 17px;
7911                                     }
7912                                 ]
7913                             }
7914                             
7915                             
7916                         ]
7917                     }
7918                 ]
7919                 
7920             }
7921         };
7922         var cal_rows = function() {
7923             
7924             var ret = []
7925             for (var r = 0; r < 6; r++) {
7926                 var row= {
7927                     tag : 'tr',
7928                     cls : 'fc-week',
7929                     cn : []
7930                 };
7931                 
7932                 for (var i =0; i < Date.dayNames.length; i++) {
7933                     var d = Date.dayNames[i];
7934                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
7935
7936                 }
7937                 row.cn[0].cls+=' fc-first';
7938                 row.cn[0].cn[0].style = 'min-height:90px';
7939                 row.cn[6].cls+=' fc-last';
7940                 ret.push(row);
7941                 
7942             }
7943             ret[0].cls += ' fc-first';
7944             ret[4].cls += ' fc-prev-last';
7945             ret[5].cls += ' fc-last';
7946             return ret;
7947             
7948         };
7949         
7950         var cal_table = {
7951             tag: 'table',
7952             cls: 'fc-border-separate',
7953             style : 'width:100%',
7954             cellspacing  : 0,
7955             cn : [
7956                 { 
7957                     tag: 'thead',
7958                     cn : [
7959                         { 
7960                             tag: 'tr',
7961                             cls : 'fc-first fc-last',
7962                             cn : cal_heads()
7963                         }
7964                     ]
7965                 },
7966                 { 
7967                     tag: 'tbody',
7968                     cn : cal_rows()
7969                 }
7970                   
7971             ]
7972         };
7973          
7974          var cfg = {
7975             cls : 'fc fc-ltr',
7976             cn : [
7977                 header,
7978                 {
7979                     cls : 'fc-content',
7980                     style : "position: relative;",
7981                     cn : [
7982                         {
7983                             cls : 'fc-view fc-view-month fc-grid',
7984                             style : 'position: relative',
7985                             unselectable : 'on',
7986                             cn : [
7987                                 {
7988                                     cls : 'fc-event-container',
7989                                     style : 'position:absolute;z-index:8;top:0;left:0;'
7990                                 },
7991                                 cal_table
7992                             ]
7993                         }
7994                     ]
7995     
7996                 }
7997            ] 
7998             
7999         };
8000         
8001          
8002         
8003         return cfg;
8004     },
8005     
8006     
8007     initEvents : function()
8008     {
8009         if(!this.store){
8010             throw "can not find store for combo";
8011         }
8012         
8013         this.store = Roo.factory(this.store, Roo.data);
8014         this.store.on('load', this.onLoad, this);
8015         
8016         this.resize();
8017         this.cells = this.el.select('.fc-day',true);
8018         this.textNodes = this.el.query('.fc-day-number');
8019         this.cells.addClassOnOver('fc-state-hover');
8020         
8021         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
8022         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
8023         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
8024         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
8025         
8026         this.on('monthchange', this.onMonthChange, this);
8027         
8028         this.update(new Date().clearTime());
8029     },
8030     
8031     resize : function() {
8032         var sz  = this.el.getSize();
8033         
8034         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
8035         this.el.select('.fc-day-content div',true).setHeight(34);
8036     },
8037     
8038     
8039     // private
8040     showPrevMonth : function(e){
8041         this.update(this.activeDate.add("mo", -1));
8042     },
8043     showToday : function(e){
8044         this.update(new Date().clearTime());
8045     },
8046     // private
8047     showNextMonth : function(e){
8048         this.update(this.activeDate.add("mo", 1));
8049     },
8050
8051     // private
8052     showPrevYear : function(){
8053         this.update(this.activeDate.add("y", -1));
8054     },
8055
8056     // private
8057     showNextYear : function(){
8058         this.update(this.activeDate.add("y", 1));
8059     },
8060
8061     
8062    // private
8063     update : function(date)
8064     {
8065         var vd = this.activeDate;
8066         this.activeDate = date;
8067         if(vd && this.el){
8068             var t = date.getTime();
8069             if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
8070                 Roo.log('using add remove');
8071                 this.cells.removeClass("fc-state-highlight");
8072                 this.cells.each(function(c){
8073                    if(c.dateValue == t){
8074                        c.addClass("fc-state-highlight");
8075                        setTimeout(function(){
8076                             try{c.dom.firstChild.focus();}catch(e){}
8077                        }, 50);
8078                        return false;
8079                    }
8080                    return true;
8081                 });
8082                 return;
8083             }
8084         }
8085         
8086         var days = date.getDaysInMonth();
8087         
8088         var firstOfMonth = date.getFirstDateOfMonth();
8089         var startingPos = firstOfMonth.getDay()-this.startDay;
8090
8091         if(startingPos < this.startDay){
8092             startingPos += 7;
8093         }
8094
8095         var pm = date.add("mo", -1);
8096         var prevStart = pm.getDaysInMonth()-startingPos;
8097
8098         var cells = this.cells.elements;
8099         var textEls = this.textNodes;
8100         days += startingPos;
8101
8102         // convert everything to numbers so it's fast
8103         var day = 86400000;
8104         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
8105         var today = new Date().clearTime().getTime();
8106         var sel = date.clearTime().getTime();
8107         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
8108         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
8109         var ddMatch = this.disabledDatesRE;
8110         var ddText = this.disabledDatesText;
8111         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
8112         var ddaysText = this.disabledDaysText;
8113         var format = this.format;
8114
8115         var setCellClass = function(cal, cell){
8116             cell.title = "";
8117             var t = d.getTime();
8118             
8119             cell.dateValue = t;
8120             if(t == today){
8121                 cell.className += " fc-today";
8122                 cell.title = cal.todayText;
8123             }
8124             if(t == sel){
8125                 cell.className += " fc-state-highlight";
8126                 //setTimeout(function(){
8127                 //    try{cell.firstChild.focus();}catch(e){}
8128                 //}, 50);
8129             }
8130             // disabling
8131             if(t < min) {
8132                 cell.className = " fc-state-disabled";
8133                 cell.title = cal.minText;
8134                 return;
8135             }
8136             if(t > max) {
8137                 cell.className = " fc-state-disabled";
8138                 cell.title = cal.maxText;
8139                 return;
8140             }
8141             if(ddays){
8142                 if(ddays.indexOf(d.getDay()) != -1){
8143                     cell.title = ddaysText;
8144                     cell.className = " fc-state-disabled";
8145                 }
8146             }
8147             if(ddMatch && format){
8148                 var fvalue = d.dateFormat(format);
8149                 if(ddMatch.test(fvalue)){
8150                     cell.title = ddText.replace("%0", fvalue);
8151                     cell.className = " fc-state-disabled";
8152                 }
8153             }
8154             if (!cell.initialClassName) {
8155                 cell.initialClassName = cell.dom.className;
8156             }
8157             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
8158         };
8159
8160         var i = 0;
8161         for(; i < startingPos; i++) {
8162             textEls[i].innerHTML = (++prevStart);
8163             d.setDate(d.getDate()+1);
8164             cells[i].className = "fc-past fc-other-month";
8165             setCellClass(this, cells[i]);
8166         }
8167         for(; i < days; i++){
8168             intDay = i - startingPos + 1;
8169             textEls[i].innerHTML = (intDay);
8170             d.setDate(d.getDate()+1);
8171             cells[i].className = ''; // "x-date-active";
8172             setCellClass(this, cells[i]);
8173         }
8174         var extraDays = 0;
8175         
8176         for(; i < 42; i++) {
8177             textEls[i].innerHTML = (++extraDays);
8178             d.setDate(d.getDate()+1);
8179             cells[i].className = "fc-future fc-other-month";
8180             setCellClass(this, cells[i]);
8181         }
8182         
8183         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
8184         
8185         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
8186         
8187         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
8188         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
8189         
8190         if(totalRows != 6){
8191             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
8192             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
8193         }
8194         
8195         this.fireEvent('monthchange', this, date);
8196         
8197         
8198         /*
8199         if(!this.internalRender){
8200             var main = this.el.dom.firstChild;
8201             var w = main.offsetWidth;
8202             this.el.setWidth(w + this.el.getBorderWidth("lr"));
8203             Roo.fly(main).setWidth(w);
8204             this.internalRender = true;
8205             // opera does not respect the auto grow header center column
8206             // then, after it gets a width opera refuses to recalculate
8207             // without a second pass
8208             if(Roo.isOpera && !this.secondPass){
8209                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
8210                 this.secondPass = true;
8211                 this.update.defer(10, this, [date]);
8212             }
8213         }
8214         */
8215         
8216     },
8217     
8218     findCell : function(dt) {
8219         dt = dt.clearTime().getTime();
8220         var ret = false;
8221         this.cells.each(function(c){
8222             //Roo.log("check " +c.dateValue + '?=' + dt);
8223             if(c.dateValue == dt){
8224                 ret = c;
8225                 return false;
8226             }
8227             return true;
8228         });
8229         
8230         return ret;
8231     },
8232     
8233     findCells : function(ev) {
8234         var s = ev.start.clone().clearTime().getTime();
8235         var e= ev.end.clone().clearTime().getTime();
8236         var ret = [];
8237         this.cells.each(function(c){
8238             //Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
8239             
8240             if(c.dateValue > e){
8241                 return ;
8242             }
8243             if(c.dateValue < s){
8244                 return ;
8245             }
8246             ret.push(c);
8247         });
8248         
8249         return ret;    
8250     },
8251     
8252     findBestRow: function(cells)
8253     {
8254         var ret = 0;
8255         
8256         for (var i =0 ; i < cells.length;i++) {
8257             ret  = Math.max(cells[i].rows || 0,ret);
8258         }
8259         return ret;
8260         
8261     },
8262     
8263     
8264     addItem : function(ev)
8265     {
8266         // look for vertical location slot in
8267         var cells = this.findCells(ev);
8268         
8269         ev.row = this.findBestRow(cells);
8270         
8271         // work out the location.
8272         
8273         var crow = false;
8274         var rows = [];
8275         for(var i =0; i < cells.length; i++) {
8276             if (!crow) {
8277                 crow = {
8278                     start : cells[i],
8279                     end :  cells[i]
8280                 };
8281                 continue;
8282             }
8283             if (crow.start.getY() == cells[i].getY()) {
8284                 // on same row.
8285                 crow.end = cells[i];
8286                 continue;
8287             }
8288             // different row.
8289             rows.push(crow);
8290             crow = {
8291                 start: cells[i],
8292                 end : cells[i]
8293             };
8294             
8295         }
8296         
8297         rows.push(crow);
8298         ev.els = [];
8299         ev.rows = rows;
8300         ev.cells = cells;
8301         for (var i = 0; i < cells.length;i++) {
8302             cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
8303             
8304         }
8305         
8306         this.calevents.push(ev);
8307     },
8308     
8309     clearEvents: function() {
8310         
8311         if(!this.calevents){
8312             return;
8313         }
8314         
8315         Roo.each(this.cells.elements, function(c){
8316             c.rows = 0;
8317         });
8318         
8319         Roo.each(this.calevents, function(e) {
8320             Roo.each(e.els, function(el) {
8321                 el.un('mouseenter' ,this.onEventEnter, this);
8322                 el.un('mouseleave' ,this.onEventLeave, this);
8323                 el.remove();
8324             },this);
8325         },this);
8326         
8327     },
8328     
8329     renderEvents: function()
8330     {   
8331         // first make sure there is enough space..
8332         
8333         this.cells.each(function(c) {
8334 //            Roo.log(c.select('.fc-day-content div',true).first(), Math.max(34, c.rows * 20));
8335             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
8336         });
8337         
8338         for (var e = 0; e < this.calevents.length; e++) {
8339             var ev = this.calevents[e];
8340             var cells = ev.cells;
8341             var rows = ev.rows;
8342             
8343             for(var i =0; i < rows.length; i++) {
8344                 
8345                  
8346                 // how many rows should it span..
8347                 
8348                 var  cfg = {
8349                     cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
8350                     style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
8351                     
8352                     unselectable : "on",
8353                     cn : [
8354                         {
8355                             cls: 'fc-event-inner',
8356                             cn : [
8357                                 {
8358                                   tag:'span',
8359                                   cls: 'fc-event-time',
8360                                   html : cells.length > 1 ? '' : ev.time
8361                                 },
8362                                 {
8363                                   tag:'span',
8364                                   cls: 'fc-event-title',
8365                                   html : String.format('{0}', ev.title)
8366                                 }
8367                                 
8368                                 
8369                             ]
8370                         },
8371                         {
8372                             cls: 'ui-resizable-handle ui-resizable-e',
8373                             html : '&nbsp;&nbsp;&nbsp'
8374                         }
8375                         
8376                     ]
8377                 };
8378                 if (i == 0) {
8379                     cfg.cls += ' fc-event-start';
8380                 }
8381                 if ((i+1) == rows.length) {
8382                     cfg.cls += ' fc-event-end';
8383                 }
8384                 
8385                 var ctr = this.el.select('.fc-event-container',true).first();
8386                 var cg = ctr.createChild(cfg);
8387                 
8388                 cg.on('mouseenter' ,this.onEventEnter, this);
8389                 cg.on('mouseleave' ,this.onEventLeave, this);
8390                 
8391                 ev.els.push(cg);
8392                 
8393                 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
8394                 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
8395                 //Roo.log(cg);
8396                 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
8397                 cg.setWidth(ebox.right - sbox.x -2);
8398             }
8399             
8400             
8401         }
8402         
8403     },
8404     
8405     onEventEnter: function (e, el,c,d) {
8406         this.fireEvent('evententer', this, el);
8407     },
8408     
8409     onEventLeave: function (e, el,c,d) {
8410         this.fireEvent('eventleave', this, el);
8411     },
8412     
8413     onMonthChange: function () {
8414         this.store.load();
8415     },
8416     
8417     onLoad: function () {
8418         
8419         this.clearEvents();
8420         
8421         this.calevents = [];
8422         var cal = this;
8423         if(this.store.getCount() > 0){
8424             this.store.data.each(function(d){
8425                cal.addItem({
8426                     start: new Date(d.data.start_dt),
8427                     end : new Date(d.data.end_dt),
8428                     time : d.data.start_time,
8429                     title : d.data.title
8430                 });
8431             });
8432         }
8433         
8434         this.renderEvents();
8435     }
8436 });
8437
8438  
8439  /*
8440  * - LGPL
8441  *
8442  * element
8443  * 
8444  */
8445
8446 /**
8447  * @class Roo.bootstrap.Popover
8448  * @extends Roo.bootstrap.Component
8449  * Bootstrap Popover class
8450  * @cfg {String} html contents of the popover   (or false to use children..)
8451  * @cfg {String} title of popover (or false to hide)
8452  * @cfg {String} placement how it is placed
8453  * @cfg {String} trigger click || hover (or false to trigger manually)
8454  * @cfg {String} over what (parent or false to trigger manually.)
8455  * 
8456  * @constructor
8457  * Create a new Popover
8458  * @param {Object} config The config object
8459  */
8460
8461 Roo.bootstrap.Popover = function(config){
8462     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
8463 };
8464
8465 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
8466     
8467     title: 'Fill in a title',
8468     html: false,
8469     
8470     placement : 'right',
8471     trigger : 'hover', // hover
8472     
8473     over: 'parent',
8474     
8475     getChildContainer : function()
8476     {
8477         return this.el.select('.popover-content',true).first();
8478     },
8479     
8480     getAutoCreate : function(){
8481          Roo.log('make popover?');
8482         var cfg = {
8483            cls : 'popover',
8484            style: 'display:block',
8485            cn : [
8486                 {
8487                     cls : 'arrow'
8488                 },
8489                 {
8490                     cls : 'popover-inner',
8491                     cn : [
8492                         {
8493                             tag: 'h3',
8494                             cls: 'popover-title',
8495                             html : this.title
8496                         },
8497                         {
8498                             cls : 'popover-content',
8499                             html : this.html
8500                         }
8501                     ]
8502                     
8503                 }
8504            ]
8505         };
8506         
8507         return cfg;
8508     },
8509     // as it get's added to the bottom of the page.
8510     onRender : function(ct, position)
8511     {
8512         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
8513         if(!this.el){
8514             var cfg = Roo.apply({},  this.getAutoCreate());
8515             cfg.id = Roo.id();
8516             
8517             if (this.cls) {
8518                 cfg.cls += ' ' + this.cls;
8519             }
8520             if (this.style) {
8521                 cfg.style = this.style;
8522             }
8523             Roo.log("adding to ")
8524             this.el = Roo.get(document.body).createChild(cfg, position);
8525             Roo.log(this.el);
8526         }
8527         this.initEvents();
8528     },
8529     
8530     initEvents : function()
8531     {
8532         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
8533         this.el.enableDisplayMode('block');
8534         this.el.hide();
8535         if (this.over === false) {
8536             return; 
8537         }
8538         if (this.triggers === false) {
8539             return;
8540         }
8541         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8542         var triggers = this.trigger ? this.trigger.split(' ') : [];
8543         Roo.each(triggers, function(trigger) {
8544         
8545             if (trigger == 'click') {
8546                 on_el.on('click', this.toggle, this);
8547             } else if (trigger != 'manual') {
8548                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
8549                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
8550       
8551                 on_el.on(eventIn  ,this.enter, this);
8552                 on_el.on(eventOut, this.leave, this);
8553             }
8554         }, this);
8555         
8556     },
8557     
8558     
8559     // private
8560     timeout : null,
8561     hoverState : null,
8562     
8563     toggle : function () {
8564         this.hoverState == 'in' ? this.leave() : this.enter();
8565     },
8566     
8567     enter : function () {
8568        
8569     
8570         clearTimeout(this.timeout);
8571     
8572         this.hoverState = 'in'
8573     
8574         if (!this.delay || !this.delay.show) {
8575             this.show();
8576             return 
8577         }
8578         var _t = this;
8579         this.timeout = setTimeout(function () {
8580             if (_t.hoverState == 'in') {
8581                 _t.show();
8582             }
8583         }, this.delay.show)
8584     },
8585     leave : function() {
8586         clearTimeout(this.timeout);
8587     
8588         this.hoverState = 'out'
8589     
8590         if (!this.delay || !this.delay.hide) {
8591             this.hide();
8592             return 
8593         }
8594         var _t = this;
8595         this.timeout = setTimeout(function () {
8596             if (_t.hoverState == 'out') {
8597                 _t.hide();
8598             }
8599         }, this.delay.hide)
8600     },
8601     
8602     show : function (on_el)
8603     {
8604         if (!on_el) {
8605             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
8606         }
8607         // set content.
8608         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
8609         if (this.html !== false) {
8610             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
8611         }
8612         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
8613         if (!this.title.length) {
8614             this.el.select('.popover-title',true).hide();
8615         }
8616         
8617         var placement = typeof this.placement == 'function' ?
8618             this.placement.call(this, this.el, on_el) :
8619             this.placement;
8620             
8621         var autoToken = /\s?auto?\s?/i;
8622         var autoPlace = autoToken.test(placement);
8623         if (autoPlace) {
8624             placement = placement.replace(autoToken, '') || 'top';
8625         }
8626         
8627         //this.el.detach()
8628         //this.el.setXY([0,0]);
8629         this.el.show();
8630         this.el.dom.style.display='block';
8631         this.el.addClass(placement);
8632         
8633         //this.el.appendTo(on_el);
8634         
8635         var p = this.getPosition();
8636         var box = this.el.getBox();
8637         
8638         if (autoPlace) {
8639             // fixme..
8640         }
8641         var align = Roo.bootstrap.Popover.alignment[placement]
8642         this.el.alignTo(on_el, align[0],align[1]);
8643         //var arrow = this.el.select('.arrow',true).first();
8644         //arrow.set(align[2], 
8645         
8646         this.el.addClass('in');
8647         this.hoverState = null;
8648         
8649         if (this.el.hasClass('fade')) {
8650             // fade it?
8651         }
8652         
8653     },
8654     hide : function()
8655     {
8656         this.el.setXY([0,0]);
8657         this.el.removeClass('in');
8658         this.el.hide();
8659         
8660     }
8661     
8662 });
8663
8664 Roo.bootstrap.Popover.alignment = {
8665     'left' : ['r-l', [-10,0], 'right'],
8666     'right' : ['l-r', [10,0], 'left'],
8667     'bottom' : ['t-b', [0,10], 'top'],
8668     'top' : [ 'b-t', [0,-10], 'bottom']
8669 };
8670
8671