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