Roo/form/ComboBoxArray.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  
17  * 
18  * @constructor
19  * Do not use directly - it does not do anything..
20  * @param {Object} config The config object
21  */
22
23
24
25 Roo.bootstrap.Component = function(config){
26     Roo.bootstrap.Component.superclass.constructor.call(this, config);
27 };
28
29 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
30     
31     
32     allowDomMove : false, // to stop relocations in parent onRender...
33     
34     cls : false,
35     
36     style : false,
37     
38     autoCreate : false,
39     
40     initEvents : function() {  },
41     
42     xattr : false,
43     
44     parentId : false,
45     
46     parent: function() {
47         // returns the parent component..
48         return Roo.ComponentMgr.get(this.parentId)
49         
50         
51     },
52     
53     // private
54     onRender : function(ct, position)
55     {
56        // Roo.log("Call onRender: " + this.xtype);
57         
58         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
59         
60         if(this.el){
61             if (this.el.attr('xtype')) {
62                 this.el.dom.removeAttribute('xtype');
63                 this.initEvents();
64             }
65             
66             return;
67         }
68         
69          
70         
71         var cfg = Roo.apply({},  this.getAutoCreate());
72         cfg.id = Roo.id();
73         
74         // fill in the extra attributes 
75         if (this.xattr && typeof(this.xattr) =='object') {
76             for (var i in this.xattr) {
77                 cfg[i] = this.xattr[i];
78             }
79         }
80         
81         if (this.cls) {
82             cfg.cls += ' ' + this.cls;
83         }
84         if (this.style) { // fixme needs to support more complex style data.
85             cfg.style = this.style;
86         }
87         this.el = ct.createChild(cfg, position);
88         if(this.tabIndex !== undefined){
89             this.el.dom.setAttribute('tabIndex', this.tabIndex);
90         }
91         this.initEvents();
92         
93         
94     },
95     
96     getChildContainer : function()
97     {
98         return this.el;
99     },
100     
101     addxtype : function (tree, cntr) {
102         var cn = this;
103         cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
104         
105         // render the element if it's not BODY.
106         if (tree.xtype != 'Body') {
107             
108             cn = Roo.factory(tree);
109            // Roo.log(cn);
110             cn.parentType = this.xtype; //??
111             cn.parentId = this.id;
112             
113             // does the container contain child eleemnts with 'xtype' attributes.
114             // that match this xtype..
115             // note - when we render we create these as well..
116             // so we should check to see if body has xtype set.
117             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
118             
119                 var echild = Roo.get(this[cntr]()).child('*[xtype]');
120                 if (echild) {
121                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
122                     cn.el = echild;
123                     //echild.dom.removeAttribute('xtype');
124                 } else {
125                     Roo.log("missing child for " + this.xtype);
126                 }
127             }
128             cn.render(this[cntr]());
129             // then add the element..
130         }
131         
132         
133         // handle the kids..
134         
135         var nitems = [];
136         if (typeof (tree.menu) != 'undefined') {
137             tree.menu.parentType = cn.xtype;
138             tree.menu.triggerEl = cn.el;
139             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
140             
141         }
142         
143         if (!tree.items || !tree.items.length) {
144             cn.items = nitems;
145             return cn;
146         }
147         var items = tree.items;
148         delete tree.items;
149         
150         //Roo.log(items.length);
151             // add the items..
152         for(var i =0;i < items.length;i++) {
153             nitems.push(cn.addxtype(Roo.apply({}, items[i])));
154         }
155         
156         cn.items = nitems;
157         
158         
159         return cn;
160     }
161     
162     
163     
164     
165 });
166
167  /*
168  * - LGPL
169  *
170  * page container.
171  * 
172  */ 
173 Roo.bootstrap.Body = function(config){
174     Roo.bootstrap.Body.superclass.constructor.call(this, config);
175     this.el = Roo.get(document.body);
176 };
177
178 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
179       
180         autoCreate : {
181         cls: 'container'
182     },
183     onRender : function(ct, position){
184         
185         
186         //this.el.addClass([this.fieldClass, this.cls]);
187         
188     }
189     
190     
191  
192    
193 });
194
195  /*
196  * - LGPL
197  *
198  * button group
199  * 
200  */
201
202
203 /**
204  * @class Roo.bootstrap.ButtonGroup
205  * @extends Roo.bootstrap.Component
206  * Bootstrap ButtonGroup class
207  * @cfg {String} size lg | sm | xs (default empty normal)
208  * @cfg {String} align vertical | justified  (default none)
209  * @cfg {String} direction up | down (default down)
210  * @cfg {Boolean} toolbar false | true
211  * @cfg {Boolean} btn true | false
212  * 
213  * 
214  * @constructor
215  * Create a new Input
216  * @param {Object} config The config object
217  */
218
219 Roo.bootstrap.ButtonGroup = function(config){
220     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
221 };
222
223 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
224     
225     size: '',
226     align: '',
227     direction: '',
228     toolbar: false,
229     btn: true,
230
231     getAutoCreate : function(){
232         var cfg = {
233             cls: 'btn-group',
234             html : null
235         }
236         
237         cfg.html = this.html || cfg.html;
238         
239         if (this.toolbar) {
240             cfg = {
241                 cls: 'btn-toolbar',
242                 html: null
243             }
244             
245             return cfg;
246         }
247         
248         if (['vertical','justified'].indexOf(this.align)!==-1) {
249             cfg.cls = 'btn-group-' + this.align;
250             
251             if (this.align == 'justified') {
252                 console.log(this.items);
253             }
254         }
255         
256         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
257             cfg.cls += ' btn-group-' + this.size;
258         }
259         
260         if (this.direction == 'up') {
261             cfg.cls += ' dropup' ;
262         }
263         
264         return cfg;
265     }
266    
267 });
268
269  /*
270  * - LGPL
271  *
272  * button
273  * 
274  */
275
276 /**
277  * @class Roo.bootstrap.Button
278  * @extends Roo.bootstrap.Component
279  * Bootstrap Button class
280  * @cfg {String} html The button content
281  * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
282  * @cfg {String} size empty | lg | sm | xs
283  * @cfg {String} tag empty | a | input | submit
284  * @cfg {String} href empty or href
285  * @cfg {Boolean} disabled false | true
286  * @cfg {Boolean} isClose false | true
287  * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
288  * @cfg {String} badge text for badge
289  * @cfg {String} theme default (or empty) | glow
290  * @cfg {Boolean} inverse false | true
291  * @cfg {Boolean} toggle false | true
292  * @cfg {String} ontext text for on toggle state
293  * @cfg {String} offtext text for off toggle state
294  * @cfg {Boolean} defaulton true | false
295  * 
296  * @constructor
297  * Create a new button
298  * @param {Object} config The config object
299  */
300
301
302 Roo.bootstrap.Button = function(config){
303     Roo.bootstrap.Button.superclass.constructor.call(this, config);
304     this.addEvents({
305         // raw events
306         /**
307          * @event click
308          * The raw click event for the entire grid.
309          * @param {Roo.EventObject} e
310          */
311         "click" : true
312     });
313 };
314
315 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
316     html: false,
317     active: false,
318     weight: '',
319     size: '',
320     tag: 'button',
321     href: '',
322     disabled: false,
323     isClose: false,
324     glyphicon: '',
325     badge: '',
326     theme: 'default',
327     inverse: false,
328     
329     toggle: false,
330     ontext: 'ON',
331     offtext: 'OFF',
332     defaulton: true,
333     
334     getAutoCreate : function(){
335         
336         var cfg = {
337             tag : 'button',
338             cls : 'roo-button',
339             html: 'hello'
340         };
341         
342         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
343             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
344             this.tag = 'button';
345         } else {
346             cfg.tag = this.tag;
347         }
348         cfg.html = this.html || cfg.html;
349         
350         if (this.toggle===true) {
351             cfg={
352                 tag: 'div',
353                 cls: 'slider-frame roo-button',
354                 cn: [
355                     {
356                         tag: 'span',
357                         'data-on-text':'ON',
358                         'data-off-text':'OFF',
359                         cls: 'slider-button',
360                         html: this.offtext
361                     }
362                 ]
363             };
364             
365             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
366                 cfg.cls += ' '+this.weight;
367             }
368             
369             return cfg;
370         }
371         
372         if (this.isClose) {
373             cfg.cls += ' close';
374             
375             cfg["aria-hidden"] = true;
376             
377             cfg.html = "&times;";
378             
379             return cfg;
380         }
381         
382          
383         if (this.theme==='default') {
384             cfg.cls = 'btn roo-button';
385             
386             if (this.parentType != 'Navbar') {
387                 this.weight = this.weight.length ?  this.weight : 'default';
388             }
389             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
390                 
391                 cfg.cls += ' btn-' + this.weight;
392             }
393         } else if (this.theme==='glow') {
394             
395             cfg.tag = 'a';
396             cfg.cls = 'btn-glow roo-button';
397             
398             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
399                 
400                 cfg.cls += ' ' + this.weight;
401             }
402         }
403    
404         
405         if (this.inverse) {
406             this.cls += ' inverse';
407         }
408         
409         
410         if (this.active) {
411             cfg.cls += ' active';
412         }
413         
414         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
415          
416         //gsRoo.log(this.parentType);
417         if (this.parentType === 'Navbar') {
418             cfg.tag = 'li';
419             
420             cfg.cls = '';
421             cfg.cn =  [{
422                 tag : 'a',
423                 cls : 'roo-button',
424                 html : this.html,
425                 href : this.href || '#'
426             }];
427             if (this.menu) {
428                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
429                 cfg.cls += ' dropdown';
430             }   
431             
432             delete cfg.html;
433             
434         } else if (this.menu) {
435             cfg.tag = 'a';
436             cfg.cls += ' dropdown test';
437         }
438         
439         
440         
441         if (this.disabled) {
442             cfg.disabled = 'disabled';
443         }
444         //????
445         if (this.items) {
446             Roo.log('changing to ul' );
447             cfg.tag = 'ul';
448             this.glyphicon = 'caret';
449         }
450         
451         if (this.glyphicon) {
452             cfg.html = ' ' + cfg.html;
453             
454             cfg.cn = [
455                 {
456                     tag: 'span',
457                     cls: 'glyphicon glyphicon-' + this.glyphicon
458                 }
459             ];
460         }
461         
462         if (this.badge) {
463             cfg.html += ' ';
464             
465             cfg.tag = 'a';
466             
467             cfg.cls='btn roo-button';
468             
469             cfg.href=this.href;
470             
471             cfg.cn = [
472                 cfg.html,
473                 {
474                     tag: 'span',
475                     cls: 'badge',
476                     html: this.badge
477                 }
478             ];
479             
480             cfg.html='';
481         }
482         
483         if (cfg.tag !== 'a' && this.href !== '') {
484             throw "Tag must be a to set href.";
485         } else if (this.href.length > 0) {
486             cfg.href = this.href;
487         }
488         
489         return cfg;
490     },
491     initEvents: function() {
492        // Roo.log('init events?');
493        // Roo.log(this.el.dom);
494        if (this.el.hasClass('roo-button')) {
495             this.el.on('click', this.onClick, this);
496        } else {
497             this.el.select('.roo-button').on('click', this.onClick, this);
498        }
499        
500        
501         
502     },
503     onClick : function(e)
504     {
505         Roo.log('button on click ');
506         e.preventDefault();
507         this.fireEvent('click', this, e);
508     }
509     
510     
511 });
512
513  /*
514  * - LGPL
515  *
516  * column
517  * 
518  */
519
520 /**
521  * @class Roo.bootstrap.Column
522  * @extends Roo.bootstrap.Component
523  * Bootstrap Column class
524  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
525  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
526  * @cfg {Number} md colspan out of 12 for computer-sized screens
527  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
528  * @cfg {String} html content of column.
529  * 
530  * @constructor
531  * Create a new Column
532  * @param {Object} config The config object
533  */
534
535 Roo.bootstrap.Column = function(config){
536     Roo.bootstrap.Column.superclass.constructor.call(this, config);
537 };
538
539 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
540     
541     xs: null,
542     sm: null,
543     md: null,
544     lg: null,
545     html: '',
546     offset: 0,
547     
548     getAutoCreate : function(){
549         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
550         
551         cfg = {
552             tag: 'div',
553             cls: 'column'
554         };
555         
556         var settings=this;
557         ['xs','sm','md','lg'].map(function(size){
558             if (settings[size]) {
559                 cfg.cls += ' col-' + size + '-' + settings[size];
560             }
561         });
562         if (this.html.length) {
563             cfg.html = this.html;
564         }
565         
566         return cfg;
567     }
568    
569 });
570
571  
572
573  /*
574  * - LGPL
575  *
576  * page container.
577  * 
578  */
579
580
581 /**
582  * @class Roo.bootstrap.Container
583  * @extends Roo.bootstrap.Component
584  * Bootstrap Container class
585  * @cfg {Boolean} jumbotron is it a jumbotron element
586  * @cfg {String} html content of element
587  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
588  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
589  * @cfg {String} header content of header (for panel)
590  * @cfg {String} footer content of footer (for panel)
591  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
592  *     
593  * @constructor
594  * Create a new Container
595  * @param {Object} config The config object
596  */
597
598 Roo.bootstrap.Container = function(config){
599     Roo.bootstrap.Container.superclass.constructor.call(this, config);
600 };
601
602 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
603     
604     jumbotron : false,
605     well: '',
606     panel : '',
607     header: '',
608     footer : '',
609     sticky: '',
610   
611      
612     getChildContainer : function() {
613         if (this.panel.length) {
614             return this.el.select('.panel-body',true).first();
615         }
616         
617         return this.el;
618     },
619     
620     
621     getAutoCreate : function(){
622         
623         var cfg = {
624             html : '',
625             cls : ''
626         };
627         if (this.jumbotron) {
628             cfg.cls = 'jumbotron';
629         }
630         if (this.cls) {
631             cfg.cls = this.cls + '';
632         }
633         
634         if (this.sticky.length) {
635             var bd = Roo.get(document.body);
636             if (!bd.hasClass('bootstrap-sticky')) {
637                 bd.addClass('bootstrap-sticky');
638                 Roo.select('html',true).setStyle('height', '100%');
639             }
640              
641             cfg.cls += 'bootstrap-sticky-' + this.sticky;
642         }
643         
644         
645         if (this.well.length) {
646             switch (this.well) {
647                 case 'lg':
648                 case 'sm':
649                     cfg.cls +=' well well-' +this.well;
650                     break;
651                 default:
652                     cfg.cls +=' well';
653                     break;
654             }
655         }
656         
657         var body = cfg;
658         
659         if (this.panel.length) {
660             cfg.cls += 'panel panel-' + this.panel;
661             cfg.cn = [];
662             if (this.header.length) {
663                 cfg.cn.push({
664                     
665                     cls : 'panel-heading',
666                     cn : [{
667                         tag: 'h3',
668                         cls : 'panel-title',
669                         html : this.header
670                     }]
671                     
672                 });
673             }
674             body = false;
675             cfg.cn.push({
676                 cls : 'panel-body',
677                 html : this.html
678             });
679             
680             
681             if (this.footer.length) {
682                 cfg.cn.push({
683                     cls : 'panel-footer',
684                     html : this.footer
685                     
686                 });
687             }
688             
689         }
690         if (body) {
691             body.html = this.html || cfg.html;
692         }
693         if (!cfg.cls.length) {
694             cfg.cls =  'container';
695         }
696         
697         return cfg;
698     }
699    
700 });
701
702  /*
703  * - LGPL
704  *
705  * image
706  * 
707  */
708
709
710 /**
711  * @class Roo.bootstrap.Img
712  * @extends Roo.bootstrap.Component
713  * Bootstrap Img class
714  * @cfg {Boolean} imgResponsive false | true
715  * @cfg {String} border rounded | circle | thumbnail
716  * @cfg {String} src image source
717  * @cfg {String} alt image alternative text
718  * 
719  * @constructor
720  * Create a new Input
721  * @param {Object} config The config object
722  */
723
724 Roo.bootstrap.Img = function(config){
725     Roo.bootstrap.Img.superclass.constructor.call(this, config);
726 };
727
728 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
729     
730     imgResponsive: true,
731     border: '',
732     src: '',
733
734     getAutoCreate : function(){
735         
736         cfg = {
737             tag: 'img',
738             cls: 'img-responsive',
739             html : null
740         }
741         
742         cfg.html = this.html || cfg.html;
743         
744         cfg.src = this.src || cfg.src;
745         
746         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
747             cfg.cls += ' img-' + this.border;
748         }
749         
750         if(this.alt){
751             cfg.alt = this.alt;
752         }
753         
754         return cfg;
755     }
756    
757 });
758
759  /*
760  * - LGPL
761  *
762  * header
763  * 
764  */
765
766 /**
767  * @class Roo.bootstrap.Header
768  * @extends Roo.bootstrap.Component
769  * Bootstrap Header class
770  * @cfg {String} html content of header
771  * @cfg {Number} level (1|2|3|4|5|6) default 1
772  * 
773  * @constructor
774  * Create a new Header
775  * @param {Object} config The config object
776  */
777
778
779 Roo.bootstrap.Header  = function(config){
780     Roo.bootstrap.Header.superclass.constructor.call(this, config);
781 };
782
783 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
784     
785     //href : false,
786     html : false,
787     level : 1,
788     
789     
790     
791     getAutoCreate : function(){
792         
793         var cfg = {
794             tag: 'h' + (1 *this.level),
795             html: this.html || 'fill in html'
796         } ;
797         
798         return cfg;
799     }
800    
801 });
802
803  
804
805  /*
806  * - LGPL
807  *
808  * menu
809  * 
810  */
811
812 /**
813  * @class Roo.bootstrap.Menu
814  * @extends Roo.bootstrap.Component
815  * Bootstrap Menu class - container for MenuItems
816  * @cfg {String} type type of menu
817  * 
818  * @constructor
819  * Create a new Menu
820  * @param {Object} config The config object
821  */
822
823
824 Roo.bootstrap.Menu = function(config){
825     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
826 };
827
828 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
829     
830    /// html : false,
831     //align : '',
832     triggerEl : false,
833     type: false,
834     
835     
836     getChildContainer : function() {
837         return this.el;  
838     },
839     
840     getAutoCreate : function(){
841          
842         //if (['right'].indexOf(this.align)!==-1) {
843         //    cfg.cn[1].cls += ' pull-right'
844         //}
845         var cfg = {
846             tag : 'ul',
847             cls : 'dropdown-menu' 
848             
849         }
850         
851         if (this.type==='submenu') {
852             cfg.cls='submenu active'
853         }
854         
855         return cfg;
856     },
857     initEvents : function() {
858        // Roo.log("ADD event");
859        // Roo.log(this.triggerEl.dom);
860         this.triggerEl.on('click', this.toggle, this);
861         this.triggerEl.addClass('dropdown-toggle');
862         
863     },
864     toggle  : function(e)
865     {
866         //Roo.log(e.getTarget());
867        // Roo.log(this.triggerEl.dom);
868         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
869             return;
870         }
871         var isActive = this.triggerEl.hasClass('open');
872         // if disabled.. ingore
873         this.clearMenus(e);
874         //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
875          // if mobile we use a backdrop because click events don't delegate
876         // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
877         // }
878  
879        //var relatedTarget = { relatedTarget: this }
880        //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
881  
882        //if (e.isDefaultPrevented()) return;
883         
884        this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
885        
886        //  .trigger('shown.bs.dropdown', relatedTarget)
887  
888        this.triggerEl.focus();
889        Roo.log(e);
890        e.preventDefault(); 
891         
892         
893     },
894     clearMenus : function()
895     {
896         //$(backdrop).remove()
897         Roo.select('.dropdown-toggle',true).each(function(aa) {
898             if (!aa.hasClass('open')) {
899                 return;
900             }
901             // triger close...
902             aa.removeClass('open');
903           //var parent = getParent($(this))
904           //var relatedTarget = { relatedTarget: this }
905           
906            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
907           //if (e.isDefaultPrevented()) return
908            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
909         })
910     }
911     
912    
913 });
914
915  
916
917  /*
918  * - LGPL
919  *
920  * menu item
921  * 
922  */
923
924
925 /**
926  * @class Roo.bootstrap.MenuItem
927  * @extends Roo.bootstrap.Component
928  * Bootstrap MenuItem class
929  * @cfg {String} html the menu label
930  * @cfg {String} href the link
931  * 
932  * 
933  * @constructor
934  * Create a new MenuItem
935  * @param {Object} config The config object
936  */
937
938
939 Roo.bootstrap.MenuItem = function(config){
940     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
941 };
942
943 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
944     
945     href : false,
946     html : false,
947     
948     getAutoCreate : function(){
949         var cfg= {
950             tag: 'li',
951             cn: [
952                 {
953                     tag : 'a',
954                     href : '#',
955                     html : 'Link'
956                 }
957             ]
958         };
959         
960         cfg.cn[0].href = this.href || cfg.cn[0].href ;
961         cfg.cn[0].html = this.html || cfg.cn[0].html ;
962         return cfg;
963     }
964    
965 });
966
967  
968
969  /*
970  * - LGPL
971  *
972  * menu separator
973  * 
974  */
975
976
977 /**
978  * @class Roo.bootstrap.MenuSeparator
979  * @extends Roo.bootstrap.Component
980  * Bootstrap MenuSeparator class
981  * 
982  * @constructor
983  * Create a new MenuItem
984  * @param {Object} config The config object
985  */
986
987
988 Roo.bootstrap.MenuSeparator = function(config){
989     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
990 };
991
992 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
993     
994     getAutoCreate : function(){
995         var cfg = {
996             cls: 'divider',
997             tag : 'li'
998         };
999         
1000         return cfg;
1001     }
1002    
1003 });
1004
1005  
1006
1007  
1008 /*
1009 <div class="modal fade">
1010   <div class="modal-dialog">
1011     <div class="modal-content">
1012       <div class="modal-header">
1013         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1014         <h4 class="modal-title">Modal title</h4>
1015       </div>
1016       <div class="modal-body">
1017         <p>One fine body&hellip;</p>
1018       </div>
1019       <div class="modal-footer">
1020         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1021         <button type="button" class="btn btn-primary">Save changes</button>
1022       </div>
1023     </div><!-- /.modal-content -->
1024   </div><!-- /.modal-dialog -->
1025 </div><!-- /.modal -->
1026 */
1027 /*
1028  * - LGPL
1029  *
1030  * page contgainer.
1031  * 
1032  */
1033
1034 /**
1035  * @class Roo.bootstrap.Modal
1036  * @extends Roo.bootstrap.Component
1037  * Bootstrap Modal class
1038  * @cfg {String} title Title of dialog
1039  * @cfg {Array} buttons Array of buttons or standard button set..
1040  * 
1041  * @constructor
1042  * Create a new Modal Dialog
1043  * @param {Object} config The config object
1044  */
1045
1046 Roo.bootstrap.Modal = function(config){
1047     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1048     this.addEvents({
1049         // raw events
1050         /**
1051          * @event click
1052          * The raw click event for the entire grid.
1053          * @param {Roo.EventObject} e
1054          */
1055         "btnclick" : true
1056     });
1057 };
1058
1059 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
1060     
1061     title : 'test dialog',
1062    
1063     buttons : false,
1064
1065     onRender : function(ct, position)
1066     {
1067         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1068         if(!this.el){
1069             var cfg = Roo.apply({},  this.getAutoCreate());
1070             cfg.id = Roo.id();
1071             //if(!cfg.name){
1072             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1073             //}
1074             //if (!cfg.name.length) {
1075             //    delete cfg.name;
1076            // }
1077             if (this.cls) {
1078                 cfg.cls += ' ' + this.cls;
1079             }
1080             if (this.style) {
1081                 cfg.style = this.style;
1082             }
1083             this.el = Roo.get(document.body).createChild(cfg, position);
1084         }
1085         //var type = this.el.dom.type;
1086          
1087         if(this.tabIndex !== undefined){
1088             this.el.dom.setAttribute('tabIndex', this.tabIndex);
1089         }
1090         
1091         
1092         
1093         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1094         this.maskEl.enableDisplayMode("block");
1095         this.maskEl.hide();
1096         //this.el.addClass("x-dlg-modal");
1097     
1098         
1099         if (this.buttons) {
1100             Roo.each(this.buttons, function(bb) {
1101                 b = Roo.apply({}, bb);
1102                 b.xns = b.xns || Roo.bootstrap;
1103                 b.xtype = b.xtype || 'Button';
1104                 if (typeof(b.listeners) == 'undefined') {
1105                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
1106                 }
1107                 
1108                 var btn = Roo.factory(b);
1109                 
1110                 btn.onRender(this.el.select('.modal-footer').first());
1111                 
1112             },this);
1113         }
1114         
1115         
1116         
1117         this.initEvents();
1118         //this.el.addClass([this.fieldClass, this.cls]);
1119         
1120     },
1121     getAutoCreate : function(){
1122         
1123         
1124         var bdy = {
1125                 cls : 'modal-body',
1126                 html : this.html || ''
1127         };
1128         
1129          
1130         return {
1131             cls: "modal fade",
1132             cn : [
1133                 {
1134                     cls: "modal-dialog",
1135                     cn : [
1136                         {
1137                             cls : "modal-content",
1138                             cn : [
1139                                 {
1140                                     cls : 'modal-header',
1141                                     cn : [
1142                                         {
1143                                             tag: 'button',
1144                                             cls : 'close',
1145                                             html : '&times'
1146                                         },
1147                                         {
1148                                             tag: 'h4',
1149                                             cls : 'modal-title',
1150                                             html : this.title
1151                                         }
1152                                     
1153                                     ]
1154                                 },
1155                                 bdy,
1156                                 {
1157                                     cls : 'modal-footer' 
1158                                 }
1159                                 
1160                                 
1161                             ]
1162                             
1163                         }
1164                     ]
1165                         
1166                 }
1167             ]
1168             
1169             
1170         };
1171           
1172     },
1173     getChildContainer : function() {
1174          
1175          return this.el.select('.modal-body',true).first();
1176         
1177     },
1178     getButtonContainer : function() {
1179          return this.el.select('.modal-footer',true).first();
1180         
1181     },
1182     initEvents : function()
1183     {
1184         this.el.select('.modal-header .close').on('click', this.hide, this);
1185     },
1186     show : function() {
1187         if (!this.rendered) {
1188             this.render();
1189         }
1190        
1191         this.el.addClass('on');
1192         this.el.removeClass('fade');
1193         this.el.setStyle('display', 'block');
1194         Roo.get(document.body).addClass("x-body-masked");
1195         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
1196         this.maskEl.show();
1197         this.el.setStyle('zIndex', '10001');
1198         
1199         
1200     },
1201     hide : function()
1202     {
1203         this.maskEl.hide();
1204         this.el.removeClass('on');
1205         this.el.addClass('fade');
1206         this.el.setStyle('display', 'none');
1207     },
1208     onButtonClick: function(btn,e)
1209     {
1210         //Roo.log([a,b,c]);
1211         this.fireEvent('btnclick', btn.name, e);
1212     }
1213 });
1214
1215
1216 Roo.apply(Roo.bootstrap.Modal,  {
1217     /**
1218          * Button config that displays a single OK button
1219          * @type Object
1220          */
1221         OK :  [{
1222             name : 'ok',
1223             weight : 'primary',
1224             html : 'OK'
1225         }], 
1226         /**
1227          * Button config that displays Yes and No buttons
1228          * @type Object
1229          */
1230         YESNO : [
1231             {
1232                 name  :'yes',
1233                 weight : 'primary',
1234                 html : 'Yes'
1235             },
1236             {
1237                 name  : 'no',
1238                 html : 'No'
1239             }
1240         ],
1241         
1242         /**
1243          * Button config that displays OK and Cancel buttons
1244          * @type Object
1245          */
1246         OKCANCEL : [
1247             {
1248                 name : 'ok',
1249                 weight : 'primary',
1250                 html : 'OK'
1251             },
1252             {
1253                name : 'cancel',
1254                 html : 'Cancel'
1255             }
1256         ],
1257         /**
1258          * Button config that displays Yes, No and Cancel buttons
1259          * @type Object
1260          */
1261         YESNOCANCEL : [
1262             {
1263                 name : 'yes',
1264                 weight : 'primary',
1265                 html : 'Yes'
1266             },
1267             {
1268                 name : 'no',
1269                 html : 'No'
1270             },
1271             {
1272                 name : 'cancel',
1273                 html : 'Cancel'
1274             }
1275         ]
1276 });
1277
1278  /*
1279  * - LGPL
1280  *
1281  * navbar
1282  * 
1283  */
1284
1285 /**
1286  * @class Roo.bootstrap.Navbar
1287  * @extends Roo.bootstrap.Component
1288  * Bootstrap Navbar class
1289  * @cfg {Boolean} sidebar has side bar
1290  * @cfg {Boolean} bar is a bar?
1291  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1292  * @cfg {String} brand what is brand
1293  * @cfg {Boolean} inverse is inverted color
1294  * @cfg {String} type (nav | pills | tabs)
1295  * @cfg {Boolean} arrangement stacked | justified
1296  * @cfg {String} align (left | right) alignment
1297  *
1298  * 
1299  * @constructor
1300  * Create a new Navbar
1301  * @param {Object} config The config object
1302  */
1303
1304
1305 Roo.bootstrap.Navbar = function(config){
1306     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1307 };
1308
1309 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
1310     
1311     sidebar: false,
1312     
1313     bar: false,
1314     brand: '',
1315     inverse: false,
1316     position: '',
1317     align : false,
1318     type: 'nav',
1319     arrangement: '',
1320     
1321     getAutoCreate : function(){
1322         var cfg = {
1323             cls : 'navbar'
1324         };
1325         
1326         if (this.sidebar === true) {
1327             cfg = {
1328                 tag: 'div',
1329                 cls: 'sidebar-nav'
1330             };
1331             return cfg;
1332         }
1333         
1334         if (this.bar === true) {
1335             cfg = {
1336                 tag: 'nav',
1337                 cls: 'navbar',
1338                 role: 'navigation',
1339                 cn: [
1340                     {
1341                         tag: 'div',
1342                         cls: 'navbar-header',
1343                         cn: [
1344                             {
1345                             tag: 'button',
1346                             type: 'button',
1347                             cls: 'navbar-toggle',
1348                             'data-toggle': 'collapse',
1349                             cn: [
1350                                 {
1351                                     tag: 'span',
1352                                     cls: 'sr-only',
1353                                     html: 'Toggle navigation'
1354                                 },
1355                                 {
1356                                     tag: 'span',
1357                                     cls: 'icon-bar'
1358                                 },
1359                                 {
1360                                     tag: 'span',
1361                                     cls: 'icon-bar'
1362                                 },
1363                                 {
1364                                     tag: 'span',
1365                                     cls: 'icon-bar'
1366                                 }
1367                             ]
1368                             }
1369                         ]
1370                     },
1371                     {
1372                     tag: 'div',
1373                     cls: 'collapse navbar-collapse'
1374                     }
1375                 ]
1376             };
1377             
1378             cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1379             
1380             if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1381             cfg.cls += ' navbar-' + this.position;
1382             cfg.tag = this.position  == 'fixed-bottom' ? 'footer' : 'header';
1383             }
1384             
1385             if (this.brand !== '') {
1386                 cfg.cn[0].cn.push({
1387                     tag: 'a',
1388                     href: '#',
1389                     cls: 'navbar-brand',
1390                     cn: [
1391                     this.brand
1392                     ]
1393                 });
1394             }
1395             
1396             return cfg;
1397         
1398         } else if (this.bar === false) {
1399             
1400         } else {
1401             Roo.log('Property \'bar\' in of Navbar must be either true or false')
1402         }
1403         
1404         cfg.cn = [
1405             {
1406                 cls: 'nav',
1407                 tag : 'ul'
1408             }
1409         ];
1410         
1411         if (['tabs','pills'].indexOf(this.type)!==-1) {
1412             cfg.cn[0].cls += ' nav-' + this.type
1413         } else {
1414             if (this.type!=='nav') {
1415             Roo.log('nav type must be nav/tabs/pills')
1416             }
1417             cfg.cn[0].cls += ' navbar-nav'
1418         }
1419         
1420         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1421             cfg.cn[0].cls += ' nav-' + this.arrangement;
1422         }
1423         
1424         if (this.align === 'right') {
1425             cfg.cn[0].cls += ' navbar-right';
1426         }
1427         if (this.inverse) {
1428             cfg.cls += ' navbar-inverse';
1429             
1430         }
1431         
1432         
1433         return cfg;
1434     },
1435     
1436     getChildContainer : function() {
1437         if (this.bar === true) {
1438             return this.el.select('.collapse',true).first();
1439         }
1440         console.log(this);
1441         return this.el;
1442     }
1443    
1444 });
1445
1446  
1447
1448  /*
1449  * - LGPL
1450  *
1451  * nav group
1452  * 
1453  */
1454
1455 /**
1456  * @class Roo.bootstrap.NavGroup
1457  * @extends Roo.bootstrap.Component
1458  * Bootstrap NavGroup class
1459  * @cfg {String} align left | right
1460  * @cfg {Boolean} inverse false | true
1461  * 
1462  * @constructor
1463  * Create a new nav group
1464  * @param {Object} config The config object
1465  */
1466
1467 Roo.bootstrap.NavGroup = function(config){
1468     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1469 };
1470
1471 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
1472     
1473     align: '',
1474     inverse: false,
1475     form: false,
1476     
1477     getAutoCreate : function(){
1478         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1479         
1480         cfg = {
1481             tag : 'ul',
1482             cls: 'nav navbar-nav' 
1483         }
1484         
1485         if (this.parent().sidebar === true) {
1486             cfg = {
1487                 tag: 'ul',
1488                 cls: 'dashboard-menu'
1489             }
1490             
1491             return cfg;
1492         }
1493         
1494         if (this.form === true) {
1495             cfg = {
1496                 tag: 'form',
1497                 cls: 'navbar-form'
1498             }
1499             
1500             if (this.align === 'right') {
1501                 cfg.cls += ' navbar-right';
1502             } else {
1503                 cfg.cls += ' navbar-left';
1504             }
1505         }
1506         
1507         
1508         if (this.align === 'right') {
1509             cfg.cls += ' navbar-right';
1510         }
1511         
1512         if (this.inverse) {
1513             cfg.cls += ' navbar-inverse';
1514             
1515         }
1516         
1517         
1518         return cfg;
1519     }
1520    
1521 });
1522
1523  
1524
1525  /*
1526  * - LGPL
1527  *
1528  * row
1529  * 
1530  */
1531 /**
1532  * @class Roo.bootstrap.Navbar.Button
1533  * @extends Roo.bootstrap.Component
1534  * Bootstrap Navbar.Button class
1535  * @cfg {String} href  link to
1536  * @cfg {String} html content of button
1537     
1538  * @constructor
1539  * Create a new Navbar Button
1540  * @param {Object} config The config object
1541  */
1542
1543
1544 Roo.bootstrap.Navbar.Button = function(config){
1545     Roo.bootstrap.Navbar.Button.superclass.constructor.call(this, config);
1546 };
1547
1548 Roo.extend(Roo.bootstrap.Navbar.Button, Roo.bootstrap.Component,  {
1549     
1550     href : false,
1551     html : false,
1552     
1553     autoCreate : {
1554         cls: 'btn',
1555         tag : 'button',
1556         html: 'hello'
1557     },
1558     
1559     getAutoCreate : function(){
1560         
1561         var cfg = {
1562             cls: 'btn',
1563             tag : 'button',
1564             html: 'hello',
1565             cn : []
1566             
1567         } ;
1568         cfg.cn.push({
1569             html : this.html || ''
1570             //href : this.
1571              //       )
1572         });
1573         cfg.cn.push({
1574             tag: 'span',
1575             cls : 'carat'
1576         });
1577         
1578         return cfg;
1579     }
1580    
1581 });
1582
1583  
1584
1585  /*
1586  * - LGPL
1587  *
1588  * row
1589  * 
1590  */
1591
1592 /**
1593  * @class Roo.bootstrap.Navbar.Item
1594  * @extends Roo.bootstrap.Component
1595  * Bootstrap Navbar.Button class
1596  * @cfg {String} href  link to
1597  * @cfg {String} html content of button
1598  * @cfg {String} badge text inside badge
1599  * @cfg {String} glyphicon name of glyphicon
1600   
1601  * @constructor
1602  * Create a new Navbar Button
1603  * @param {Object} config The config object
1604  */
1605 Roo.bootstrap.Navbar.Item = function(config){
1606     Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1607 };
1608
1609 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component,  {
1610     
1611     href: false,
1612     html: '',
1613     badge: '',
1614     icon: false,
1615     glyphicon: false,
1616     
1617     getAutoCreate : function(){
1618         
1619         var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1620         
1621         if (this.parent().parent().sidebar === true) {
1622             cfg = {
1623                 tag: 'li',
1624                 cls: '',
1625                 cn: [
1626                     {
1627                         tag: 'p',
1628                         cls: ''
1629                     }
1630                 ]
1631             }
1632             
1633             if (this.html) {
1634                 cfg.cn[0].html = this.html;
1635             }
1636             
1637             if (this.active) {
1638                 this.cls += ' active';
1639             }
1640             
1641             if (this.menu) {
1642                 cfg.cn[0].cls += ' dropdown-toggle';
1643                 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1644             }
1645             
1646             if (this.href) {
1647                 cfg.cn[0].tag = 'a',
1648                 cfg.cn[0].href = this.href;
1649             }
1650             
1651             if (this.glyphicon) {
1652                 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1653             }
1654             
1655             return cfg;
1656         }
1657         
1658         cfg = {
1659             tag: 'li'
1660         }
1661         cfg.cn = [
1662             {
1663                 tag: 'p',
1664                 html: 'Text'
1665             }
1666         ];
1667         
1668         if (this.glyphicon) {
1669             if(cfg.html){cfg.html = ' ' + this.html};
1670             cfg.cn=[
1671                 {
1672                     tag: 'span',
1673                     cls: 'glyphicon glyphicon-' + this.glyphicon
1674                 }
1675             ];
1676         }
1677         
1678         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1679         if (this.menu) {
1680             cfg.cn[0].tag='a';
1681             cfg.cn[0].href='#';
1682             cfg.cn[0].html += " <span class='caret'></span>";
1683         //}else if (!this.href) {
1684         //    cfg.cn[0].tag='p';
1685         //    cfg.cn[0].cls='navbar-text';
1686         } else {
1687             cfg.cn[0].tag='a';
1688             cfg.cn[0].href=this.href||'#';
1689             cfg.cn[0].html=this.html;
1690         }
1691         
1692         if (this.badge !== '') {
1693             
1694             cfg.cn[0].cn=[
1695                 cfg.cn[0].html + ' ',
1696                 {
1697                     tag: 'span',
1698                     cls: 'badge',
1699                     html: this.badge
1700                 }
1701             ];
1702             cfg.cn[0].html=''
1703         }
1704          
1705         
1706         return cfg;
1707     },
1708     initEvents: function() {
1709        // Roo.log('init events?');
1710        // Roo.log(this.el.dom);
1711         this.el.select('a',true).on('click',
1712                 function(e) {
1713                     this.fireEvent('click', this);
1714                 },
1715                 this
1716         );
1717     }
1718    
1719 });
1720  
1721
1722  /*
1723  * - LGPL
1724  *
1725  * row
1726  * 
1727  */
1728
1729 /**
1730  * @class Roo.bootstrap.Row
1731  * @extends Roo.bootstrap.Component
1732  * Bootstrap Row class (contains columns...)
1733  * 
1734  * @constructor
1735  * Create a new Row
1736  * @param {Object} config The config object
1737  */
1738
1739 Roo.bootstrap.Row = function(config){
1740     Roo.bootstrap.Row.superclass.constructor.call(this, config);
1741 };
1742
1743 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
1744     
1745     autoCreate: {
1746         cls: 'row clearfix'
1747     }
1748     
1749     
1750 });
1751
1752  
1753
1754  /*
1755  * - LGPL
1756  *
1757  * element
1758  * 
1759  */
1760
1761 /**
1762  * @class Roo.bootstrap.Element
1763  * @extends Roo.bootstrap.Component
1764  * Bootstrap Element class
1765  * @cfg {String} html contents of the element
1766  * @cfg {String} tag tag of the element
1767  * @cfg {String} cls class of the element
1768  * 
1769  * @constructor
1770  * Create a new Element
1771  * @param {Object} config The config object
1772  */
1773
1774 Roo.bootstrap.Element = function(config){
1775     Roo.bootstrap.Element.superclass.constructor.call(this, config);
1776 };
1777
1778 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
1779     
1780     tag: 'div',
1781     cls: '',
1782     html: '',
1783     
1784     
1785     
1786     getAutoCreate : function(){
1787         var cfg = Roo.apply({}, Roo.bootstrap.Element.superclass.getAutoCreate.call(this));
1788         
1789         cfg = {
1790             tag: this.tag,
1791             cls: '',
1792             html: this.html
1793         }
1794         
1795         return cfg;
1796     }
1797    
1798 });
1799
1800  
1801
1802  /*
1803  * - LGPL
1804  *
1805  * pagination
1806  * 
1807  */
1808
1809 /**
1810  * @class Roo.bootstrap.Pagination
1811  * @extends Roo.bootstrap.Component
1812  * Bootstrap Pagination class
1813  * @cfg {String} size xs | sm | md | lg
1814  * @cfg {Boolean} inverse false | true
1815  * @cfg {Number} from pagination starting number
1816  * @cfg {Number} to pagination ending number
1817  * @cfg {String} align empty or left | right
1818  * @cfg {Number} active active page number
1819  * 
1820  * @constructor
1821  * Create a new Pagination
1822  * @param {Object} config The config object
1823  */
1824
1825 Roo.bootstrap.Pagination = function(config){
1826     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1827 };
1828
1829 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
1830     
1831     cls: false,
1832     size: false,
1833     inverse: false,
1834     from: 1,
1835     to: 4,
1836     align: false,
1837     active: 1,
1838     
1839     getAutoCreate : function(){
1840         cfg = {
1841             tag: 'ul',
1842                 cls: 'pagination',
1843                 cn: []
1844         };
1845         if (this.inverse) {
1846             cfg.cls += ' inverse';
1847         }
1848         if (this.html) {
1849             cfg.html=this.html;
1850         }
1851         if (this.cls) {
1852             cfg.cls=this.cls;
1853         }
1854         cfg.cn[0]={
1855             tag: 'li',
1856             cn: [
1857                 {
1858                     tag: 'a',
1859                     href:'#',
1860                     html: '&laquo;'
1861                 }
1862             ]
1863         };
1864         var from=this.from>0?this.from:1;
1865         var to=this.to-from<=10?this.to:from+10;
1866         var active=this.active>=from&&this.active<=to?this.active:null;
1867         for (var i=from;i<=to;i++) {
1868             cfg.cn.push(
1869                 {
1870                     tag: 'li',
1871                     cls: active===i?'active':'',
1872                     cn: [
1873                         {
1874                             tag: 'a',
1875                             href: '#',
1876                             html: i
1877                         }
1878                     ]
1879                 }
1880             );
1881         }
1882         
1883         cfg.cn.push(
1884             {
1885                 tag: 'li',
1886                 cn: [
1887                     {
1888                        tag: 'a',
1889                        href: '#',
1890                        html: '&raquo;'
1891                     }
1892                 ]
1893             }
1894         );
1895         
1896         return cfg;
1897     }
1898    
1899 });
1900
1901  
1902
1903  /*
1904  * - LGPL
1905  *
1906  * slider
1907  * 
1908  */
1909
1910
1911 /**
1912  * @class Roo.bootstrap.Slider
1913  * @extends Roo.bootstrap.Component
1914  * Bootstrap Slider class
1915  *    
1916  * @constructor
1917  * Create a new Slider
1918  * @param {Object} config The config object
1919  */
1920
1921 Roo.bootstrap.Slider = function(config){
1922     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1923 };
1924
1925 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
1926     
1927     getAutoCreate : function(){
1928         
1929         var cfg = {
1930             tag: 'div',
1931             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1932             cn: [
1933                 {
1934                     tag: 'a',
1935                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
1936                 }
1937             ]
1938         }
1939         
1940         return cfg;
1941     }
1942    
1943 });
1944
1945  /*
1946  * - LGPL
1947  *
1948  * table
1949  * 
1950  */
1951
1952 /**
1953  * @class Roo.bootstrap.Table
1954  * @extends Roo.bootstrap.Component
1955  * Bootstrap Table class
1956  * 
1957  * @constructor
1958  * Create a new Table
1959  * @param {Object} config The config object
1960  */
1961
1962 Roo.bootstrap.Table = function(config){
1963     Roo.bootstrap.Table.superclass.constructor.call(this, config);
1964 };
1965
1966 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
1967     
1968     html: false,
1969     cls: false,
1970     
1971     getAutoCreate : function(){
1972         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
1973         
1974         cfg = {
1975             tag: 'table',
1976             cn: [
1977                 {
1978                     tag: 'tbody'
1979                 }
1980             ]
1981         }
1982         if (this.html) {
1983             cfg.html=this.html
1984         }
1985         if (this.cls) {
1986             cfg.cls=this.cls
1987         }
1988         
1989         return cfg;
1990     }
1991    
1992 });
1993
1994  
1995
1996  /*
1997  * - LGPL
1998  *
1999  * table cell
2000  * 
2001  */
2002
2003 /**
2004  * @class Roo.bootstrap.TableCell
2005  * @extends Roo.bootstrap.Component
2006  * Bootstrap TableCell class
2007  * 
2008  * @constructor
2009  * Create a new TableCell
2010  * @param {Object} config The config object
2011  */
2012
2013 Roo.bootstrap.TableCell = function(config){
2014     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
2015 };
2016
2017 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
2018     
2019     getAutoCreate : function(){
2020         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
2021         
2022         cfg = {
2023             tag: 'td'
2024         }
2025         if (this.html) {
2026             cfg.html=this.html
2027         }
2028         if (this.cls) {
2029             cfg.cls=this.cls
2030         }
2031         
2032         return cfg;
2033     }
2034    
2035 });
2036
2037  
2038
2039  /*
2040  * - LGPL
2041  *
2042  * table row
2043  * 
2044  */
2045
2046 /**
2047  * @class Roo.bootstrap.TableRow
2048  * @extends Roo.bootstrap.Component
2049  * Bootstrap TableRow class
2050  * 
2051  * @constructor
2052  * Create a new TableRow
2053  * @param {Object} config The config object
2054  */
2055
2056 Roo.bootstrap.TableRow = function(config){
2057     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
2058 };
2059
2060 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
2061     
2062     getAutoCreate : function(){
2063         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
2064         
2065         cfg = {
2066             tag: 'tr'
2067         }
2068         
2069         return cfg;
2070     }
2071    
2072 });
2073
2074  
2075
2076  /*
2077  * Based on:
2078  * Ext JS Library 1.1.1
2079  * Copyright(c) 2006-2007, Ext JS, LLC.
2080  *
2081  * Originally Released Under LGPL - original licence link has changed is not relivant.
2082  *
2083  * Fork - LGPL
2084  * <script type="text/javascript">
2085  */
2086
2087 // as we use this in bootstrap.
2088 Roo.namespace('Roo.form');
2089  /**
2090  * @class Roo.form.Action
2091  * Internal Class used to handle form actions
2092  * @constructor
2093  * @param {Roo.form.BasicForm} el The form element or its id
2094  * @param {Object} config Configuration options
2095  */
2096
2097  
2098  
2099 // define the action interface
2100 Roo.form.Action = function(form, options){
2101     this.form = form;
2102     this.options = options || {};
2103 };
2104 /**
2105  * Client Validation Failed
2106  * @const 
2107  */
2108 Roo.form.Action.CLIENT_INVALID = 'client';
2109 /**
2110  * Server Validation Failed
2111  * @const 
2112  */
2113 Roo.form.Action.SERVER_INVALID = 'server';
2114  /**
2115  * Connect to Server Failed
2116  * @const 
2117  */
2118 Roo.form.Action.CONNECT_FAILURE = 'connect';
2119 /**
2120  * Reading Data from Server Failed
2121  * @const 
2122  */
2123 Roo.form.Action.LOAD_FAILURE = 'load';
2124
2125 Roo.form.Action.prototype = {
2126     type : 'default',
2127     failureType : undefined,
2128     response : undefined,
2129     result : undefined,
2130
2131     // interface method
2132     run : function(options){
2133
2134     },
2135
2136     // interface method
2137     success : function(response){
2138
2139     },
2140
2141     // interface method
2142     handleResponse : function(response){
2143
2144     },
2145
2146     // default connection failure
2147     failure : function(response){
2148         
2149         this.response = response;
2150         this.failureType = Roo.form.Action.CONNECT_FAILURE;
2151         this.form.afterAction(this, false);
2152     },
2153
2154     processResponse : function(response){
2155         this.response = response;
2156         if(!response.responseText){
2157             return true;
2158         }
2159         this.result = this.handleResponse(response);
2160         return this.result;
2161     },
2162
2163     // utility functions used internally
2164     getUrl : function(appendParams){
2165         var url = this.options.url || this.form.url || this.form.el.dom.action;
2166         if(appendParams){
2167             var p = this.getParams();
2168             if(p){
2169                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
2170             }
2171         }
2172         return url;
2173     },
2174
2175     getMethod : function(){
2176         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
2177     },
2178
2179     getParams : function(){
2180         var bp = this.form.baseParams;
2181         var p = this.options.params;
2182         if(p){
2183             if(typeof p == "object"){
2184                 p = Roo.urlEncode(Roo.applyIf(p, bp));
2185             }else if(typeof p == 'string' && bp){
2186                 p += '&' + Roo.urlEncode(bp);
2187             }
2188         }else if(bp){
2189             p = Roo.urlEncode(bp);
2190         }
2191         return p;
2192     },
2193
2194     createCallback : function(){
2195         return {
2196             success: this.success,
2197             failure: this.failure,
2198             scope: this,
2199             timeout: (this.form.timeout*1000),
2200             upload: this.form.fileUpload ? this.success : undefined
2201         };
2202     }
2203 };
2204
2205 Roo.form.Action.Submit = function(form, options){
2206     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
2207 };
2208
2209 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
2210     type : 'submit',
2211
2212     haveProgress : false,
2213     uploadComplete : false,
2214     
2215     // uploadProgress indicator.
2216     uploadProgress : function()
2217     {
2218         if (!this.form.progressUrl) {
2219             return;
2220         }
2221         
2222         if (!this.haveProgress) {
2223             Roo.MessageBox.progress("Uploading", "Uploading");
2224         }
2225         if (this.uploadComplete) {
2226            Roo.MessageBox.hide();
2227            return;
2228         }
2229         
2230         this.haveProgress = true;
2231    
2232         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
2233         
2234         var c = new Roo.data.Connection();
2235         c.request({
2236             url : this.form.progressUrl,
2237             params: {
2238                 id : uid
2239             },
2240             method: 'GET',
2241             success : function(req){
2242                //console.log(data);
2243                 var rdata = false;
2244                 var edata;
2245                 try  {
2246                    rdata = Roo.decode(req.responseText)
2247                 } catch (e) {
2248                     Roo.log("Invalid data from server..");
2249                     Roo.log(edata);
2250                     return;
2251                 }
2252                 if (!rdata || !rdata.success) {
2253                     Roo.log(rdata);
2254                     Roo.MessageBox.alert(Roo.encode(rdata));
2255                     return;
2256                 }
2257                 var data = rdata.data;
2258                 
2259                 if (this.uploadComplete) {
2260                    Roo.MessageBox.hide();
2261                    return;
2262                 }
2263                    
2264                 if (data){
2265                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
2266                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
2267                     );
2268                 }
2269                 this.uploadProgress.defer(2000,this);
2270             },
2271        
2272             failure: function(data) {
2273                 Roo.log('progress url failed ');
2274                 Roo.log(data);
2275             },
2276             scope : this
2277         });
2278            
2279     },
2280     
2281     
2282     run : function()
2283     {
2284         // run get Values on the form, so it syncs any secondary forms.
2285         this.form.getValues();
2286         
2287         var o = this.options;
2288         var method = this.getMethod();
2289         var isPost = method == 'POST';
2290         if(o.clientValidation === false || this.form.isValid()){
2291             
2292             if (this.form.progressUrl) {
2293                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
2294                     (new Date() * 1) + '' + Math.random());
2295                     
2296             } 
2297             
2298             
2299             Roo.Ajax.request(Roo.apply(this.createCallback(), {
2300                 form:this.form.el.dom,
2301                 url:this.getUrl(!isPost),
2302                 method: method,
2303                 params:isPost ? this.getParams() : null,
2304                 isUpload: this.form.fileUpload
2305             }));
2306             
2307             this.uploadProgress();
2308
2309         }else if (o.clientValidation !== false){ // client validation failed
2310             this.failureType = Roo.form.Action.CLIENT_INVALID;
2311             this.form.afterAction(this, false);
2312         }
2313     },
2314
2315     success : function(response)
2316     {
2317         this.uploadComplete= true;
2318         if (this.haveProgress) {
2319             Roo.MessageBox.hide();
2320         }
2321         
2322         
2323         var result = this.processResponse(response);
2324         if(result === true || result.success){
2325             this.form.afterAction(this, true);
2326             return;
2327         }
2328         if(result.errors){
2329             this.form.markInvalid(result.errors);
2330             this.failureType = Roo.form.Action.SERVER_INVALID;
2331         }
2332         this.form.afterAction(this, false);
2333     },
2334     failure : function(response)
2335     {
2336         this.uploadComplete= true;
2337         if (this.haveProgress) {
2338             Roo.MessageBox.hide();
2339         }
2340         
2341         this.response = response;
2342         this.failureType = Roo.form.Action.CONNECT_FAILURE;
2343         this.form.afterAction(this, false);
2344     },
2345     
2346     handleResponse : function(response){
2347         if(this.form.errorReader){
2348             var rs = this.form.errorReader.read(response);
2349             var errors = [];
2350             if(rs.records){
2351                 for(var i = 0, len = rs.records.length; i < len; i++) {
2352                     var r = rs.records[i];
2353                     errors[i] = r.data;
2354                 }
2355             }
2356             if(errors.length < 1){
2357                 errors = null;
2358             }
2359             return {
2360                 success : rs.success,
2361                 errors : errors
2362             };
2363         }
2364         var ret = false;
2365         try {
2366             ret = Roo.decode(response.responseText);
2367         } catch (e) {
2368             ret = {
2369                 success: false,
2370                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
2371                 errors : []
2372             };
2373         }
2374         return ret;
2375         
2376     }
2377 });
2378
2379
2380 Roo.form.Action.Load = function(form, options){
2381     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
2382     this.reader = this.form.reader;
2383 };
2384
2385 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
2386     type : 'load',
2387
2388     run : function(){
2389         
2390         Roo.Ajax.request(Roo.apply(
2391                 this.createCallback(), {
2392                     method:this.getMethod(),
2393                     url:this.getUrl(false),
2394                     params:this.getParams()
2395         }));
2396     },
2397
2398     success : function(response){
2399         
2400         var result = this.processResponse(response);
2401         if(result === true || !result.success || !result.data){
2402             this.failureType = Roo.form.Action.LOAD_FAILURE;
2403             this.form.afterAction(this, false);
2404             return;
2405         }
2406         this.form.clearInvalid();
2407         this.form.setValues(result.data);
2408         this.form.afterAction(this, true);
2409     },
2410
2411     handleResponse : function(response){
2412         if(this.form.reader){
2413             var rs = this.form.reader.read(response);
2414             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
2415             return {
2416                 success : rs.success,
2417                 data : data
2418             };
2419         }
2420         return Roo.decode(response.responseText);
2421     }
2422 });
2423
2424 Roo.form.Action.ACTION_TYPES = {
2425     'load' : Roo.form.Action.Load,
2426     'submit' : Roo.form.Action.Submit
2427 };/*
2428  * - LGPL
2429  *
2430  * form
2431  * 
2432  */
2433
2434 /**
2435  * @class Roo.bootstrap.Form
2436  * @extends Roo.bootstrap.Component
2437  * Bootstrap Form class
2438  * @cfg {String} method  GET | POST (default POST)
2439  * @cfg {String} labelAlign top | left (default top)
2440   * @cfg {String} align left  | right - for navbars
2441
2442  * 
2443  * @constructor
2444  * Create a new Form
2445  * @param {Object} config The config object
2446  */
2447
2448
2449 Roo.bootstrap.Form = function(config){
2450     Roo.bootstrap.Form.superclass.constructor.call(this, config);
2451     this.addEvents({
2452         /**
2453          * @event clientvalidation
2454          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2455          * @param {Form} this
2456          * @param {Boolean} valid true if the form has passed client-side validation
2457          */
2458         clientvalidation: true,
2459         /**
2460          * @event beforeaction
2461          * Fires before any action is performed. Return false to cancel the action.
2462          * @param {Form} this
2463          * @param {Action} action The action to be performed
2464          */
2465         beforeaction: true,
2466         /**
2467          * @event actionfailed
2468          * Fires when an action fails.
2469          * @param {Form} this
2470          * @param {Action} action The action that failed
2471          */
2472         actionfailed : true,
2473         /**
2474          * @event actioncomplete
2475          * Fires when an action is completed.
2476          * @param {Form} this
2477          * @param {Action} action The action that completed
2478          */
2479         actioncomplete : true
2480     });
2481     
2482 };
2483
2484 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
2485       
2486      /**
2487      * @cfg {String} method
2488      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2489      */
2490     method : 'POST',
2491     /**
2492      * @cfg {String} url
2493      * The URL to use for form actions if one isn't supplied in the action options.
2494      */
2495     /**
2496      * @cfg {Boolean} fileUpload
2497      * Set to true if this form is a file upload.
2498      */
2499      
2500     /**
2501      * @cfg {Object} baseParams
2502      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2503      */
2504       
2505     /**
2506      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2507      */
2508     timeout: 30,
2509     /**
2510      * @cfg {Sting} align (left|right) for navbar forms
2511      */
2512     align : 'left',
2513
2514     // private
2515     activeAction : null,
2516  
2517     /**
2518      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2519      * element by passing it or its id or mask the form itself by passing in true.
2520      * @type Mixed
2521      */
2522     waitMsgTarget : false,
2523     
2524      
2525     
2526     /**
2527      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2528      * element by passing it or its id or mask the form itself by passing in true.
2529      * @type Mixed
2530      */
2531     
2532     getAutoCreate : function(){
2533         
2534         var cfg = {
2535             tag: 'form',
2536             method : this.method || 'POST',
2537             id : this.id || Roo.id(),
2538             cls : ''
2539         }
2540         if (this.parent().xtype.match(/^Nav/)) {
2541             cfg.cls = 'navbar-form navbar-' + this.align;
2542             
2543         }
2544         
2545         if (this.labelAlign == 'left' ) {
2546             cfg.cls += ' form-horizontal';
2547         }
2548         
2549         
2550         return cfg;
2551     },
2552     initEvents : function()
2553     {
2554         this.el.on('submit', this.onSubmit, this);
2555         
2556         
2557     },
2558     // private
2559     onSubmit : function(e){
2560         e.stopEvent();
2561     },
2562     
2563      /**
2564      * Returns true if client-side validation on the form is successful.
2565      * @return Boolean
2566      */
2567     isValid : function(){
2568         var items = this.getItems();
2569         var valid = true;
2570         items.each(function(f){
2571            if(!f.validate()){
2572                valid = false;
2573                
2574            }
2575         });
2576         return valid;
2577     },
2578     /**
2579      * Returns true if any fields in this form have changed since their original load.
2580      * @return Boolean
2581      */
2582     isDirty : function(){
2583         var dirty = false;
2584         var items = this.getItems();
2585         items.each(function(f){
2586            if(f.isDirty()){
2587                dirty = true;
2588                return false;
2589            }
2590            return true;
2591         });
2592         return dirty;
2593     },
2594      /**
2595      * Performs a predefined action (submit or load) or custom actions you define on this form.
2596      * @param {String} actionName The name of the action type
2597      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
2598      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2599      * accept other config options):
2600      * <pre>
2601 Property          Type             Description
2602 ----------------  ---------------  ----------------------------------------------------------------------------------
2603 url               String           The url for the action (defaults to the form's url)
2604 method            String           The form method to use (defaults to the form's method, or POST if not defined)
2605 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
2606 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
2607                                    validate the form on the client (defaults to false)
2608      * </pre>
2609      * @return {BasicForm} this
2610      */
2611     doAction : function(action, options){
2612         if(typeof action == 'string'){
2613             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2614         }
2615         if(this.fireEvent('beforeaction', this, action) !== false){
2616             this.beforeAction(action);
2617             action.run.defer(100, action);
2618         }
2619         return this;
2620     },
2621     
2622     // private
2623     beforeAction : function(action){
2624         var o = action.options;
2625         
2626         // not really supported yet.. ??
2627         
2628         //if(this.waitMsgTarget === true){
2629             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2630         //}else if(this.waitMsgTarget){
2631         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2632         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2633         //}else {
2634         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2635        // }
2636          
2637     },
2638
2639     // private
2640     afterAction : function(action, success){
2641         this.activeAction = null;
2642         var o = action.options;
2643         
2644         //if(this.waitMsgTarget === true){
2645             this.el.unmask();
2646         //}else if(this.waitMsgTarget){
2647         //    this.waitMsgTarget.unmask();
2648         //}else{
2649         //    Roo.MessageBox.updateProgress(1);
2650         //    Roo.MessageBox.hide();
2651        // }
2652         // 
2653         if(success){
2654             if(o.reset){
2655                 this.reset();
2656             }
2657             Roo.callback(o.success, o.scope, [this, action]);
2658             this.fireEvent('actioncomplete', this, action);
2659             
2660         }else{
2661             
2662             // failure condition..
2663             // we have a scenario where updates need confirming.
2664             // eg. if a locking scenario exists..
2665             // we look for { errors : { needs_confirm : true }} in the response.
2666             if (
2667                 (typeof(action.result) != 'undefined')  &&
2668                 (typeof(action.result.errors) != 'undefined')  &&
2669                 (typeof(action.result.errors.needs_confirm) != 'undefined')
2670            ){
2671                 var _t = this;
2672                 Roo.log("not supported yet");
2673                  /*
2674                 
2675                 Roo.MessageBox.confirm(
2676                     "Change requires confirmation",
2677                     action.result.errorMsg,
2678                     function(r) {
2679                         if (r != 'yes') {
2680                             return;
2681                         }
2682                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
2683                     }
2684                     
2685                 );
2686                 */
2687                 
2688                 
2689                 return;
2690             }
2691             
2692             Roo.callback(o.failure, o.scope, [this, action]);
2693             // show an error message if no failed handler is set..
2694             if (!this.hasListener('actionfailed')) {
2695                 Roo.log("need to add dialog support");
2696                 /*
2697                 Roo.MessageBox.alert("Error",
2698                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2699                         action.result.errorMsg :
2700                         "Saving Failed, please check your entries or try again"
2701                 );
2702                 */
2703             }
2704             
2705             this.fireEvent('actionfailed', this, action);
2706         }
2707         
2708     },
2709     /**
2710      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2711      * @param {String} id The value to search for
2712      * @return Field
2713      */
2714     findField : function(id){
2715         var items = this.getItems();
2716         var field = items.get(id);
2717         if(!field){
2718              items.each(function(f){
2719                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2720                     field = f;
2721                     return false;
2722                 }
2723                 return true;
2724             });
2725         }
2726         return field || null;
2727     },
2728      /**
2729      * Mark fields in this form invalid in bulk.
2730      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2731      * @return {BasicForm} this
2732      */
2733     markInvalid : function(errors){
2734         if(errors instanceof Array){
2735             for(var i = 0, len = errors.length; i < len; i++){
2736                 var fieldError = errors[i];
2737                 var f = this.findField(fieldError.id);
2738                 if(f){
2739                     f.markInvalid(fieldError.msg);
2740                 }
2741             }
2742         }else{
2743             var field, id;
2744             for(id in errors){
2745                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2746                     field.markInvalid(errors[id]);
2747                 }
2748             }
2749         }
2750         //Roo.each(this.childForms || [], function (f) {
2751         //    f.markInvalid(errors);
2752         //});
2753         
2754         return this;
2755     },
2756
2757     /**
2758      * Set values for fields in this form in bulk.
2759      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2760      * @return {BasicForm} this
2761      */
2762     setValues : function(values){
2763         if(values instanceof Array){ // array of objects
2764             for(var i = 0, len = values.length; i < len; i++){
2765                 var v = values[i];
2766                 var f = this.findField(v.id);
2767                 if(f){
2768                     f.setValue(v.value);
2769                     if(this.trackResetOnLoad){
2770                         f.originalValue = f.getValue();
2771                     }
2772                 }
2773             }
2774         }else{ // object hash
2775             var field, id;
2776             for(id in values){
2777                 if(typeof values[id] != 'function' && (field = this.findField(id))){
2778                     
2779                     if (field.setFromData && 
2780                         field.valueField && 
2781                         field.displayField &&
2782                         // combos' with local stores can 
2783                         // be queried via setValue()
2784                         // to set their value..
2785                         (field.store && !field.store.isLocal)
2786                         ) {
2787                         // it's a combo
2788                         var sd = { };
2789                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2790                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2791                         field.setFromData(sd);
2792                         
2793                     } else {
2794                         field.setValue(values[id]);
2795                     }
2796                     
2797                     
2798                     if(this.trackResetOnLoad){
2799                         field.originalValue = field.getValue();
2800                     }
2801                 }
2802             }
2803         }
2804          
2805         //Roo.each(this.childForms || [], function (f) {
2806         //    f.setValues(values);
2807         //});
2808                 
2809         return this;
2810     },
2811
2812     /**
2813      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2814      * they are returned as an array.
2815      * @param {Boolean} asString
2816      * @return {Object}
2817      */
2818     getValues : function(asString){
2819         //if (this.childForms) {
2820             // copy values from the child forms
2821         //    Roo.each(this.childForms, function (f) {
2822         //        this.setValues(f.getValues());
2823         //    }, this);
2824         //}
2825         
2826         
2827         
2828         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2829         if(asString === true){
2830             return fs;
2831         }
2832         return Roo.urlDecode(fs);
2833     },
2834     
2835     /**
2836      * Returns the fields in this form as an object with key/value pairs. 
2837      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2838      * @return {Object}
2839      */
2840     getFieldValues : function(with_hidden)
2841     {
2842         var items = this.getItems();
2843         var ret = {};
2844         items.each(function(f){
2845             if (!f.getName()) {
2846                 return;
2847             }
2848             var v = f.getValue();
2849             if (f.inputType =='radio') {
2850                 if (typeof(ret[f.getName()]) == 'undefined') {
2851                     ret[f.getName()] = ''; // empty..
2852                 }
2853                 
2854                 if (!f.el.dom.checked) {
2855                     return;
2856                     
2857                 }
2858                 v = f.el.dom.value;
2859                 
2860             }
2861             
2862             // not sure if this supported any more..
2863             if ((typeof(v) == 'object') && f.getRawValue) {
2864                 v = f.getRawValue() ; // dates..
2865             }
2866             // combo boxes where name != hiddenName...
2867             if (f.name != f.getName()) {
2868                 ret[f.name] = f.getRawValue();
2869             }
2870             ret[f.getName()] = v;
2871         });
2872         
2873         return ret;
2874     },
2875
2876     /**
2877      * Clears all invalid messages in this form.
2878      * @return {BasicForm} this
2879      */
2880     clearInvalid : function(){
2881         var items = this.getItems();
2882         
2883         items.each(function(f){
2884            f.clearInvalid();
2885         });
2886         
2887         
2888         
2889         return this;
2890     },
2891
2892     /**
2893      * Resets this form.
2894      * @return {BasicForm} this
2895      */
2896     reset : function(){
2897         var items = this.getItems();
2898         items.each(function(f){
2899             f.reset();
2900         });
2901         
2902         Roo.each(this.childForms || [], function (f) {
2903             f.reset();
2904         });
2905        
2906         
2907         return this;
2908     },
2909     getItems : function()
2910     {
2911         var r=new Roo.util.MixedCollection(false, function(o){
2912             return o.id || (o.id = Roo.id());
2913         });
2914         var iter = function(el) {
2915             if (el.inputEl) {
2916                 r.add(el);
2917             }
2918             if (!el.items) {
2919                 return;
2920             }
2921             Roo.each(el.items,function(e) {
2922                 iter(e);
2923             });
2924             
2925             
2926         };
2927         iter(this);
2928         return r;
2929         
2930         
2931         
2932         
2933     }
2934     
2935 });
2936
2937  
2938 /*
2939  * Based on:
2940  * Ext JS Library 1.1.1
2941  * Copyright(c) 2006-2007, Ext JS, LLC.
2942  *
2943  * Originally Released Under LGPL - original licence link has changed is not relivant.
2944  *
2945  * Fork - LGPL
2946  * <script type="text/javascript">
2947  */
2948 /**
2949  * @class Roo.form.VTypes
2950  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2951  * @singleton
2952  */
2953 Roo.form.VTypes = function(){
2954     // closure these in so they are only created once.
2955     var alpha = /^[a-zA-Z_]+$/;
2956     var alphanum = /^[a-zA-Z0-9_]+$/;
2957     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2958     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2959
2960     // All these messages and functions are configurable
2961     return {
2962         /**
2963          * The function used to validate email addresses
2964          * @param {String} value The email address
2965          */
2966         'email' : function(v){
2967             return email.test(v);
2968         },
2969         /**
2970          * The error text to display when the email validation function returns false
2971          * @type String
2972          */
2973         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2974         /**
2975          * The keystroke filter mask to be applied on email input
2976          * @type RegExp
2977          */
2978         'emailMask' : /[a-z0-9_\.\-@]/i,
2979
2980         /**
2981          * The function used to validate URLs
2982          * @param {String} value The URL
2983          */
2984         'url' : function(v){
2985             return url.test(v);
2986         },
2987         /**
2988          * The error text to display when the url validation function returns false
2989          * @type String
2990          */
2991         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2992         
2993         /**
2994          * The function used to validate alpha values
2995          * @param {String} value The value
2996          */
2997         'alpha' : function(v){
2998             return alpha.test(v);
2999         },
3000         /**
3001          * The error text to display when the alpha validation function returns false
3002          * @type String
3003          */
3004         'alphaText' : 'This field should only contain letters and _',
3005         /**
3006          * The keystroke filter mask to be applied on alpha input
3007          * @type RegExp
3008          */
3009         'alphaMask' : /[a-z_]/i,
3010
3011         /**
3012          * The function used to validate alphanumeric values
3013          * @param {String} value The value
3014          */
3015         'alphanum' : function(v){
3016             return alphanum.test(v);
3017         },
3018         /**
3019          * The error text to display when the alphanumeric validation function returns false
3020          * @type String
3021          */
3022         'alphanumText' : 'This field should only contain letters, numbers and _',
3023         /**
3024          * The keystroke filter mask to be applied on alphanumeric input
3025          * @type RegExp
3026          */
3027         'alphanumMask' : /[a-z0-9_]/i
3028     };
3029 }();/*
3030  * - LGPL
3031  *
3032  * Input
3033  * 
3034  */
3035
3036 /**
3037  * @class Roo.bootstrap.Input
3038  * @extends Roo.bootstrap.Component
3039  * Bootstrap Input class
3040  * @cfg {Boolean} disabled is it disabled
3041  * @cfg {String} fieldLabel - the label associated
3042  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
3043  * @cfg {String} name name of the input
3044  * @cfg {string} fieldLabel - the label associated
3045  * @cfg {string}  inputType - input / file submit ...
3046  * @cfg {string} placeholder - placeholder to put in text.
3047  * @cfg {string}  before - input group add on before
3048  * @cfg {string} after - input group add on after
3049  * @cfg {string} size - (lg|sm) or leave empty..
3050  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
3051  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
3052  * @cfg {Number} md colspan out of 12 for computer-sized screens
3053  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
3054  * 
3055  * 
3056  * @constructor
3057  * Create a new Input
3058  * @param {Object} config The config object
3059  */
3060
3061 Roo.bootstrap.Input = function(config){
3062     Roo.bootstrap.Input.superclass.constructor.call(this, config);
3063    
3064         this.addEvents({
3065             /**
3066              * @event focus
3067              * Fires when this field receives input focus.
3068              * @param {Roo.form.Field} this
3069              */
3070             focus : true,
3071             /**
3072              * @event blur
3073              * Fires when this field loses input focus.
3074              * @param {Roo.form.Field} this
3075              */
3076             blur : true,
3077             /**
3078              * @event specialkey
3079              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
3080              * {@link Roo.EventObject#getKey} to determine which key was pressed.
3081              * @param {Roo.form.Field} this
3082              * @param {Roo.EventObject} e The event object
3083              */
3084             specialkey : true,
3085             /**
3086              * @event change
3087              * Fires just before the field blurs if the field value has changed.
3088              * @param {Roo.form.Field} this
3089              * @param {Mixed} newValue The new value
3090              * @param {Mixed} oldValue The original value
3091              */
3092             change : true,
3093             /**
3094              * @event invalid
3095              * Fires after the field has been marked as invalid.
3096              * @param {Roo.form.Field} this
3097              * @param {String} msg The validation message
3098              */
3099             invalid : true,
3100             /**
3101              * @event valid
3102              * Fires after the field has been validated with no errors.
3103              * @param {Roo.form.Field} this
3104              */
3105             valid : true,
3106              /**
3107              * @event keyup
3108              * Fires after the key up
3109              * @param {Roo.form.Field} this
3110              * @param {Roo.EventObject}  e The event Object
3111              */
3112             keyup : true
3113         });
3114 };
3115
3116 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
3117      /**
3118      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
3119       automatic validation (defaults to "keyup").
3120      */
3121     validationEvent : "keyup",
3122      /**
3123      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
3124      */
3125     validateOnBlur : true,
3126     /**
3127      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
3128      */
3129     validationDelay : 250,
3130      /**
3131      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
3132      */
3133     focusClass : "x-form-focus",  // not needed???
3134     
3135        
3136     /**
3137      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
3138      */
3139     invalidClass : "has-error",
3140     
3141     /**
3142      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
3143      */
3144     selectOnFocus : false,
3145     
3146      /**
3147      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
3148      */
3149     maskRe : null,
3150        /**
3151      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
3152      */
3153     vtype : null,
3154     
3155       /**
3156      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
3157      */
3158     disableKeyFilter : false,
3159     
3160        /**
3161      * @cfg {Boolean} disabled True to disable the field (defaults to false).
3162      */
3163     disabled : false,
3164      /**
3165      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
3166      */
3167     allowBlank : true,
3168     /**
3169      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
3170      */
3171     blankText : "This field is required",
3172     
3173      /**
3174      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
3175      */
3176     minLength : 0,
3177     /**
3178      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
3179      */
3180     maxLength : Number.MAX_VALUE,
3181     /**
3182      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
3183      */
3184     minLengthText : "The minimum length for this field is {0}",
3185     /**
3186      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
3187      */
3188     maxLengthText : "The maximum length for this field is {0}",
3189   
3190     
3191     /**
3192      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
3193      * If available, this function will be called only after the basic validators all return true, and will be passed the
3194      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
3195      */
3196     validator : null,
3197     /**
3198      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
3199      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
3200      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
3201      */
3202     regex : null,
3203     /**
3204      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
3205      */
3206     regexText : "",
3207     
3208     
3209     
3210     fieldLabel : '',
3211     inputType : 'text',
3212     
3213     name : false,
3214     placeholder: false,
3215     before : false,
3216     after : false,
3217     size : false,
3218     // private
3219     hasFocus : false,
3220     preventMark: false,
3221     isFormField : true,
3222     
3223     getAutoCreate : function(){
3224         
3225         var parent = this.parent();
3226         
3227         var align = parent.labelAlign;
3228         
3229         var id = Roo.id();
3230         
3231         var cfg = {
3232             cls: 'form-group' //input-group
3233         };
3234         
3235         var input =  {
3236             tag: 'input',
3237             id : id,
3238             type : this.inputType,
3239             cls : 'form-control',
3240             placeholder : this.placeholder || '' 
3241             
3242         };
3243         if (this.name) {
3244             input.name = this.name;
3245         }
3246         if (this.size) {
3247             input.cls += ' input-' + this.size;
3248         }
3249         var settings=this;
3250         ['xs','sm','md','lg'].map(function(size){
3251             if (settings[size]) {
3252                 cfg.cls += ' col-' + size + '-' + settings[size];
3253             }
3254         });
3255         
3256         var inputblock = input;
3257         
3258         if (this.before || this.after) {
3259             
3260             inputblock = {
3261                 cls : 'input-group',
3262                 cn :  [] 
3263             };
3264             if (this.before) {
3265                 inputblock.cn.push({
3266                     tag :'span',
3267                     cls : 'input-group-addon',
3268                     html : this.before
3269                 });
3270             }
3271             inputblock.cn.push(input);
3272             if (this.after) {
3273                 inputblock.cn.push({
3274                     tag :'span',
3275                     cls : 'input-group-addon',
3276                     html : this.after
3277                 });
3278             }
3279             
3280         }
3281         
3282         Roo.log(align);
3283         Roo.log(this.fieldLabel.length);
3284         
3285         if (align ==='left' && this.fieldLabel.length) {
3286                 Roo.log("left and has label");
3287                 cfg.cn = [
3288                     
3289                     {
3290                         tag: 'label',
3291                         'for' :  id,
3292                         cls : 'col-sm-2 control-label',
3293                         html : this.fieldLabel
3294                         
3295                     },
3296                     {
3297                         cls : "col-sm-10", 
3298                         cn: [
3299                             inputblock
3300                         ]
3301                     }
3302                     
3303                 ];
3304         } else if ( this.fieldLabel.length) {
3305                 Roo.log(" label");
3306                  cfg.cn = [
3307                    
3308                     {
3309                         tag: 'label',
3310                         //cls : 'input-group-addon',
3311                         html : this.fieldLabel
3312                         
3313                     },
3314                     
3315                     inputblock
3316                     
3317                 ];
3318
3319         } else {
3320             
3321                    Roo.log(" no label && no align");
3322                 cfg.cn = [
3323                     
3324                         inputblock
3325                     
3326                 ];
3327                 
3328                 
3329         }
3330          
3331         
3332         
3333         
3334         if (this.disabled) {
3335             input.disabled=true;
3336         }
3337         return cfg;
3338         
3339     },
3340     /**
3341      * return the real input element.
3342      */
3343     inputEl: function ()
3344     {
3345         return this.el.select('input.form-control',true).first();
3346     },
3347     setDisabled : function(v)
3348     {
3349         var i  = this.inputEl().dom;
3350         if (v) {
3351             i.removeAttribute('disabled');
3352             return;
3353             
3354         }
3355         i.setAttribute('disabled','true');
3356     },
3357     initEvents : function()
3358     {
3359         
3360         this.inputEl().on("keydown" , this.fireKey,  this);
3361         this.inputEl().on("focus", this.onFocus,  this);
3362         this.inputEl().on("blur", this.onBlur,  this);
3363         this.inputEl().relayEvent('keyup', this);
3364
3365         // reference to original value for reset
3366         this.originalValue = this.getValue();
3367         //Roo.form.TextField.superclass.initEvents.call(this);
3368         if(this.validationEvent == 'keyup'){
3369             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
3370             this.inputEl().on('keyup', this.filterValidation, this);
3371         }
3372         else if(this.validationEvent !== false){
3373             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
3374         }
3375         
3376         if(this.selectOnFocus){
3377             this.on("focus", this.preFocus, this);
3378             
3379         }
3380         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
3381             this.inputEl().on("keypress", this.filterKeys, this);
3382         }
3383        /* if(this.grow){
3384             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
3385             this.el.on("click", this.autoSize,  this);
3386         }
3387         */
3388         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
3389             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
3390         }
3391         
3392     },
3393     filterValidation : function(e){
3394         if(!e.isNavKeyPress()){
3395             this.validationTask.delay(this.validationDelay);
3396         }
3397     },
3398      /**
3399      * Validates the field value
3400      * @return {Boolean} True if the value is valid, else false
3401      */
3402     validate : function(){
3403         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
3404         if(this.disabled || this.validateValue(this.getRawValue())){
3405             this.clearInvalid();
3406             return true;
3407         }
3408         return false;
3409     },
3410     
3411     
3412     /**
3413      * Validates a value according to the field's validation rules and marks the field as invalid
3414      * if the validation fails
3415      * @param {Mixed} value The value to validate
3416      * @return {Boolean} True if the value is valid, else false
3417      */
3418     validateValue : function(value){
3419         if(value.length < 1)  { // if it's blank
3420              if(this.allowBlank){
3421                 this.clearInvalid();
3422                 return true;
3423              }else{
3424                 this.markInvalid(this.blankText);
3425                 return false;
3426              }
3427         }
3428         if(value.length < this.minLength){
3429             this.markInvalid(String.format(this.minLengthText, this.minLength));
3430             return false;
3431         }
3432         if(value.length > this.maxLength){
3433             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
3434             return false;
3435         }
3436         if(this.vtype){
3437             var vt = Roo.form.VTypes;
3438             if(!vt[this.vtype](value, this)){
3439                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
3440                 return false;
3441             }
3442         }
3443         if(typeof this.validator == "function"){
3444             var msg = this.validator(value);
3445             if(msg !== true){
3446                 this.markInvalid(msg);
3447                 return false;
3448             }
3449         }
3450         if(this.regex && !this.regex.test(value)){
3451             this.markInvalid(this.regexText);
3452             return false;
3453         }
3454         return true;
3455     },
3456
3457     
3458     
3459      // private
3460     fireKey : function(e){
3461         //Roo.log('field ' + e.getKey());
3462         if(e.isNavKeyPress()){
3463             this.fireEvent("specialkey", this, e);
3464         }
3465     },
3466     focus : function (selectText){
3467         if(this.rendered){
3468             this.inputEl().focus();
3469             if(selectText === true){
3470                 this.inputEl().dom.select();
3471             }
3472         }
3473         return this;
3474     } ,
3475     
3476     onFocus : function(){
3477         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3478            // this.el.addClass(this.focusClass);
3479         }
3480         if(!this.hasFocus){
3481             this.hasFocus = true;
3482             this.startValue = this.getValue();
3483             this.fireEvent("focus", this);
3484         }
3485     },
3486     
3487     beforeBlur : Roo.emptyFn,
3488
3489     
3490     // private
3491     onBlur : function(){
3492         this.beforeBlur();
3493         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3494             //this.el.removeClass(this.focusClass);
3495         }
3496         this.hasFocus = false;
3497         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3498             this.validate();
3499         }
3500         var v = this.getValue();
3501         if(String(v) !== String(this.startValue)){
3502             this.fireEvent('change', this, v, this.startValue);
3503         }
3504         this.fireEvent("blur", this);
3505     },
3506     
3507     /**
3508      * Resets the current field value to the originally loaded value and clears any validation messages
3509      */
3510     reset : function(){
3511         this.setValue(this.originalValue);
3512         this.clearInvalid();
3513     },
3514      /**
3515      * Returns the name of the field
3516      * @return {Mixed} name The name field
3517      */
3518     getName: function(){
3519         return this.name;
3520     },
3521      /**
3522      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
3523      * @return {Mixed} value The field value
3524      */
3525     getValue : function(){
3526         var v = this.inputEl().getValue();
3527         return v;
3528     },
3529     /**
3530      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
3531      * @return {Mixed} value The field value
3532      */
3533     getRawValue : function(){
3534         var v = this.inputEl().getValue();
3535         
3536         return v;
3537     },
3538     /**
3539      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
3540      * @param {Mixed} value The value to set
3541      */
3542     setValue : function(v){
3543         this.value = v;
3544         if(this.rendered){
3545             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3546             this.validate();
3547         }
3548     },
3549     
3550     /*
3551     processValue : function(value){
3552         if(this.stripCharsRe){
3553             var newValue = value.replace(this.stripCharsRe, '');
3554             if(newValue !== value){
3555                 this.setRawValue(newValue);
3556                 return newValue;
3557             }
3558         }
3559         return value;
3560     },
3561   */
3562     preFocus : function(){
3563         
3564         if(this.selectOnFocus){
3565             this.inputEl().dom.select();
3566         }
3567     },
3568     filterKeys : function(e){
3569         var k = e.getKey();
3570         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3571             return;
3572         }
3573         var c = e.getCharCode(), cc = String.fromCharCode(c);
3574         if(Roo.isIE && (e.isSpecialKey() || !cc)){
3575             return;
3576         }
3577         if(!this.maskRe.test(cc)){
3578             e.stopEvent();
3579         }
3580     },
3581      /**
3582      * Clear any invalid styles/messages for this field
3583      */
3584     clearInvalid : function(){
3585         
3586         if(!this.el || this.preventMark){ // not rendered
3587             return;
3588         }
3589         this.el.removeClass(this.invalidClass);
3590         /*
3591         switch(this.msgTarget){
3592             case 'qtip':
3593                 this.el.dom.qtip = '';
3594                 break;
3595             case 'title':
3596                 this.el.dom.title = '';
3597                 break;
3598             case 'under':
3599                 if(this.errorEl){
3600                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3601                 }
3602                 break;
3603             case 'side':
3604                 if(this.errorIcon){
3605                     this.errorIcon.dom.qtip = '';
3606                     this.errorIcon.hide();
3607                     this.un('resize', this.alignErrorIcon, this);
3608                 }
3609                 break;
3610             default:
3611                 var t = Roo.getDom(this.msgTarget);
3612                 t.innerHTML = '';
3613                 t.style.display = 'none';
3614                 break;
3615         }
3616         */
3617         this.fireEvent('valid', this);
3618     },
3619      /**
3620      * Mark this field as invalid
3621      * @param {String} msg The validation message
3622      */
3623     markInvalid : function(msg){
3624         if(!this.el  || this.preventMark){ // not rendered
3625             return;
3626         }
3627         this.el.addClass(this.invalidClass);
3628         /*
3629         msg = msg || this.invalidText;
3630         switch(this.msgTarget){
3631             case 'qtip':
3632                 this.el.dom.qtip = msg;
3633                 this.el.dom.qclass = 'x-form-invalid-tip';
3634                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3635                     Roo.QuickTips.enable();
3636                 }
3637                 break;
3638             case 'title':
3639                 this.el.dom.title = msg;
3640                 break;
3641             case 'under':
3642                 if(!this.errorEl){
3643                     var elp = this.el.findParent('.x-form-element', 5, true);
3644                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3645                     this.errorEl.setWidth(elp.getWidth(true)-20);
3646                 }
3647                 this.errorEl.update(msg);
3648                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3649                 break;
3650             case 'side':
3651                 if(!this.errorIcon){
3652                     var elp = this.el.findParent('.x-form-element', 5, true);
3653                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3654                 }
3655                 this.alignErrorIcon();
3656                 this.errorIcon.dom.qtip = msg;
3657                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3658                 this.errorIcon.show();
3659                 this.on('resize', this.alignErrorIcon, this);
3660                 break;
3661             default:
3662                 var t = Roo.getDom(this.msgTarget);
3663                 t.innerHTML = msg;
3664                 t.style.display = this.msgDisplay;
3665                 break;
3666         }
3667         */
3668         this.fireEvent('invalid', this, msg);
3669     },
3670     // private
3671     SafariOnKeyDown : function(event)
3672     {
3673         // this is a workaround for a password hang bug on chrome/ webkit.
3674         
3675         var isSelectAll = false;
3676         
3677         if(this.inputEl().dom.selectionEnd > 0){
3678             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3679         }
3680         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3681             event.preventDefault();
3682             this.setValue('');
3683             return;
3684         }
3685         
3686         if(isSelectAll){ // backspace and delete key
3687             
3688             event.preventDefault();
3689             // this is very hacky as keydown always get's upper case.
3690             //
3691             var cc = String.fromCharCode(event.getCharCode());
3692             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
3693             
3694         }
3695         
3696         
3697     }
3698 });
3699
3700  
3701 /*
3702  * - LGPL
3703  *
3704  * trigger field - base class for combo..
3705  * 
3706  */
3707  
3708 /**
3709  * @class Roo.bootstrap.TriggerField
3710  * @extends Roo.bootstrap.Input
3711  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
3712  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
3713  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
3714  * for which you can provide a custom implementation.  For example:
3715  * <pre><code>
3716 var trigger = new Roo.bootstrap.TriggerField();
3717 trigger.onTriggerClick = myTriggerFn;
3718 trigger.applyTo('my-field');
3719 </code></pre>
3720  *
3721  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
3722  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
3723  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
3724  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
3725  * @constructor
3726  * Create a new TriggerField.
3727  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
3728  * to the base TextField)
3729  */
3730 Roo.bootstrap.TriggerField = function(config){
3731     this.mimicing = false;
3732     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
3733 };
3734
3735 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
3736     /**
3737      * @cfg {String} triggerClass A CSS class to apply to the trigger
3738      */
3739      /**
3740      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
3741      */
3742     hideTrigger:false,
3743
3744     /** @cfg {Boolean} grow @hide */
3745     /** @cfg {Number} growMin @hide */
3746     /** @cfg {Number} growMax @hide */
3747
3748     /**
3749      * @hide 
3750      * @method
3751      */
3752     autoSize: Roo.emptyFn,
3753     // private
3754     monitorTab : true,
3755     // private
3756     deferHeight : true,
3757
3758     
3759     actionMode : 'wrap',
3760     
3761     
3762     
3763     getAutoCreate : function(){
3764        
3765         var parent = this.parent();
3766         
3767         var align = parent.labelAlign;
3768         
3769         var id = Roo.id();
3770         
3771         var cfg = {
3772             cls: 'form-group' //input-group
3773         };
3774         
3775         
3776         var input =  {
3777             tag: 'input',
3778             id : id,
3779             type : this.inputType,
3780             cls : 'form-control',
3781             autocomplete: 'off',
3782             placeholder : this.placeholder || '' 
3783             
3784         };
3785         if (this.name) {
3786             input.name = this.name;
3787         }
3788         if (this.size) {
3789             input.cls += ' input-' + this.size;
3790         }
3791         var inputblock = {
3792             cls: 'combobox-container input-group',
3793             cn: [
3794                 {
3795                     tag: 'input',
3796                     type : 'hidden',
3797                     cls: 'form-hidden-field'
3798                 },
3799                 input,
3800                 {
3801                     tag: 'ul',
3802                     cls : 'typeahead typeahead-long dropdown-menu',
3803                     style : 'display:none'
3804                 },
3805                 {
3806                     tag :'span',
3807                     cls : 'input-group-addon btn dropdown-toggle',
3808                     cn : [
3809                         {
3810                             tag: 'span',
3811                             cls: 'caret'
3812                         },
3813                         {
3814                             tag: 'span',
3815                             cls: 'combobox-clear',
3816                             cn  : [
3817                                 {
3818                                     tag : 'i',
3819                                     cls: 'icon-remove'
3820                                 }
3821                             ]
3822                         }
3823                     ]
3824                         
3825                 }
3826             ]
3827         };
3828         
3829         
3830         
3831         
3832         if (align ==='left' && this.fieldLabel.length) {
3833                 
3834             
3835             
3836                 Roo.log("left and has label");
3837                 cfg.cn = [
3838                     
3839                     {
3840                         tag: 'label',
3841                         'for' :  id,
3842                         cls : 'col-sm-2 control-label',
3843                         html : this.fieldLabel
3844                         
3845                     },
3846                     {
3847                         cls : "col-sm-10", 
3848                         cn: [
3849                             inputblock
3850                         ]
3851                     }
3852                     
3853                 ];
3854         } else if ( this.fieldLabel.length) {
3855                 Roo.log(" label");
3856                  cfg.cn = [
3857                    
3858                     {
3859                         tag: 'label',
3860                         //cls : 'input-group-addon',
3861                         html : this.fieldLabel
3862                         
3863                     },
3864                     
3865                     inputblock
3866                     
3867                 ];
3868
3869         } else {
3870             
3871                 Roo.log(" no label && no align");
3872                 cfg = inputblock
3873                      
3874                 
3875         }
3876          
3877         var settings=this;
3878         ['xs','sm','md','lg'].map(function(size){
3879             if (settings[size]) {
3880                 cfg.cls += ' col-' + size + '-' + settings[size];
3881             }
3882         });
3883         
3884         
3885         
3886         if (this.disabled) {
3887             input.disabled=true;
3888         }
3889         return cfg;
3890         
3891     },
3892     
3893     
3894     
3895     // private
3896     onResize : function(w, h){
3897         Roo.boostrap.TriggerField.superclass.onResize.apply(this, arguments);
3898         if(typeof w == 'number'){
3899             var x = w - this.trigger.getWidth();
3900             this.inputEl().setWidth(this.adjustWidth('input', x));
3901             this.trigger.setStyle('left', x+'px');
3902         }
3903     },
3904
3905     // private
3906     adjustSize : Roo.BoxComponent.prototype.adjustSize,
3907
3908     // private
3909     getResizeEl : function(){
3910         return this.inputEl();
3911     },
3912
3913     // private
3914     getPositionEl : function(){
3915         return this.inputEl();
3916     },
3917
3918     // private
3919     alignErrorIcon : function(){
3920         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
3921     },
3922
3923     // private
3924     initEvents : function(){
3925         
3926         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
3927         
3928         this.trigger = this.el.select('span.dropdown-toggle',true).first();
3929         if(this.hideTrigger){
3930             this.trigger.setDisplayed(false);
3931         }
3932         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
3933         //this.trigger.addClassOnOver('x-form-trigger-over');
3934         //this.trigger.addClassOnClick('x-form-trigger-click');
3935         
3936         //if(!this.width){
3937         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
3938         //}
3939     },
3940
3941     // private
3942     initTrigger : function(){
3943        
3944     },
3945
3946     // private
3947     onDestroy : function(){
3948         if(this.trigger){
3949             this.trigger.removeAllListeners();
3950           //  this.trigger.remove();
3951         }
3952         //if(this.wrap){
3953         //    this.wrap.remove();
3954         //}
3955         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
3956     },
3957
3958     // private
3959     onFocus : function(){
3960         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
3961         /*
3962         if(!this.mimicing){
3963             this.wrap.addClass('x-trigger-wrap-focus');
3964             this.mimicing = true;
3965             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
3966             if(this.monitorTab){
3967                 this.el.on("keydown", this.checkTab, this);
3968             }
3969         }
3970         */
3971     },
3972
3973     // private
3974     checkTab : function(e){
3975         if(e.getKey() == e.TAB){
3976             this.triggerBlur();
3977         }
3978     },
3979
3980     // private
3981     onBlur : function(){
3982         // do nothing
3983     },
3984
3985     // private
3986     mimicBlur : function(e, t){
3987         /*
3988         if(!this.wrap.contains(t) && this.validateBlur()){
3989             this.triggerBlur();
3990         }
3991         */
3992     },
3993
3994     // private
3995     triggerBlur : function(){
3996         this.mimicing = false;
3997         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
3998         if(this.monitorTab){
3999             this.el.un("keydown", this.checkTab, this);
4000         }
4001         //this.wrap.removeClass('x-trigger-wrap-focus');
4002         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
4003     },
4004
4005     // private
4006     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
4007     validateBlur : function(e, t){
4008         return true;
4009     },
4010
4011     // private
4012     onDisable : function(){
4013         Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
4014         //if(this.wrap){
4015         //    this.wrap.addClass('x-item-disabled');
4016         //}
4017     },
4018
4019     // private
4020     onEnable : function(){
4021         Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
4022         //if(this.wrap){
4023         //    this.el.removeClass('x-item-disabled');
4024         //}
4025     },
4026
4027     // private
4028     onShow : function(){
4029         var ae = this.getActionEl();
4030         
4031         if(ae){
4032             ae.dom.style.display = '';
4033             ae.dom.style.visibility = 'visible';
4034         }
4035     },
4036
4037     // private
4038     
4039     onHide : function(){
4040         var ae = this.getActionEl();
4041         ae.dom.style.display = 'none';
4042     },
4043
4044     /**
4045      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
4046      * by an implementing function.
4047      * @method
4048      * @param {EventObject} e
4049      */
4050     onTriggerClick : Roo.emptyFn
4051 });
4052  /*
4053  * - LGPL
4054  * * 
4055  */
4056
4057 /**
4058  * @class Roo.bootstrap.ComboBox
4059  * @extends Roo.bootstrap.TriggerField
4060  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
4061  * @constructor
4062  * Create a new ComboBox.
4063  * @param {Object} config Configuration options
4064  */
4065 Roo.bootstrap.ComboBox = function(config){
4066     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
4067     this.addEvents({
4068         /**
4069          * @event expand
4070          * Fires when the dropdown list is expanded
4071              * @param {Roo.bootstrap.ComboBox} combo This combo box
4072              */
4073         'expand' : true,
4074         /**
4075          * @event collapse
4076          * Fires when the dropdown list is collapsed
4077              * @param {Roo.bootstrap.ComboBox} combo This combo box
4078              */
4079         'collapse' : true,
4080         /**
4081          * @event beforeselect
4082          * Fires before a list item is selected. Return false to cancel the selection.
4083              * @param {Roo.bootstrap.ComboBox} combo This combo box
4084              * @param {Roo.data.Record} record The data record returned from the underlying store
4085              * @param {Number} index The index of the selected item in the dropdown list
4086              */
4087         'beforeselect' : true,
4088         /**
4089          * @event select
4090          * Fires when a list item is selected
4091              * @param {Roo.bootstrap.ComboBox} combo This combo box
4092              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
4093              * @param {Number} index The index of the selected item in the dropdown list
4094              */
4095         'select' : true,
4096         /**
4097          * @event beforequery
4098          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
4099          * The event object passed has these properties:
4100              * @param {Roo.bootstrap.ComboBox} combo This combo box
4101              * @param {String} query The query
4102              * @param {Boolean} forceAll true to force "all" query
4103              * @param {Boolean} cancel true to cancel the query
4104              * @param {Object} e The query event object
4105              */
4106         'beforequery': true,
4107          /**
4108          * @event add
4109          * Fires when the 'add' icon is pressed (add a listener to enable add button)
4110              * @param {Roo.bootstrap.ComboBox} combo This combo box
4111              */
4112         'add' : true,
4113         /**
4114          * @event edit
4115          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
4116              * @param {Roo.bootstrap.ComboBox} combo This combo box
4117              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
4118              */
4119         'edit' : true
4120         
4121         
4122     });
4123     
4124     if (!this.store) {
4125         throw "can not find store for combo";
4126     }
4127     this.store = Roo.factory(this.store, Roo.data);
4128     
4129     
4130     this.selectedIndex = -1;
4131     if(this.mode == 'local'){
4132         if(config.queryDelay === undefined){
4133             this.queryDelay = 10;
4134         }
4135         if(config.minChars === undefined){
4136             this.minChars = 0;
4137         }
4138     }
4139 };
4140
4141 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
4142      
4143     /**
4144      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
4145      * rendering into an Roo.Editor, defaults to false)
4146      */
4147     /**
4148      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
4149      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
4150      */
4151     /**
4152      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
4153      */
4154     /**
4155      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
4156      * the dropdown list (defaults to undefined, with no header element)
4157      */
4158
4159      /**
4160      * @cfg {String/Roo.Template} tpl The template to use to render the output
4161      */
4162      
4163      /**
4164      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
4165      */
4166     listWidth: undefined,
4167     /**
4168      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
4169      * mode = 'remote' or 'text' if mode = 'local')
4170      */
4171     displayField: undefined,
4172     /**
4173      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
4174      * mode = 'remote' or 'value' if mode = 'local'). 
4175      * Note: use of a valueField requires the user make a selection
4176      * in order for a value to be mapped.
4177      */
4178     valueField: undefined,
4179     
4180     
4181     /**
4182      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
4183      * field's data value (defaults to the underlying DOM element's name)
4184      */
4185     hiddenName: undefined,
4186     /**
4187      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
4188      */
4189     listClass: '',
4190     /**
4191      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
4192      */
4193     selectedClass: 'active',
4194     
4195     /**
4196      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
4197      */
4198     shadow:'sides',
4199     /**
4200      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
4201      * anchor positions (defaults to 'tl-bl')
4202      */
4203     listAlign: 'tl-bl?',
4204     /**
4205      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
4206      */
4207     maxHeight: 300,
4208     /**
4209      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
4210      * query specified by the allQuery config option (defaults to 'query')
4211      */
4212     triggerAction: 'query',
4213     /**
4214      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
4215      * (defaults to 4, does not apply if editable = false)
4216      */
4217     minChars : 4,
4218     /**
4219      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
4220      * delay (typeAheadDelay) if it matches a known value (defaults to false)
4221      */
4222     typeAhead: false,
4223     /**
4224      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
4225      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
4226      */
4227     queryDelay: 500,
4228     /**
4229      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
4230      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
4231      */
4232     pageSize: 0,
4233     /**
4234      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
4235      * when editable = true (defaults to false)
4236      */
4237     selectOnFocus:false,
4238     /**
4239      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
4240      */
4241     queryParam: 'query',
4242     /**
4243      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
4244      * when mode = 'remote' (defaults to 'Loading...')
4245      */
4246     loadingText: 'Loading...',
4247     /**
4248      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
4249      */
4250     resizable: false,
4251     /**
4252      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
4253      */
4254     handleHeight : 8,
4255     /**
4256      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
4257      * traditional select (defaults to true)
4258      */
4259     editable: true,
4260     /**
4261      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
4262      */
4263     allQuery: '',
4264     /**
4265      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
4266      */
4267     mode: 'remote',
4268     /**
4269      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
4270      * listWidth has a higher value)
4271      */
4272     minListWidth : 70,
4273     /**
4274      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
4275      * allow the user to set arbitrary text into the field (defaults to false)
4276      */
4277     forceSelection:false,
4278     /**
4279      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
4280      * if typeAhead = true (defaults to 250)
4281      */
4282     typeAheadDelay : 250,
4283     /**
4284      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
4285      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
4286      */
4287     valueNotFoundText : undefined,
4288     /**
4289      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
4290      */
4291     blockFocus : false,
4292     
4293     /**
4294      * @cfg {Boolean} disableClear Disable showing of clear button.
4295      */
4296     disableClear : false,
4297     /**
4298      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
4299      */
4300     alwaysQuery : false,
4301     
4302     //private
4303     addicon : false,
4304     editicon: false,
4305     
4306     // element that contains real text value.. (when hidden is used..)
4307      
4308     // private
4309     initEvents: function(){
4310         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
4311         
4312         
4313         if(this.hiddenName){
4314             
4315             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
4316             
4317             this.hiddenField.dom.value =
4318                 this.hiddenValue !== undefined ? this.hiddenValue :
4319                 this.value !== undefined ? this.value : '';
4320
4321             // prevent input submission
4322             this.el.dom.removeAttribute('name');
4323             this.hiddenField.dom.setAttribute('name', this.hiddenName);
4324              
4325              
4326         }
4327         //if(Roo.isGecko){
4328         //    this.el.dom.setAttribute('autocomplete', 'off');
4329         //}
4330
4331         var cls = 'x-combo-list';
4332         this.list = this.el.select('ul',true).first();
4333
4334         //this.list = new Roo.Layer({
4335         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
4336         //});
4337         
4338         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
4339         this.list.setWidth(lw);
4340         /*
4341         this.list.swallowEvent('mousewheel');
4342         this.assetHeight = 0;
4343
4344         if(this.title){
4345             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
4346             this.assetHeight += this.header.getHeight();
4347         }
4348
4349         this.innerList = this.list.createChild({cls:cls+'-inner'});
4350         this.innerList.on('mouseover', this.onViewOver, this);
4351         this.innerList.on('mousemove', this.onViewMove, this);
4352         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
4353         
4354         if(this.allowBlank && !this.pageSize && !this.disableClear){
4355             this.footer = this.list.createChild({cls:cls+'-ft'});
4356             this.pageTb = new Roo.Toolbar(this.footer);
4357            
4358         }
4359         if(this.pageSize){
4360             this.footer = this.list.createChild({cls:cls+'-ft'});
4361             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
4362                     {pageSize: this.pageSize});
4363             
4364         }
4365         
4366         if (this.pageTb && this.allowBlank && !this.disableClear) {
4367             var _this = this;
4368             this.pageTb.add(new Roo.Toolbar.Fill(), {
4369                 cls: 'x-btn-icon x-btn-clear',
4370                 text: '&#160;',
4371                 handler: function()
4372                 {
4373                     _this.collapse();
4374                     _this.clearValue();
4375                     _this.onSelect(false, -1);
4376                 }
4377             });
4378         }
4379         if (this.footer) {
4380             this.assetHeight += this.footer.getHeight();
4381         }
4382         */
4383             
4384         if(!this.tpl){
4385             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
4386         }
4387
4388         this.view = new Roo.View(this.el.select('ul',true).first(), this.tpl, {
4389             singleSelect:true, store: this.store, selectedClass: this.selectedClass
4390         });
4391         //this.view.wrapEl.setDisplayed(false);
4392         this.view.on('click', this.onViewClick, this);
4393         
4394         
4395         
4396         this.store.on('beforeload', this.onBeforeLoad, this);
4397         this.store.on('load', this.onLoad, this);
4398         this.store.on('loadexception', this.onLoadException, this);
4399         /*
4400         if(this.resizable){
4401             this.resizer = new Roo.Resizable(this.list,  {
4402                pinned:true, handles:'se'
4403             });
4404             this.resizer.on('resize', function(r, w, h){
4405                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
4406                 this.listWidth = w;
4407                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
4408                 this.restrictHeight();
4409             }, this);
4410             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
4411         }
4412         */
4413         if(!this.editable){
4414             this.editable = true;
4415             this.setEditable(false);
4416         }
4417         
4418         /*
4419         
4420         if (typeof(this.events.add.listeners) != 'undefined') {
4421             
4422             this.addicon = this.wrap.createChild(
4423                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
4424        
4425             this.addicon.on('click', function(e) {
4426                 this.fireEvent('add', this);
4427             }, this);
4428         }
4429         if (typeof(this.events.edit.listeners) != 'undefined') {
4430             
4431             this.editicon = this.wrap.createChild(
4432                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
4433             if (this.addicon) {
4434                 this.editicon.setStyle('margin-left', '40px');
4435             }
4436             this.editicon.on('click', function(e) {
4437                 
4438                 // we fire even  if inothing is selected..
4439                 this.fireEvent('edit', this, this.lastData );
4440                 
4441             }, this);
4442         }
4443         */
4444         
4445  
4446         this.keyNav = new Roo.KeyNav(this.inputEl(), {
4447             "up" : function(e){
4448                 this.inKeyMode = true;
4449                 this.selectPrev();
4450             },
4451
4452             "down" : function(e){
4453                 if(!this.isExpanded()){
4454                     this.onTriggerClick();
4455                 }else{
4456                     this.inKeyMode = true;
4457                     this.selectNext();
4458                 }
4459             },
4460
4461             "enter" : function(e){
4462                 this.onViewClick();
4463                 //return true;
4464             },
4465
4466             "esc" : function(e){
4467                 this.collapse();
4468             },
4469
4470             "tab" : function(e){
4471                 this.onViewClick(false);
4472                 this.fireEvent("specialkey", this, e);
4473                 return true;
4474             },
4475
4476             scope : this,
4477
4478             doRelay : function(foo, bar, hname){
4479                 if(hname == 'down' || this.scope.isExpanded()){
4480                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
4481                 }
4482                 return true;
4483             },
4484
4485             forceKeyDown: true
4486         });
4487         
4488         
4489         this.queryDelay = Math.max(this.queryDelay || 10,
4490                 this.mode == 'local' ? 10 : 250);
4491         
4492         
4493         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
4494         
4495         if(this.typeAhead){
4496             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
4497         }
4498         if(this.editable !== false){
4499             this.inputEl().on("keyup", this.onKeyUp, this);
4500         }
4501         if(this.forceSelection){
4502             this.on('blur', this.doForce, this);
4503         }
4504     },
4505
4506     onDestroy : function(){
4507         if(this.view){
4508             this.view.setStore(null);
4509             this.view.el.removeAllListeners();
4510             this.view.el.remove();
4511             this.view.purgeListeners();
4512         }
4513         if(this.list){
4514             this.list.dom.innerHTML  = '';
4515         }
4516         if(this.store){
4517             this.store.un('beforeload', this.onBeforeLoad, this);
4518             this.store.un('load', this.onLoad, this);
4519             this.store.un('loadexception', this.onLoadException, this);
4520         }
4521         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
4522     },
4523
4524     // private
4525     fireKey : function(e){
4526         if(e.isNavKeyPress() && !this.list.isVisible()){
4527             this.fireEvent("specialkey", this, e);
4528         }
4529     },
4530
4531     // private
4532     onResize: function(w, h){
4533         Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
4534         
4535         if(typeof w != 'number'){
4536             // we do not handle it!?!?
4537             return;
4538         }
4539         var tw = this.trigger.getWidth();
4540        // tw += this.addicon ? this.addicon.getWidth() : 0;
4541        // tw += this.editicon ? this.editicon.getWidth() : 0;
4542         var x = w - tw;
4543         this.inputEl().setWidth( this.adjustWidth('input', x));
4544             
4545         //this.trigger.setStyle('left', x+'px');
4546         
4547         if(this.list && this.listWidth === undefined){
4548             var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
4549             this.list.setWidth(lw);
4550             this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
4551         }
4552         
4553     
4554         
4555     },
4556
4557     /**
4558      * Allow or prevent the user from directly editing the field text.  If false is passed,
4559      * the user will only be able to select from the items defined in the dropdown list.  This method
4560      * is the runtime equivalent of setting the 'editable' config option at config time.
4561      * @param {Boolean} value True to allow the user to directly edit the field text
4562      */
4563     setEditable : function(value){
4564         if(value == this.editable){
4565             return;
4566         }
4567         this.editable = value;
4568         if(!value){
4569             this.inputEl().dom.setAttribute('readOnly', true);
4570             this.inputEl().on('mousedown', this.onTriggerClick,  this);
4571             this.inputEl().addClass('x-combo-noedit');
4572         }else{
4573             this.inputEl().dom.setAttribute('readOnly', false);
4574             this.inputEl().un('mousedown', this.onTriggerClick,  this);
4575             this.inputEl().removeClass('x-combo-noedit');
4576         }
4577     },
4578
4579     // private
4580     onBeforeLoad : function(){
4581         if(!this.hasFocus){
4582             return;
4583         }
4584         //this.innerList.update(this.loadingText ?
4585         //       '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
4586         this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
4587         
4588         this.restrictHeight();
4589         this.selectedIndex = -1;
4590     },
4591
4592     // private
4593     onLoad : function(){
4594         if(!this.hasFocus){
4595             return;
4596         }
4597         if(this.store.getCount() > 0){
4598             this.expand();
4599             this.restrictHeight();
4600             if(this.lastQuery == this.allQuery){
4601                 if(this.editable){
4602                     this.inputEl().dom.select();
4603                 }
4604                 if(!this.selectByValue(this.value, true)){
4605                     this.select(0, true);
4606                 }
4607             }else{
4608                 this.selectNext();
4609                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
4610                     this.taTask.delay(this.typeAheadDelay);
4611                 }
4612             }
4613         }else{
4614             this.onEmptyResults();
4615         }
4616         //this.el.focus();
4617     },
4618     // private
4619     onLoadException : function()
4620     {
4621         this.collapse();
4622         Roo.log(this.store.reader.jsonData);
4623         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4624             // fixme
4625             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4626         }
4627         
4628         
4629     },
4630     // private
4631     onTypeAhead : function(){
4632         if(this.store.getCount() > 0){
4633             var r = this.store.getAt(0);
4634             var newValue = r.data[this.displayField];
4635             var len = newValue.length;
4636             var selStart = this.getRawValue().length;
4637             if(selStart != len){
4638                 this.setRawValue(newValue);
4639                 this.selectText(selStart, newValue.length);
4640             }
4641         }
4642     },
4643
4644     // private
4645     onSelect : function(record, index){
4646         if(this.fireEvent('beforeselect', this, record, index) !== false){
4647             this.setFromData(index > -1 ? record.data : false);
4648             this.collapse();
4649             this.fireEvent('select', this, record, index);
4650         }
4651     },
4652
4653     /**
4654      * Returns the currently selected field value or empty string if no value is set.
4655      * @return {String} value The selected value
4656      */
4657     getValue : function(){
4658         if(this.valueField){
4659             return typeof this.value != 'undefined' ? this.value : '';
4660         }else{
4661             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
4662         }
4663     },
4664
4665     /**
4666      * Clears any text/value currently set in the field
4667      */
4668     clearValue : function(){
4669         if(this.hiddenField){
4670             this.hiddenField.dom.value = '';
4671         }
4672         this.value = '';
4673         this.setRawValue('');
4674         this.lastSelectionText = '';
4675         
4676     },
4677
4678     /**
4679      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
4680      * will be displayed in the field.  If the value does not match the data value of an existing item,
4681      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
4682      * Otherwise the field will be blank (although the value will still be set).
4683      * @param {String} value The value to match
4684      */
4685     setValue : function(v){
4686         var text = v;
4687         if(this.valueField){
4688             var r = this.findRecord(this.valueField, v);
4689             if(r){
4690                 text = r.data[this.displayField];
4691             }else if(this.valueNotFoundText !== undefined){
4692                 text = this.valueNotFoundText;
4693             }
4694         }
4695         this.lastSelectionText = text;
4696         if(this.hiddenField){
4697             this.hiddenField.dom.value = v;
4698         }
4699         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
4700         this.value = v;
4701     },
4702     /**
4703      * @property {Object} the last set data for the element
4704      */
4705     
4706     lastData : false,
4707     /**
4708      * Sets the value of the field based on a object which is related to the record format for the store.
4709      * @param {Object} value the value to set as. or false on reset?
4710      */
4711     setFromData : function(o){
4712         var dv = ''; // display value
4713         var vv = ''; // value value..
4714         this.lastData = o;
4715         if (this.displayField) {
4716             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
4717         } else {
4718             // this is an error condition!!!
4719             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
4720         }
4721         
4722         if(this.valueField){
4723             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
4724         }
4725         if(this.hiddenField){
4726             this.hiddenField.dom.value = vv;
4727             
4728             this.lastSelectionText = dv;
4729             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
4730             this.value = vv;
4731             return;
4732         }
4733         // no hidden field.. - we store the value in 'value', but still display
4734         // display field!!!!
4735         this.lastSelectionText = dv;
4736         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
4737         this.value = vv;
4738         
4739         
4740     },
4741     // private
4742     reset : function(){
4743         // overridden so that last data is reset..
4744         this.setValue(this.originalValue);
4745         this.clearInvalid();
4746         this.lastData = false;
4747         if (this.view) {
4748             this.view.clearSelections();
4749         }
4750     },
4751     // private
4752     findRecord : function(prop, value){
4753         var record;
4754         if(this.store.getCount() > 0){
4755             this.store.each(function(r){
4756                 if(r.data[prop] == value){
4757                     record = r;
4758                     return false;
4759                 }
4760                 return true;
4761             });
4762         }
4763         return record;
4764     },
4765     
4766     getName: function()
4767     {
4768         // returns hidden if it's set..
4769         if (!this.rendered) {return ''};
4770         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
4771         
4772     },
4773     // private
4774     onViewMove : function(e, t){
4775         this.inKeyMode = false;
4776     },
4777
4778     // private
4779     onViewOver : function(e, t){
4780         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
4781             return;
4782         }
4783         var item = this.view.findItemFromChild(t);
4784         if(item){
4785             var index = this.view.indexOf(item);
4786             this.select(index, false);
4787         }
4788     },
4789
4790     // private
4791     onViewClick : function(doFocus)
4792     {
4793         var index = this.view.getSelectedIndexes()[0];
4794         var r = this.store.getAt(index);
4795         if(r){
4796             this.onSelect(r, index);
4797         }
4798         if(doFocus !== false && !this.blockFocus){
4799             this.inputEl().focus();
4800         }
4801     },
4802
4803     // private
4804     restrictHeight : function(){
4805         //this.innerList.dom.style.height = '';
4806         //var inner = this.innerList.dom;
4807         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
4808         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
4809         //this.list.beginUpdate();
4810         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
4811         this.list.alignTo(this.inputEl(), this.listAlign);
4812         //this.list.endUpdate();
4813     },
4814
4815     // private
4816     onEmptyResults : function(){
4817         this.collapse();
4818     },
4819
4820     /**
4821      * Returns true if the dropdown list is expanded, else false.
4822      */
4823     isExpanded : function(){
4824         return this.list.isVisible();
4825     },
4826
4827     /**
4828      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
4829      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
4830      * @param {String} value The data value of the item to select
4831      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
4832      * selected item if it is not currently in view (defaults to true)
4833      * @return {Boolean} True if the value matched an item in the list, else false
4834      */
4835     selectByValue : function(v, scrollIntoView){
4836         if(v !== undefined && v !== null){
4837             var r = this.findRecord(this.valueField || this.displayField, v);
4838             if(r){
4839                 this.select(this.store.indexOf(r), scrollIntoView);
4840                 return true;
4841             }
4842         }
4843         return false;
4844     },
4845
4846     /**
4847      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
4848      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
4849      * @param {Number} index The zero-based index of the list item to select
4850      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
4851      * selected item if it is not currently in view (defaults to true)
4852      */
4853     select : function(index, scrollIntoView){
4854         this.selectedIndex = index;
4855         this.view.select(index);
4856         if(scrollIntoView !== false){
4857             var el = this.view.getNode(index);
4858             if(el){
4859                 //this.innerList.scrollChildIntoView(el, false);
4860                 
4861             }
4862         }
4863     },
4864
4865     // private
4866     selectNext : function(){
4867         var ct = this.store.getCount();
4868         if(ct > 0){
4869             if(this.selectedIndex == -1){
4870                 this.select(0);
4871             }else if(this.selectedIndex < ct-1){
4872                 this.select(this.selectedIndex+1);
4873             }
4874         }
4875     },
4876
4877     // private
4878     selectPrev : function(){
4879         var ct = this.store.getCount();
4880         if(ct > 0){
4881             if(this.selectedIndex == -1){
4882                 this.select(0);
4883             }else if(this.selectedIndex != 0){
4884                 this.select(this.selectedIndex-1);
4885             }
4886         }
4887     },
4888
4889     // private
4890     onKeyUp : function(e){
4891         if(this.editable !== false && !e.isSpecialKey()){
4892             this.lastKey = e.getKey();
4893             this.dqTask.delay(this.queryDelay);
4894         }
4895     },
4896
4897     // private
4898     validateBlur : function(){
4899         return !this.list || !this.list.isVisible();   
4900     },
4901
4902     // private
4903     initQuery : function(){
4904         this.doQuery(this.getRawValue());
4905     },
4906
4907     // private
4908     doForce : function(){
4909         if(this.el.dom.value.length > 0){
4910             this.el.dom.value =
4911                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
4912              
4913         }
4914     },
4915
4916     /**
4917      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
4918      * query allowing the query action to be canceled if needed.
4919      * @param {String} query The SQL query to execute
4920      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
4921      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
4922      * saved in the current store (defaults to false)
4923      */
4924     doQuery : function(q, forceAll){
4925         if(q === undefined || q === null){
4926             q = '';
4927         }
4928         var qe = {
4929             query: q,
4930             forceAll: forceAll,
4931             combo: this,
4932             cancel:false
4933         };
4934         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
4935             return false;
4936         }
4937         q = qe.query;
4938         forceAll = qe.forceAll;
4939         if(forceAll === true || (q.length >= this.minChars)){
4940             if(this.lastQuery != q || this.alwaysQuery){
4941                 this.lastQuery = q;
4942                 if(this.mode == 'local'){
4943                     this.selectedIndex = -1;
4944                     if(forceAll){
4945                         this.store.clearFilter();
4946                     }else{
4947                         this.store.filter(this.displayField, q);
4948                     }
4949                     this.onLoad();
4950                 }else{
4951                     this.store.baseParams[this.queryParam] = q;
4952                     this.store.load({
4953                         params: this.getParams(q)
4954                     });
4955                     this.expand();
4956                 }
4957             }else{
4958                 this.selectedIndex = -1;
4959                 this.onLoad();   
4960             }
4961         }
4962     },
4963
4964     // private
4965     getParams : function(q){
4966         var p = {};
4967         //p[this.queryParam] = q;
4968         if(this.pageSize){
4969             p.start = 0;
4970             p.limit = this.pageSize;
4971         }
4972         return p;
4973     },
4974
4975     /**
4976      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
4977      */
4978     collapse : function(){
4979         if(!this.isExpanded()){
4980             return;
4981         }
4982         this.list.hide();
4983         Roo.get(document).un('mousedown', this.collapseIf, this);
4984         Roo.get(document).un('mousewheel', this.collapseIf, this);
4985         if (!this.editable) {
4986             Roo.get(document).un('keydown', this.listKeyPress, this);
4987         }
4988         this.fireEvent('collapse', this);
4989     },
4990
4991     // private
4992     collapseIf : function(e){
4993         if(!e.within(this.el) && !e.within(this.el)){
4994             this.collapse();
4995         }
4996     },
4997
4998     /**
4999      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
5000      */
5001     expand : function(){
5002         Roo.log('expand');
5003         if(this.isExpanded() || !this.hasFocus){
5004             return;
5005         }
5006         this.list.alignTo(this.inputEl(), this.listAlign);
5007         this.list.show();
5008         Roo.get(document).on('mousedown', this.collapseIf, this);
5009         Roo.get(document).on('mousewheel', this.collapseIf, this);
5010         if (!this.editable) {
5011             Roo.get(document).on('keydown', this.listKeyPress, this);
5012         }
5013         
5014         this.fireEvent('expand', this);
5015     },
5016
5017     // private
5018     // Implements the default empty TriggerField.onTriggerClick function
5019     onTriggerClick : function()
5020     {
5021         Roo.log('trigger click');
5022         
5023         if(this.disabled){
5024             return;
5025         }
5026         if(this.isExpanded()){
5027             this.collapse();
5028             if (!this.blockFocus) {
5029                 this.inputEl().focus();
5030             }
5031             
5032         }else {
5033             this.hasFocus = true;
5034             if(this.triggerAction == 'all') {
5035                 this.doQuery(this.allQuery, true);
5036             } else {
5037                 this.doQuery(this.getRawValue());
5038             }
5039             if (!this.blockFocus) {
5040                 this.inputEl().focus();
5041             }
5042         }
5043     },
5044     listKeyPress : function(e)
5045     {
5046         //Roo.log('listkeypress');
5047         // scroll to first matching element based on key pres..
5048         if (e.isSpecialKey()) {
5049             return false;
5050         }
5051         var k = String.fromCharCode(e.getKey()).toUpperCase();
5052         //Roo.log(k);
5053         var match  = false;
5054         var csel = this.view.getSelectedNodes();
5055         var cselitem = false;
5056         if (csel.length) {
5057             var ix = this.view.indexOf(csel[0]);
5058             cselitem  = this.store.getAt(ix);
5059             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
5060                 cselitem = false;
5061             }
5062             
5063         }
5064         
5065         this.store.each(function(v) { 
5066             if (cselitem) {
5067                 // start at existing selection.
5068                 if (cselitem.id == v.id) {
5069                     cselitem = false;
5070                 }
5071                 return true;
5072             }
5073                 
5074             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
5075                 match = this.store.indexOf(v);
5076                 return false;
5077             }
5078             return true;
5079         }, this);
5080         
5081         if (match === false) {
5082             return true; // no more action?
5083         }
5084         // scroll to?
5085         this.view.select(match);
5086         var sn = Roo.get(this.view.getSelectedNodes()[0])
5087         //sn.scrollIntoView(sn.dom.parentNode, false);
5088     }
5089
5090     /** 
5091     * @cfg {Boolean} grow 
5092     * @hide 
5093     */
5094     /** 
5095     * @cfg {Number} growMin 
5096     * @hide 
5097     */
5098     /** 
5099     * @cfg {Number} growMax 
5100     * @hide 
5101     */
5102     /**
5103      * @hide
5104      * @method autoSize
5105      */
5106 });