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