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