roojs-bootstrap.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         if (typeof (tree.buttons) != 'undefined' && typeof(cn.getButtonContainer) == 'function') {
143             
144             for(var i =0;i < tree.buttons.length;i++) {
145                 nitems.push(cn.addxtype(Roo.apply({}, tree.buttons[i]), 'getButtonContainer'));
146             }
147             
148             
149         }
150         if (!tree.items || !tree.items.length) {
151             cn.items = nitems;
152             return cn;
153         }
154         var items = tree.items;
155         delete tree.items;
156         
157         //Roo.log(items.length);
158             // add the items..
159         for(var i =0;i < items.length;i++) {
160             nitems.push(cn.addxtype(Roo.apply({}, items[i])));
161         }
162         
163         cn.items = nitems;
164         
165         
166         return cn;
167     }
168     
169     
170     
171     
172 });
173
174  /*
175  * - LGPL
176  *
177  * page container.
178  * 
179  */ 
180 Roo.bootstrap.Body = function(config){
181     Roo.bootstrap.Body.superclass.constructor.call(this, config);
182     this.el = Roo.get(document.body);
183 };
184
185 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
186       
187         autoCreate : {
188         cls: 'container'
189     },
190     onRender : function(ct, position){
191         
192         
193         //this.el.addClass([this.fieldClass, this.cls]);
194         
195     }
196     
197     
198  
199    
200 });
201
202  /*
203  * - LGPL
204  *
205  * button group
206  * 
207  */
208
209
210 /**
211  * @class Roo.bootstrap.ButtonGroup
212  * @extends Roo.bootstrap.Component
213  * Bootstrap ButtonGroup class
214  * @cfg {String} size lg | sm | xs (default empty normal)
215  * @cfg {String} align vertical | justified  (default none)
216  * @cfg {String} direction up | down (default down)
217  * @cfg {Boolean} toolbar false | true
218  * @cfg {Boolean} btn true | false
219  * 
220  * 
221  * @constructor
222  * Create a new Input
223  * @param {Object} config The config object
224  */
225
226 Roo.bootstrap.ButtonGroup = function(config){
227     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
228 };
229
230 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
231     
232     size: '',
233     align: '',
234     direction: '',
235     toolbar: false,
236     btn: true,
237
238     getAutoCreate : function(){
239         var cfg = {
240             cls: 'btn-group',
241             html : null
242         }
243         
244         cfg.html = this.html || cfg.html;
245         
246         if (this.toolbar) {
247             cfg = {
248                 cls: 'btn-toolbar',
249                 html: null
250             }
251             
252             return cfg;
253         }
254         
255         if (['vertical','justified'].indexOf(this.align)!==-1) {
256             cfg.cls = 'btn-group-' + this.align;
257             
258             if (this.align == 'justified') {
259                 console.log(this.items);
260             }
261         }
262         
263         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
264             cfg.cls += ' btn-group-' + this.size;
265         }
266         
267         if (this.direction == 'up') {
268             cfg.cls += ' dropup' ;
269         }
270         
271         return cfg;
272     }
273    
274 });
275
276  /*
277  * - LGPL
278  *
279  * button
280  * 
281  */
282
283 /**
284  * @class Roo.bootstrap.Button
285  * @extends Roo.bootstrap.Component
286  * Bootstrap Button class
287  * @cfg {String} html The button content
288  * @cfg {String} weight default (or empty) | primary | success | info | warning | danger
289  * @cfg {String} size empty | lg | sm | xs
290  * @cfg {String} tag empty | a | input | submit
291  * @cfg {String} href empty or href
292  * @cfg {Boolean} disabled false | true
293  * @cfg {Boolean} isClose false | true
294  * @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
295  * @cfg {String} badge text for badge
296  * @cfg {String} theme default (or empty) | glow
297  * @cfg {Boolean} inverse false | true
298  * @cfg {Boolean} toggle false | true
299  * @cfg {String} ontext text for on toggle state
300  * @cfg {String} offtext text for off toggle state
301  * @cfg {Boolean} defaulton true | false
302  * 
303  * @constructor
304  * Create a new button
305  * @param {Object} config The config object
306  */
307
308
309 Roo.bootstrap.Button = function(config){
310     Roo.bootstrap.Button.superclass.constructor.call(this, config);
311     this.addEvents({
312         // raw events
313         /**
314          * @event click
315          * The raw click event for the entire grid.
316          * @param {Roo.EventObject} e
317          */
318         "click" : true
319     });
320 };
321
322 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
323     html: false,
324     active: false,
325     weight: '',
326     size: '',
327     tag: 'button',
328     href: '',
329     disabled: false,
330     isClose: false,
331     glyphicon: '',
332     badge: '',
333     theme: 'default',
334     inverse: false,
335     
336     toggle: false,
337     ontext: 'ON',
338     offtext: 'OFF',
339     defaulton: true,
340     
341     getAutoCreate : function(){
342         
343         var cfg = {
344             tag : 'button',
345             cls : 'roo-button',
346             html: 'hello'
347         };
348         
349         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
350             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
351             this.tag = 'button';
352         } else {
353             cfg.tag = this.tag;
354         }
355         cfg.html = this.html || cfg.html;
356         
357         if (this.toggle===true) {
358             cfg={
359                 tag: 'div',
360                 cls: 'slider-frame roo-button',
361                 cn: [
362                     {
363                         tag: 'span',
364                         'data-on-text':'ON',
365                         'data-off-text':'OFF',
366                         cls: 'slider-button',
367                         html: this.offtext
368                     }
369                 ]
370             };
371             
372             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
373                 cfg.cls += ' '+this.weight;
374             }
375             
376             return cfg;
377         }
378         
379         if (this.isClose) {
380             cfg.cls += ' close';
381             
382             cfg["aria-hidden"] = true;
383             
384             cfg.html = "&times;";
385             
386             return cfg;
387         }
388         
389          
390         if (this.theme==='default') {
391             cfg.cls = 'btn roo-button';
392             
393             if (this.parentType != 'Navbar') {
394                 this.weight = this.weight.length ?  this.weight : 'default';
395             }
396             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
397                 
398                 cfg.cls += ' btn-' + this.weight;
399             }
400         } else if (this.theme==='glow') {
401             
402             cfg.tag = 'a';
403             cfg.cls = 'btn-glow roo-button';
404             
405             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
406                 
407                 cfg.cls += ' ' + this.weight;
408             }
409         }
410    
411         
412         if (this.inverse) {
413             this.cls += ' inverse';
414         }
415         
416         
417         if (this.active) {
418             cfg.cls += ' active';
419         }
420         
421         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
422          
423         //gsRoo.log(this.parentType);
424         if (this.parentType === 'Navbar') {
425             cfg.tag = 'li';
426             
427             cfg.cls = '';
428             cfg.cn =  [{
429                 tag : 'a',
430                 cls : 'roo-button',
431                 html : this.html,
432                 href : this.href || '#'
433             }];
434             if (this.menu) {
435                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
436                 cfg.cls += ' dropdown';
437             }   
438             
439             delete cfg.html;
440             
441         } else if (this.menu) {
442             cfg.tag = 'a';
443             cfg.cls += ' dropdown test';
444         }
445         
446         
447         
448         if (this.disabled) {
449             cfg.disabled = 'disabled';
450         }
451         //????
452         if (this.items) {
453             Roo.log('changing to ul' );
454             cfg.tag = 'ul';
455             this.glyphicon = 'caret';
456         }
457         
458         if (this.glyphicon) {
459             cfg.html = ' ' + cfg.html;
460             
461             cfg.cn = [
462                 {
463                     tag: 'span',
464                     cls: 'glyphicon glyphicon-' + this.glyphicon
465                 }
466             ];
467         }
468         
469         if (this.badge) {
470             cfg.html += ' ';
471             
472             cfg.tag = 'a';
473             
474             cfg.cls='btn roo-button';
475             
476             cfg.href=this.href;
477             
478             cfg.cn = [
479                 cfg.html,
480                 {
481                     tag: 'span',
482                     cls: 'badge',
483                     html: this.badge
484                 }
485             ];
486             
487             cfg.html='';
488         }
489         
490         if (cfg.tag !== 'a' && this.href !== '') {
491             throw "Tag must be a to set href.";
492         } else if (this.href.length > 0) {
493             cfg.href = this.href;
494         }
495         
496         return cfg;
497     },
498     initEvents: function() {
499        // Roo.log('init events?');
500        // Roo.log(this.el.dom);
501        if (this.el.hasClass('roo-button')) {
502             this.el.on('click', this.onClick, this);
503        } else {
504             this.el.select('.roo-button').on('click', this.onClick, this);
505        }
506        
507        
508         
509     },
510     onClick : function(e)
511     {
512         Roo.log('button on click ');
513         e.preventDefault();
514         this.fireEvent('click', this, e);
515     }
516     
517     
518 });
519
520  /*
521  * - LGPL
522  *
523  * column
524  * 
525  */
526
527 /**
528  * @class Roo.bootstrap.Column
529  * @extends Roo.bootstrap.Component
530  * Bootstrap Column class
531  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
532  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
533  * @cfg {Number} md colspan out of 12 for computer-sized screens
534  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
535  * @cfg {String} html content of column.
536  * 
537  * @constructor
538  * Create a new Column
539  * @param {Object} config The config object
540  */
541
542 Roo.bootstrap.Column = function(config){
543     Roo.bootstrap.Column.superclass.constructor.call(this, config);
544 };
545
546 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
547     
548     xs: null,
549     sm: null,
550     md: null,
551     lg: null,
552     html: '',
553     offset: 0,
554     
555     getAutoCreate : function(){
556         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
557         
558         cfg = {
559             tag: 'div',
560             cls: 'column'
561         };
562         
563         var settings=this;
564         ['xs','sm','md','lg'].map(function(size){
565             if (settings[size]) {
566                 cfg.cls += ' col-' + size + '-' + settings[size];
567             }
568         });
569         if (this.html.length) {
570             cfg.html = this.html;
571         }
572         
573         return cfg;
574     }
575    
576 });
577
578  
579
580  /*
581  * - LGPL
582  *
583  * page container.
584  * 
585  */
586
587
588 /**
589  * @class Roo.bootstrap.Container
590  * @extends Roo.bootstrap.Component
591  * Bootstrap Container class
592  * @cfg {Boolean} jumbotron is it a jumbotron element
593  * @cfg {String} html content of element
594  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
595  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
596  * @cfg {String} header content of header (for panel)
597  * @cfg {String} footer content of footer (for panel)
598  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
599  *     
600  * @constructor
601  * Create a new Container
602  * @param {Object} config The config object
603  */
604
605 Roo.bootstrap.Container = function(config){
606     Roo.bootstrap.Container.superclass.constructor.call(this, config);
607 };
608
609 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
610     
611     jumbotron : false,
612     well: '',
613     panel : '',
614     header: '',
615     footer : '',
616     sticky: '',
617   
618      
619     getChildContainer : function() {
620         if (this.panel.length) {
621             return this.el.select('.panel-body',true).first();
622         }
623         
624         return this.el;
625     },
626     
627     
628     getAutoCreate : function(){
629         
630         var cfg = {
631             html : '',
632             cls : ''
633         };
634         if (this.jumbotron) {
635             cfg.cls = 'jumbotron';
636         }
637         if (this.cls) {
638             cfg.cls = this.cls + '';
639         }
640         
641         if (this.sticky.length) {
642             var bd = Roo.get(document.body);
643             if (!bd.hasClass('bootstrap-sticky')) {
644                 bd.addClass('bootstrap-sticky');
645                 Roo.select('html',true).setStyle('height', '100%');
646             }
647              
648             cfg.cls += 'bootstrap-sticky-' + this.sticky;
649         }
650         
651         
652         if (this.well.length) {
653             switch (this.well) {
654                 case 'lg':
655                 case 'sm':
656                     cfg.cls +=' well well-' +this.well;
657                     break;
658                 default:
659                     cfg.cls +=' well';
660                     break;
661             }
662         }
663         
664         var body = cfg;
665         
666         if (this.panel.length) {
667             cfg.cls += 'panel panel-' + this.panel;
668             cfg.cn = [];
669             if (this.header.length) {
670                 cfg.cn.push({
671                     
672                     cls : 'panel-heading',
673                     cn : [{
674                         tag: 'h3',
675                         cls : 'panel-title',
676                         html : this.header
677                     }]
678                     
679                 });
680             }
681             body = false;
682             cfg.cn.push({
683                 cls : 'panel-body',
684                 html : this.html
685             });
686             
687             
688             if (this.footer.length) {
689                 cfg.cn.push({
690                     cls : 'panel-footer',
691                     html : this.footer
692                     
693                 });
694             }
695             
696         }
697         if (body) {
698             body.html = this.html || cfg.html;
699         }
700         if (!cfg.cls.length) {
701             cfg.cls =  'container';
702         }
703         
704         return cfg;
705     }
706    
707 });
708
709  /*
710  * - LGPL
711  *
712  * image
713  * 
714  */
715
716
717 /**
718  * @class Roo.bootstrap.Img
719  * @extends Roo.bootstrap.Component
720  * Bootstrap Img class
721  * @cfg {Boolean} imgResponsive false | true
722  * @cfg {String} border rounded | circle | thumbnail
723  * @cfg {String} src image source
724  * @cfg {String} alt image alternative text
725  * 
726  * @constructor
727  * Create a new Input
728  * @param {Object} config The config object
729  */
730
731 Roo.bootstrap.Img = function(config){
732     Roo.bootstrap.Img.superclass.constructor.call(this, config);
733 };
734
735 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
736     
737     imgResponsive: true,
738     border: '',
739     src: '',
740
741     getAutoCreate : function(){
742         
743         cfg = {
744             tag: 'img',
745             cls: 'img-responsive',
746             html : null
747         }
748         
749         cfg.html = this.html || cfg.html;
750         
751         cfg.src = this.src || cfg.src;
752         
753         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
754             cfg.cls += ' img-' + this.border;
755         }
756         
757         if(this.alt){
758             cfg.alt = this.alt;
759         }
760         
761         return cfg;
762     }
763    
764 });
765
766  /*
767  * - LGPL
768  *
769  * header
770  * 
771  */
772
773 /**
774  * @class Roo.bootstrap.Header
775  * @extends Roo.bootstrap.Component
776  * Bootstrap Header class
777  * @cfg {String} html content of header
778  * @cfg {Number} level (1|2|3|4|5|6) default 1
779  * 
780  * @constructor
781  * Create a new Header
782  * @param {Object} config The config object
783  */
784
785
786 Roo.bootstrap.Header  = function(config){
787     Roo.bootstrap.Header.superclass.constructor.call(this, config);
788 };
789
790 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
791     
792     //href : false,
793     html : false,
794     level : 1,
795     
796     
797     
798     getAutoCreate : function(){
799         
800         var cfg = {
801             tag: 'h' + (1 *this.level),
802             html: this.html || 'fill in html'
803         } ;
804         
805         return cfg;
806     }
807    
808 });
809
810  
811
812  /*
813  * - LGPL
814  *
815  * menu
816  * 
817  */
818
819 /**
820  * @class Roo.bootstrap.Menu
821  * @extends Roo.bootstrap.Component
822  * Bootstrap Menu class - container for MenuItems
823  * @cfg {String} type type of menu
824  * 
825  * @constructor
826  * Create a new Menu
827  * @param {Object} config The config object
828  */
829
830
831 Roo.bootstrap.Menu = function(config){
832     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
833 };
834
835 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
836     
837    /// html : false,
838     //align : '',
839     triggerEl : false,
840     type: false,
841     
842     
843     getChildContainer : function() {
844         return this.el;  
845     },
846     
847     getAutoCreate : function(){
848          
849         //if (['right'].indexOf(this.align)!==-1) {
850         //    cfg.cn[1].cls += ' pull-right'
851         //}
852         var cfg = {
853             tag : 'ul',
854             cls : 'dropdown-menu' 
855             
856         }
857         
858         if (this.type==='submenu') {
859             cfg.cls='submenu active'
860         }
861         
862         return cfg;
863     },
864     initEvents : function() {
865        // Roo.log("ADD event");
866        // Roo.log(this.triggerEl.dom);
867         this.triggerEl.on('click', this.toggle, this);
868         this.triggerEl.addClass('dropdown-toggle');
869         
870     },
871     toggle  : function(e)
872     {
873         //Roo.log(e.getTarget());
874        // Roo.log(this.triggerEl.dom);
875         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
876             return;
877         }
878         var isActive = this.triggerEl.hasClass('open');
879         // if disabled.. ingore
880         this.clearMenus(e);
881         //if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
882          // if mobile we use a backdrop because click events don't delegate
883         // $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
884         // }
885  
886        //var relatedTarget = { relatedTarget: this }
887        //$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
888  
889        //if (e.isDefaultPrevented()) return;
890         
891        this.triggerEl[isActive ? 'removeClass' : 'addClass']('open');
892        
893        //  .trigger('shown.bs.dropdown', relatedTarget)
894  
895        this.triggerEl.focus();
896        Roo.log(e);
897        e.preventDefault(); 
898         
899         
900     },
901     clearMenus : function()
902     {
903         //$(backdrop).remove()
904         Roo.select('.dropdown-toggle',true).each(function(aa) {
905             if (!aa.hasClass('open')) {
906                 return;
907             }
908             // triger close...
909             aa.removeClass('open');
910           //var parent = getParent($(this))
911           //var relatedTarget = { relatedTarget: this }
912           
913            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
914           //if (e.isDefaultPrevented()) return
915            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
916         })
917     }
918     
919    
920 });
921
922  
923
924  /*
925  * - LGPL
926  *
927  * menu item
928  * 
929  */
930
931
932 /**
933  * @class Roo.bootstrap.MenuItem
934  * @extends Roo.bootstrap.Component
935  * Bootstrap MenuItem class
936  * @cfg {String} html the menu label
937  * @cfg {String} href the link
938  * 
939  * 
940  * @constructor
941  * Create a new MenuItem
942  * @param {Object} config The config object
943  */
944
945
946 Roo.bootstrap.MenuItem = function(config){
947     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
948 };
949
950 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
951     
952     href : false,
953     html : false,
954     
955     getAutoCreate : function(){
956         var cfg= {
957             tag: 'li',
958             cn: [
959                 {
960                     tag : 'a',
961                     href : '#',
962                     html : 'Link'
963                 }
964             ]
965         };
966         
967         cfg.cn[0].href = this.href || cfg.cn[0].href ;
968         cfg.cn[0].html = this.html || cfg.cn[0].html ;
969         return cfg;
970     }
971    
972 });
973
974  
975
976  /*
977  * - LGPL
978  *
979  * menu separator
980  * 
981  */
982
983
984 /**
985  * @class Roo.bootstrap.MenuSeparator
986  * @extends Roo.bootstrap.Component
987  * Bootstrap MenuSeparator class
988  * 
989  * @constructor
990  * Create a new MenuItem
991  * @param {Object} config The config object
992  */
993
994
995 Roo.bootstrap.MenuSeparator = function(config){
996     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
997 };
998
999 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
1000     
1001     getAutoCreate : function(){
1002         var cfg = {
1003             cls: 'divider',
1004             tag : 'li'
1005         };
1006         
1007         return cfg;
1008     }
1009    
1010 });
1011
1012  
1013
1014  
1015 /*
1016 <div class="modal fade">
1017   <div class="modal-dialog">
1018     <div class="modal-content">
1019       <div class="modal-header">
1020         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1021         <h4 class="modal-title">Modal title</h4>
1022       </div>
1023       <div class="modal-body">
1024         <p>One fine body&hellip;</p>
1025       </div>
1026       <div class="modal-footer">
1027         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1028         <button type="button" class="btn btn-primary">Save changes</button>
1029       </div>
1030     </div><!-- /.modal-content -->
1031   </div><!-- /.modal-dialog -->
1032 </div><!-- /.modal -->
1033 */
1034 /*
1035  * - LGPL
1036  *
1037  * page contgainer.
1038  * 
1039  */
1040
1041 /**
1042  * @class Roo.bootstrap.Modal
1043  * @extends Roo.bootstrap.Component
1044  * Bootstrap Modal class
1045  * @cfg {String} title Title of dialog
1046  * @cfg {Array} buttons Array of buttons
1047  * 
1048  * @constructor
1049  * Create a new Modal Dialog
1050  * @param {Object} config The config object
1051  */
1052
1053 Roo.bootstrap.Modal = function(config){
1054     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1055 };
1056
1057 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
1058     
1059     title : 'test dialog',
1060    
1061     buttons : false,
1062
1063     onRender : function(ct, position)
1064     {
1065         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1066         if(!this.el){
1067             var cfg = Roo.apply({},  this.getAutoCreate());
1068             cfg.id = Roo.id();
1069             //if(!cfg.name){
1070             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1071             //}
1072             //if (!cfg.name.length) {
1073             //    delete cfg.name;
1074            // }
1075             if (this.cls) {
1076                 cfg.cls += ' ' + this.cls;
1077             }
1078             if (this.style) {
1079                 cfg.style = this.style;
1080             }
1081             this.el = Roo.get(document.body).createChild(cfg, position);
1082         }
1083         //var type = this.el.dom.type;
1084          
1085         if(this.tabIndex !== undefined){
1086             this.el.dom.setAttribute('tabIndex', this.tabIndex);
1087         }
1088         this.initEvents();
1089         //this.el.addClass([this.fieldClass, this.cls]);
1090         
1091     },
1092     getAutoCreate : function(){
1093         
1094         return {
1095             cls: "modal fade",
1096             cn : [
1097                 {
1098                     cls: "modal-dialog",
1099                     cn : [
1100                         {
1101                             cls : "modal-content",
1102                             cn : [
1103                                 {
1104                                     cls : 'modal-header',
1105                                     cn : [
1106                                         {
1107                                             tag: 'button',
1108                                             cls : 'close',
1109                                             html : '&times'
1110                                         },
1111                                         {
1112                                             tag: 'h4',
1113                                             cls : 'modal-title',
1114                                             html : this.title
1115                                         }
1116                                     
1117                                     ]
1118                                 },
1119                                 {
1120                                     cls : 'modal-body'
1121                                  
1122                                 },
1123                                  {
1124                                     cls : 'modal-footer'
1125                                     /*
1126                                     cn : [
1127                                         {
1128                                             tag: 'button',
1129                                             cls : 'btn btn-default',
1130                                             html : 'Close'
1131                                         },
1132                                         {
1133                                             tag: 'button',
1134                                             cls : 'btn btn-primary',
1135                                             html : 'Save'
1136                                         }
1137                                     
1138                                     ]
1139                                     */
1140                                 }
1141                                 
1142                                 
1143                             ]
1144                             
1145                         }
1146                     ]
1147                         
1148                 }
1149             ]
1150             
1151             
1152         };
1153           
1154     },
1155     getChildContainer : function() {
1156          
1157          return this.el.select('.modal-body',true).first();
1158         
1159     },
1160     getButtonContainer : function() {
1161          return this.el.select('.modal-footer',true).first();
1162         
1163     },
1164     initEvents : function()
1165     {
1166         this.el.select('.modal-header .close').on('click', this.hide, this);
1167     },
1168     show : function() {
1169         this.el.addClass('on');
1170         this.el.removeClass('fade');
1171         this.el.setStyle('display', 'block');
1172     },
1173     hide : function() {
1174         this.el.removeClass('on');
1175         this.el.addClass('fade');
1176         this.el.setStyle('display', 'none');
1177     }
1178 });
1179
1180  /*
1181  * - LGPL
1182  *
1183  * navbar
1184  * 
1185  */
1186
1187 /**
1188  * @class Roo.bootstrap.Navbar
1189  * @extends Roo.bootstrap.Component
1190  * Bootstrap Navbar class
1191  * @cfg {Boolean} sidebar has side bar
1192  * @cfg {Boolean} bar is a bar?
1193  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
1194  * @cfg {String} brand what is brand
1195  * @cfg {Boolean} inverse is inverted color
1196  * @cfg {String} type (nav | pills | tabs)
1197  * @cfg {Boolean} arrangement stacked | justified
1198  * @cfg {String} align (left | right) alignment
1199  *
1200  * 
1201  * @constructor
1202  * Create a new Navbar
1203  * @param {Object} config The config object
1204  */
1205
1206
1207 Roo.bootstrap.Navbar = function(config){
1208     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
1209 };
1210
1211 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
1212     
1213     sidebar: false,
1214     
1215     bar: false,
1216     brand: '',
1217     inverse: false,
1218     position: '',
1219     align : false,
1220     type: 'nav',
1221     arrangement: '',
1222     
1223     getAutoCreate : function(){
1224         var cfg = {
1225             cls : 'navbar'
1226         };
1227         
1228         if (this.sidebar === true) {
1229             cfg = {
1230                 tag: 'div',
1231                 cls: 'sidebar-nav'
1232             };
1233             return cfg;
1234         }
1235         
1236         if (this.bar === true) {
1237             cfg = {
1238                 tag: 'nav',
1239                 cls: 'navbar',
1240                 role: 'navigation',
1241                 cn: [
1242                     {
1243                         tag: 'div',
1244                         cls: 'navbar-header',
1245                         cn: [
1246                             {
1247                             tag: 'button',
1248                             type: 'button',
1249                             cls: 'navbar-toggle',
1250                             'data-toggle': 'collapse',
1251                             cn: [
1252                                 {
1253                                     tag: 'span',
1254                                     cls: 'sr-only',
1255                                     html: 'Toggle navigation'
1256                                 },
1257                                 {
1258                                     tag: 'span',
1259                                     cls: 'icon-bar'
1260                                 },
1261                                 {
1262                                     tag: 'span',
1263                                     cls: 'icon-bar'
1264                                 },
1265                                 {
1266                                     tag: 'span',
1267                                     cls: 'icon-bar'
1268                                 }
1269                             ]
1270                             }
1271                         ]
1272                     },
1273                     {
1274                     tag: 'div',
1275                     cls: 'collapse navbar-collapse'
1276                     }
1277                 ]
1278             };
1279             
1280             cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
1281             
1282             if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
1283             cfg.cls += ' navbar-' + this.position;
1284             cfg.tag = this.position  == 'fixed-bottom' ? 'footer' : 'header';
1285             }
1286             
1287             if (this.brand !== '') {
1288                 cfg.cn[0].cn.push({
1289                     tag: 'a',
1290                     href: '#',
1291                     cls: 'navbar-brand',
1292                     cn: [
1293                     this.brand
1294                     ]
1295                 });
1296             }
1297             
1298             return cfg;
1299         
1300         } else if (this.bar === false) {
1301             
1302         } else {
1303             Roo.log('Property \'bar\' in of Navbar must be either true or false')
1304         }
1305         
1306         cfg.cn = [
1307             {
1308                 cls: 'nav',
1309                 tag : 'ul'
1310             }
1311         ];
1312         
1313         if (['tabs','pills'].indexOf(this.type)!==-1) {
1314             cfg.cn[0].cls += ' nav-' + this.type
1315         } else {
1316             if (this.type!=='nav') {
1317             Roo.log('nav type must be nav/tabs/pills')
1318             }
1319             cfg.cn[0].cls += ' navbar-nav'
1320         }
1321         
1322         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
1323             cfg.cn[0].cls += ' nav-' + this.arrangement;
1324         }
1325         
1326         if (this.align === 'right') {
1327             cfg.cn[0].cls += ' navbar-right';
1328         }
1329         if (this.inverse) {
1330             cfg.cls += ' navbar-inverse';
1331             
1332         }
1333         
1334         
1335         return cfg;
1336     },
1337     
1338     getChildContainer : function() {
1339         if (this.bar === true) {
1340             return this.el.select('.collapse',true).first();
1341         }
1342         console.log(this);
1343         return this.el;
1344     }
1345    
1346 });
1347
1348  
1349
1350  /*
1351  * - LGPL
1352  *
1353  * nav group
1354  * 
1355  */
1356
1357 /**
1358  * @class Roo.bootstrap.NavGroup
1359  * @extends Roo.bootstrap.Component
1360  * Bootstrap NavGroup class
1361  * @cfg {String} align left | right
1362  * @cfg {Boolean} inverse false | true
1363  * 
1364  * @constructor
1365  * Create a new nav group
1366  * @param {Object} config The config object
1367  */
1368
1369 Roo.bootstrap.NavGroup = function(config){
1370     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
1371 };
1372
1373 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
1374     
1375     align: '',
1376     inverse: false,
1377     form: false,
1378     
1379     getAutoCreate : function(){
1380         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
1381         
1382         cfg = {
1383             tag : 'ul',
1384             cls: 'nav navbar-nav' 
1385         }
1386         
1387         if (this.parent().sidebar === true) {
1388             cfg = {
1389                 tag: 'ul',
1390                 cls: 'dashboard-menu'
1391             }
1392             
1393             return cfg;
1394         }
1395         
1396         if (this.form === true) {
1397             cfg = {
1398                 tag: 'form',
1399                 cls: 'navbar-form'
1400             }
1401             
1402             if (this.align === 'right') {
1403                 cfg.cls += ' navbar-right';
1404             } else {
1405                 cfg.cls += ' navbar-left';
1406             }
1407         }
1408         
1409         
1410         if (this.align === 'right') {
1411             cfg.cls += ' navbar-right';
1412         }
1413         
1414         if (this.inverse) {
1415             cfg.cls += ' navbar-inverse';
1416             
1417         }
1418         
1419         
1420         return cfg;
1421     }
1422    
1423 });
1424
1425  
1426
1427  /*
1428  * - LGPL
1429  *
1430  * row
1431  * 
1432  */
1433 /**
1434  * @class Roo.bootstrap.Navbar.Button
1435  * @extends Roo.bootstrap.Component
1436  * Bootstrap Navbar.Button class
1437  * @cfg {String} href  link to
1438  * @cfg {String} html content of button
1439     
1440  * @constructor
1441  * Create a new Navbar Button
1442  * @param {Object} config The config object
1443  */
1444
1445
1446 Roo.bootstrap.Navbar.Button = function(config){
1447     Roo.bootstrap.Navbar.Button.superclass.constructor.call(this, config);
1448 };
1449
1450 Roo.extend(Roo.bootstrap.Navbar.Button, Roo.bootstrap.Component,  {
1451     
1452     href : false,
1453     html : false,
1454     
1455     autoCreate : {
1456         cls: 'btn',
1457         tag : 'button',
1458         html: 'hello'
1459     },
1460     
1461     getAutoCreate : function(){
1462         
1463         var cfg = {
1464             cls: 'btn',
1465             tag : 'button',
1466             html: 'hello',
1467             cn : []
1468             
1469         } ;
1470         cfg.cn.push({
1471             html : this.html || ''
1472             //href : this.
1473              //       )
1474         });
1475         cfg.cn.push({
1476             tag: 'span',
1477             cls : 'carat'
1478         });
1479         
1480         return cfg;
1481     }
1482    
1483 });
1484
1485  
1486
1487  /*
1488  * - LGPL
1489  *
1490  * row
1491  * 
1492  */
1493
1494 /**
1495  * @class Roo.bootstrap.Navbar.Item
1496  * @extends Roo.bootstrap.Component
1497  * Bootstrap Navbar.Button class
1498  * @cfg {String} href  link to
1499  * @cfg {String} html content of button
1500  * @cfg {String} badge text inside badge
1501  * @cfg {String} glyphicon name of glyphicon
1502   
1503  * @constructor
1504  * Create a new Navbar Button
1505  * @param {Object} config The config object
1506  */
1507 Roo.bootstrap.Navbar.Item = function(config){
1508     Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
1509 };
1510
1511 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component,  {
1512     
1513     href: false,
1514     html: '',
1515     badge: '',
1516     icon: false,
1517     glyphicon: false,
1518     
1519     getAutoCreate : function(){
1520         
1521         var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
1522         
1523         if (this.parent().parent().sidebar === true) {
1524             cfg = {
1525                 tag: 'li',
1526                 cls: '',
1527                 cn: [
1528                     {
1529                         tag: 'p',
1530                         cls: ''
1531                     }
1532                 ]
1533             }
1534             
1535             if (this.html) {
1536                 cfg.cn[0].html = this.html;
1537             }
1538             
1539             if (this.active) {
1540                 this.cls += ' active';
1541             }
1542             
1543             if (this.menu) {
1544                 cfg.cn[0].cls += ' dropdown-toggle';
1545                 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
1546             }
1547             
1548             if (this.href) {
1549                 cfg.cn[0].tag = 'a',
1550                 cfg.cn[0].href = this.href;
1551             }
1552             
1553             if (this.glyphicon) {
1554                 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
1555             }
1556             
1557             return cfg;
1558         }
1559         
1560         cfg = {
1561             tag: 'li'
1562         }
1563         cfg.cn = [
1564             {
1565                 tag: 'p',
1566                 html: 'Text'
1567             }
1568         ];
1569         
1570         if (this.glyphicon) {
1571             if(cfg.html){cfg.html = ' ' + this.html};
1572             cfg.cn=[
1573                 {
1574                     tag: 'span',
1575                     cls: 'glyphicon glyphicon-' + this.glyphicon
1576                 }
1577             ];
1578         }
1579         
1580         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1581         if (this.menu) {
1582             cfg.cn[0].tag='a';
1583             cfg.cn[0].href='#';
1584             cfg.cn[0].html += " <span class='caret'></span>";
1585         //}else if (!this.href) {
1586         //    cfg.cn[0].tag='p';
1587         //    cfg.cn[0].cls='navbar-text';
1588         } else {
1589             cfg.cn[0].tag='a';
1590             cfg.cn[0].href=this.href||'#';
1591             cfg.cn[0].html=this.html;
1592         }
1593         
1594         if (this.badge !== '') {
1595             
1596             cfg.cn[0].cn=[
1597                 cfg.cn[0].html + ' ',
1598                 {
1599                     tag: 'span',
1600                     cls: 'badge',
1601                     html: this.badge
1602                 }
1603             ];
1604             cfg.cn[0].html=''
1605         }
1606          
1607         
1608         return cfg;
1609     },
1610     initEvents: function() {
1611        // Roo.log('init events?');
1612        // Roo.log(this.el.dom);
1613         this.el.select('a',true).on('click',
1614                 function(e) {
1615                     this.fireEvent('click', this);
1616                 },
1617                 this
1618         );
1619     }
1620    
1621 });
1622  
1623
1624  /*
1625  * - LGPL
1626  *
1627  * row
1628  * 
1629  */
1630
1631 /**
1632  * @class Roo.bootstrap.Row
1633  * @extends Roo.bootstrap.Component
1634  * Bootstrap Row class (contains columns...)
1635  * 
1636  * @constructor
1637  * Create a new Row
1638  * @param {Object} config The config object
1639  */
1640
1641 Roo.bootstrap.Row = function(config){
1642     Roo.bootstrap.Row.superclass.constructor.call(this, config);
1643 };
1644
1645 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
1646     
1647     autoCreate: {
1648         cls: 'row clearfix'
1649     }
1650     
1651     
1652 });
1653
1654  
1655
1656  /*
1657  * - LGPL
1658  *
1659  * element
1660  * 
1661  */
1662
1663 /**
1664  * @class Roo.bootstrap.Element
1665  * @extends Roo.bootstrap.Component
1666  * Bootstrap Element class
1667  * @cfg {String} html contents of the element
1668  * @cfg {String} tag tag of the element
1669  * @cfg {String} cls class of the element
1670  * 
1671  * @constructor
1672  * Create a new Element
1673  * @param {Object} config The config object
1674  */
1675
1676 Roo.bootstrap.Element = function(config){
1677     Roo.bootstrap.Element.superclass.constructor.call(this, config);
1678 };
1679
1680 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
1681     
1682     tag: 'div',
1683     cls: '',
1684     html: '',
1685     
1686     
1687     
1688     getAutoCreate : function(){
1689         var cfg = Roo.apply({}, Roo.bootstrap.Element.superclass.getAutoCreate.call(this));
1690         
1691         cfg = {
1692             tag: this.tag,
1693             cls: '',
1694             html: this.html
1695         }
1696         
1697         return cfg;
1698     }
1699    
1700 });
1701
1702  
1703
1704  /*
1705  * - LGPL
1706  *
1707  * pagination
1708  * 
1709  */
1710
1711 /**
1712  * @class Roo.bootstrap.Pagination
1713  * @extends Roo.bootstrap.Component
1714  * Bootstrap Pagination class
1715  * @cfg {String} size xs | sm | md | lg
1716  * @cfg {Boolean} inverse false | true
1717  * @cfg {Number} from pagination starting number
1718  * @cfg {Number} to pagination ending number
1719  * @cfg {String} align empty or left | right
1720  * @cfg {Number} active active page number
1721  * 
1722  * @constructor
1723  * Create a new Pagination
1724  * @param {Object} config The config object
1725  */
1726
1727 Roo.bootstrap.Pagination = function(config){
1728     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
1729 };
1730
1731 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
1732     
1733     cls: false,
1734     size: false,
1735     inverse: false,
1736     from: 1,
1737     to: 4,
1738     align: false,
1739     active: 1,
1740     
1741     getAutoCreate : function(){
1742         cfg = {
1743             tag: 'ul',
1744                 cls: 'pagination',
1745                 cn: []
1746         };
1747         if (this.inverse) {
1748             cfg.cls += ' inverse';
1749         }
1750         if (this.html) {
1751             cfg.html=this.html;
1752         }
1753         if (this.cls) {
1754             cfg.cls=this.cls;
1755         }
1756         cfg.cn[0]={
1757             tag: 'li',
1758             cn: [
1759                 {
1760                     tag: 'a',
1761                     href:'#',
1762                     html: '&laquo;'
1763                 }
1764             ]
1765         };
1766         var from=this.from>0?this.from:1;
1767         var to=this.to-from<=10?this.to:from+10;
1768         var active=this.active>=from&&this.active<=to?this.active:null;
1769         for (var i=from;i<=to;i++) {
1770             cfg.cn.push(
1771                 {
1772                     tag: 'li',
1773                     cls: active===i?'active':'',
1774                     cn: [
1775                         {
1776                             tag: 'a',
1777                             href: '#',
1778                             html: i
1779                         }
1780                     ]
1781                 }
1782             );
1783         }
1784         
1785         cfg.cn.push(
1786             {
1787                 tag: 'li',
1788                 cn: [
1789                     {
1790                        tag: 'a',
1791                        href: '#',
1792                        html: '&raquo;'
1793                     }
1794                 ]
1795             }
1796         );
1797         
1798         return cfg;
1799     }
1800    
1801 });
1802
1803  
1804
1805  /*
1806  * - LGPL
1807  *
1808  * slider
1809  * 
1810  */
1811
1812
1813 /**
1814  * @class Roo.bootstrap.Slider
1815  * @extends Roo.bootstrap.Component
1816  * Bootstrap Slider class
1817  *    
1818  * @constructor
1819  * Create a new Slider
1820  * @param {Object} config The config object
1821  */
1822
1823 Roo.bootstrap.Slider = function(config){
1824     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
1825 };
1826
1827 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
1828     
1829     getAutoCreate : function(){
1830         
1831         var cfg = {
1832             tag: 'div',
1833             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
1834             cn: [
1835                 {
1836                     tag: 'a',
1837                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
1838                 }
1839             ]
1840         }
1841         
1842         return cfg;
1843     }
1844    
1845 });
1846
1847  /*
1848  * - LGPL
1849  *
1850  * table
1851  * 
1852  */
1853
1854 /**
1855  * @class Roo.bootstrap.Table
1856  * @extends Roo.bootstrap.Component
1857  * Bootstrap Table class
1858  * 
1859  * @constructor
1860  * Create a new Table
1861  * @param {Object} config The config object
1862  */
1863
1864 Roo.bootstrap.Table = function(config){
1865     Roo.bootstrap.Table.superclass.constructor.call(this, config);
1866 };
1867
1868 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
1869     
1870     html: false,
1871     cls: false,
1872     
1873     getAutoCreate : function(){
1874         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
1875         
1876         cfg = {
1877             tag: 'table',
1878             cn: [
1879                 {
1880                     tag: 'tbody'
1881                 }
1882             ]
1883         }
1884         if (this.html) {
1885             cfg.html=this.html
1886         }
1887         if (this.cls) {
1888             cfg.cls=this.cls
1889         }
1890         
1891         return cfg;
1892     }
1893    
1894 });
1895
1896  
1897
1898  /*
1899  * - LGPL
1900  *
1901  * table cell
1902  * 
1903  */
1904
1905 /**
1906  * @class Roo.bootstrap.TableCell
1907  * @extends Roo.bootstrap.Component
1908  * Bootstrap TableCell class
1909  * 
1910  * @constructor
1911  * Create a new TableCell
1912  * @param {Object} config The config object
1913  */
1914
1915 Roo.bootstrap.TableCell = function(config){
1916     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
1917 };
1918
1919 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
1920     
1921     getAutoCreate : function(){
1922         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
1923         
1924         cfg = {
1925             tag: 'td'
1926         }
1927         if (this.html) {
1928             cfg.html=this.html
1929         }
1930         if (this.cls) {
1931             cfg.cls=this.cls
1932         }
1933         
1934         return cfg;
1935     }
1936    
1937 });
1938
1939  
1940
1941  /*
1942  * - LGPL
1943  *
1944  * table row
1945  * 
1946  */
1947
1948 /**
1949  * @class Roo.bootstrap.TableRow
1950  * @extends Roo.bootstrap.Component
1951  * Bootstrap TableRow class
1952  * 
1953  * @constructor
1954  * Create a new TableRow
1955  * @param {Object} config The config object
1956  */
1957
1958 Roo.bootstrap.TableRow = function(config){
1959     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
1960 };
1961
1962 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
1963     
1964     getAutoCreate : function(){
1965         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
1966         
1967         cfg = {
1968             tag: 'tr'
1969         }
1970         
1971         return cfg;
1972     }
1973    
1974 });
1975
1976  
1977
1978  /*
1979  * - LGPL
1980  *
1981  * form
1982  * 
1983  */
1984
1985 /**
1986  * @class Roo.bootstrap.Form
1987  * @extends Roo.bootstrap.Component
1988  * Bootstrap Form class
1989  * @cfg {String} method  GET | POST (default POST)
1990  * @cfg {String} labelAlign top | left (default top)
1991  * 
1992  * @constructor
1993  * Create a new Form
1994  * @param {Object} config The config object
1995  */
1996
1997
1998 Roo.bootstrap.Form = function(config){
1999     Roo.bootstrap.Form.superclass.constructor.call(this, config);
2000     this.addEvents({
2001         /**
2002          * @event clientvalidation
2003          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
2004          * @param {Form} this
2005          * @param {Boolean} valid true if the form has passed client-side validation
2006          */
2007         clientvalidation: true,
2008         /**
2009          * @event beforeaction
2010          * Fires before any action is performed. Return false to cancel the action.
2011          * @param {Form} this
2012          * @param {Action} action The action to be performed
2013          */
2014         beforeaction: true,
2015         /**
2016          * @event actionfailed
2017          * Fires when an action fails.
2018          * @param {Form} this
2019          * @param {Action} action The action that failed
2020          */
2021         actionfailed : true,
2022         /**
2023          * @event actioncomplete
2024          * Fires when an action is completed.
2025          * @param {Form} this
2026          * @param {Action} action The action that completed
2027          */
2028         actioncomplete : true
2029     });
2030     
2031 };
2032
2033 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
2034       
2035      /**
2036      * @cfg {String} method
2037      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
2038      */
2039     method : 'POST',
2040     /**
2041      * @cfg {String} url
2042      * The URL to use for form actions if one isn't supplied in the action options.
2043      */
2044     /**
2045      * @cfg {Boolean} fileUpload
2046      * Set to true if this form is a file upload.
2047      */
2048      
2049     /**
2050      * @cfg {Object} baseParams
2051      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
2052      */
2053       
2054     /**
2055      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
2056      */
2057     timeout: 30,
2058
2059     // private
2060     activeAction : null,
2061  
2062     /**
2063      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2064      * element by passing it or its id or mask the form itself by passing in true.
2065      * @type Mixed
2066      */
2067     waitMsgTarget : false,
2068     
2069      
2070     
2071     /**
2072      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
2073      * element by passing it or its id or mask the form itself by passing in true.
2074      * @type Mixed
2075      */
2076     
2077     getAutoCreate : function(){
2078         
2079         var cfg = {
2080             tag: 'form',
2081             method : this.method || 'POST',
2082             id : this.id || Roo.id(),
2083             cls : ''
2084         }
2085         
2086         if (this.labelAlign == 'left' ) {
2087             cfg.cls += ' form-horizontal';
2088         }
2089         return cfg;
2090     },
2091     initEvents : function()
2092     {
2093         this.el.on('submit', this.onSubmit, this);
2094         
2095         
2096     },
2097     // private
2098     onSubmit : function(e){
2099         e.stopEvent();
2100     },
2101     
2102      /**
2103      * Returns true if client-side validation on the form is successful.
2104      * @return Boolean
2105      */
2106     isValid : function(){
2107         var items = this.getItems();
2108         var valid = true;
2109         items.each(function(f){
2110            if(!f.validate()){
2111                valid = false;
2112                
2113            }
2114         });
2115         return valid;
2116     },
2117     /**
2118      * Returns true if any fields in this form have changed since their original load.
2119      * @return Boolean
2120      */
2121     isDirty : function(){
2122         var dirty = false;
2123         var items = this.getItems();
2124         items.each(function(f){
2125            if(f.isDirty()){
2126                dirty = true;
2127                return false;
2128            }
2129            return true;
2130         });
2131         return dirty;
2132     },
2133      /**
2134      * Performs a predefined action (submit or load) or custom actions you define on this form.
2135      * @param {String} actionName The name of the action type
2136      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
2137      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
2138      * accept other config options):
2139      * <pre>
2140 Property          Type             Description
2141 ----------------  ---------------  ----------------------------------------------------------------------------------
2142 url               String           The url for the action (defaults to the form's url)
2143 method            String           The form method to use (defaults to the form's method, or POST if not defined)
2144 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
2145 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
2146                                    validate the form on the client (defaults to false)
2147      * </pre>
2148      * @return {BasicForm} this
2149      */
2150     doAction : function(action, options){
2151         if(typeof action == 'string'){
2152             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
2153         }
2154         if(this.fireEvent('beforeaction', this, action) !== false){
2155             this.beforeAction(action);
2156             action.run.defer(100, action);
2157         }
2158         return this;
2159     },
2160     
2161     // private
2162     beforeAction : function(action){
2163         var o = action.options;
2164         
2165         // not really supported yet.. ??
2166         
2167         //if(this.waitMsgTarget === true){
2168             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
2169         //}else if(this.waitMsgTarget){
2170         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
2171         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
2172         //}else {
2173         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
2174        // }
2175          
2176     },
2177
2178     // private
2179     afterAction : function(action, success){
2180         this.activeAction = null;
2181         var o = action.options;
2182         
2183         //if(this.waitMsgTarget === true){
2184             this.el.unmask();
2185         //}else if(this.waitMsgTarget){
2186         //    this.waitMsgTarget.unmask();
2187         //}else{
2188         //    Roo.MessageBox.updateProgress(1);
2189         //    Roo.MessageBox.hide();
2190        // }
2191         // 
2192         if(success){
2193             if(o.reset){
2194                 this.reset();
2195             }
2196             Roo.callback(o.success, o.scope, [this, action]);
2197             this.fireEvent('actioncomplete', this, action);
2198             
2199         }else{
2200             
2201             // failure condition..
2202             // we have a scenario where updates need confirming.
2203             // eg. if a locking scenario exists..
2204             // we look for { errors : { needs_confirm : true }} in the response.
2205             if (
2206                 (typeof(action.result) != 'undefined')  &&
2207                 (typeof(action.result.errors) != 'undefined')  &&
2208                 (typeof(action.result.errors.needs_confirm) != 'undefined')
2209            ){
2210                 var _t = this;
2211                 Roo.log("not supported yet");
2212                  /*
2213                 
2214                 Roo.MessageBox.confirm(
2215                     "Change requires confirmation",
2216                     action.result.errorMsg,
2217                     function(r) {
2218                         if (r != 'yes') {
2219                             return;
2220                         }
2221                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
2222                     }
2223                     
2224                 );
2225                 */
2226                 
2227                 
2228                 return;
2229             }
2230             
2231             Roo.callback(o.failure, o.scope, [this, action]);
2232             // show an error message if no failed handler is set..
2233             if (!this.hasListener('actionfailed')) {
2234                 Roo.log("need to add dialog support");
2235                 /*
2236                 Roo.MessageBox.alert("Error",
2237                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
2238                         action.result.errorMsg :
2239                         "Saving Failed, please check your entries or try again"
2240                 );
2241                 */
2242             }
2243             
2244             this.fireEvent('actionfailed', this, action);
2245         }
2246         
2247     },
2248     /**
2249      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
2250      * @param {String} id The value to search for
2251      * @return Field
2252      */
2253     findField : function(id){
2254         var items = this.getItems();
2255         var field = items.get(id);
2256         if(!field){
2257              items.each(function(f){
2258                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
2259                     field = f;
2260                     return false;
2261                 }
2262                 return true;
2263             });
2264         }
2265         return field || null;
2266     },
2267      /**
2268      * Mark fields in this form invalid in bulk.
2269      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
2270      * @return {BasicForm} this
2271      */
2272     markInvalid : function(errors){
2273         if(errors instanceof Array){
2274             for(var i = 0, len = errors.length; i < len; i++){
2275                 var fieldError = errors[i];
2276                 var f = this.findField(fieldError.id);
2277                 if(f){
2278                     f.markInvalid(fieldError.msg);
2279                 }
2280             }
2281         }else{
2282             var field, id;
2283             for(id in errors){
2284                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
2285                     field.markInvalid(errors[id]);
2286                 }
2287             }
2288         }
2289         //Roo.each(this.childForms || [], function (f) {
2290         //    f.markInvalid(errors);
2291         //});
2292         
2293         return this;
2294     },
2295
2296     /**
2297      * Set values for fields in this form in bulk.
2298      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
2299      * @return {BasicForm} this
2300      */
2301     setValues : function(values){
2302         if(values instanceof Array){ // array of objects
2303             for(var i = 0, len = values.length; i < len; i++){
2304                 var v = values[i];
2305                 var f = this.findField(v.id);
2306                 if(f){
2307                     f.setValue(v.value);
2308                     if(this.trackResetOnLoad){
2309                         f.originalValue = f.getValue();
2310                     }
2311                 }
2312             }
2313         }else{ // object hash
2314             var field, id;
2315             for(id in values){
2316                 if(typeof values[id] != 'function' && (field = this.findField(id))){
2317                     
2318                     if (field.setFromData && 
2319                         field.valueField && 
2320                         field.displayField &&
2321                         // combos' with local stores can 
2322                         // be queried via setValue()
2323                         // to set their value..
2324                         (field.store && !field.store.isLocal)
2325                         ) {
2326                         // it's a combo
2327                         var sd = { };
2328                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
2329                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
2330                         field.setFromData(sd);
2331                         
2332                     } else {
2333                         field.setValue(values[id]);
2334                     }
2335                     
2336                     
2337                     if(this.trackResetOnLoad){
2338                         field.originalValue = field.getValue();
2339                     }
2340                 }
2341             }
2342         }
2343          
2344         //Roo.each(this.childForms || [], function (f) {
2345         //    f.setValues(values);
2346         //});
2347                 
2348         return this;
2349     },
2350
2351     /**
2352      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
2353      * they are returned as an array.
2354      * @param {Boolean} asString
2355      * @return {Object}
2356      */
2357     getValues : function(asString){
2358         //if (this.childForms) {
2359             // copy values from the child forms
2360         //    Roo.each(this.childForms, function (f) {
2361         //        this.setValues(f.getValues());
2362         //    }, this);
2363         //}
2364         
2365         
2366         
2367         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
2368         if(asString === true){
2369             return fs;
2370         }
2371         return Roo.urlDecode(fs);
2372     },
2373     
2374     /**
2375      * Returns the fields in this form as an object with key/value pairs. 
2376      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
2377      * @return {Object}
2378      */
2379     getFieldValues : function(with_hidden)
2380     {
2381         var items = this.getItems();
2382         var ret = {};
2383         items.each(function(f){
2384             if (!f.getName()) {
2385                 return;
2386             }
2387             var v = f.getValue();
2388             if (f.inputType =='radio') {
2389                 if (typeof(ret[f.getName()]) == 'undefined') {
2390                     ret[f.getName()] = ''; // empty..
2391                 }
2392                 
2393                 if (!f.el.dom.checked) {
2394                     return;
2395                     
2396                 }
2397                 v = f.el.dom.value;
2398                 
2399             }
2400             
2401             // not sure if this supported any more..
2402             if ((typeof(v) == 'object') && f.getRawValue) {
2403                 v = f.getRawValue() ; // dates..
2404             }
2405             // combo boxes where name != hiddenName...
2406             if (f.name != f.getName()) {
2407                 ret[f.name] = f.getRawValue();
2408             }
2409             ret[f.getName()] = v;
2410         });
2411         
2412         return ret;
2413     },
2414
2415     /**
2416      * Clears all invalid messages in this form.
2417      * @return {BasicForm} this
2418      */
2419     clearInvalid : function(){
2420         var items = this.getItems();
2421         
2422         items.each(function(f){
2423            f.clearInvalid();
2424         });
2425         
2426         
2427         
2428         return this;
2429     },
2430
2431     /**
2432      * Resets this form.
2433      * @return {BasicForm} this
2434      */
2435     reset : function(){
2436         var items = this.getItems();
2437         items.each(function(f){
2438             f.reset();
2439         });
2440         
2441         Roo.each(this.childForms || [], function (f) {
2442             f.reset();
2443         });
2444        
2445         
2446         return this;
2447     },
2448     getItems : function()
2449     {
2450         var r=new Roo.util.MixedCollection(false, function(o){
2451             return o.id || (o.id = Roo.id());
2452         });
2453         var iter = function(el) {
2454             if (el.inputEl) {
2455                 r.add(el);
2456             }
2457             if (!el.items) {
2458                 return;
2459             }
2460             Roo.each(el.items,function(e) {
2461                 iter(e);
2462             });
2463             
2464             
2465         };
2466         iter(this);
2467         return r;
2468         
2469         
2470         
2471         
2472     }
2473     
2474 });
2475
2476  
2477 /*
2478  * Based on:
2479  * Ext JS Library 1.1.1
2480  * Copyright(c) 2006-2007, Ext JS, LLC.
2481  *
2482  * Originally Released Under LGPL - original licence link has changed is not relivant.
2483  *
2484  * Fork - LGPL
2485  * <script type="text/javascript">
2486  */
2487 /**
2488  * @class Roo.form.VTypes
2489  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
2490  * @singleton
2491  */
2492 Roo.form.VTypes = function(){
2493     // closure these in so they are only created once.
2494     var alpha = /^[a-zA-Z_]+$/;
2495     var alphanum = /^[a-zA-Z0-9_]+$/;
2496     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
2497     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
2498
2499     // All these messages and functions are configurable
2500     return {
2501         /**
2502          * The function used to validate email addresses
2503          * @param {String} value The email address
2504          */
2505         'email' : function(v){
2506             return email.test(v);
2507         },
2508         /**
2509          * The error text to display when the email validation function returns false
2510          * @type String
2511          */
2512         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
2513         /**
2514          * The keystroke filter mask to be applied on email input
2515          * @type RegExp
2516          */
2517         'emailMask' : /[a-z0-9_\.\-@]/i,
2518
2519         /**
2520          * The function used to validate URLs
2521          * @param {String} value The URL
2522          */
2523         'url' : function(v){
2524             return url.test(v);
2525         },
2526         /**
2527          * The error text to display when the url validation function returns false
2528          * @type String
2529          */
2530         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
2531         
2532         /**
2533          * The function used to validate alpha values
2534          * @param {String} value The value
2535          */
2536         'alpha' : function(v){
2537             return alpha.test(v);
2538         },
2539         /**
2540          * The error text to display when the alpha validation function returns false
2541          * @type String
2542          */
2543         'alphaText' : 'This field should only contain letters and _',
2544         /**
2545          * The keystroke filter mask to be applied on alpha input
2546          * @type RegExp
2547          */
2548         'alphaMask' : /[a-z_]/i,
2549
2550         /**
2551          * The function used to validate alphanumeric values
2552          * @param {String} value The value
2553          */
2554         'alphanum' : function(v){
2555             return alphanum.test(v);
2556         },
2557         /**
2558          * The error text to display when the alphanumeric validation function returns false
2559          * @type String
2560          */
2561         'alphanumText' : 'This field should only contain letters, numbers and _',
2562         /**
2563          * The keystroke filter mask to be applied on alphanumeric input
2564          * @type RegExp
2565          */
2566         'alphanumMask' : /[a-z0-9_]/i
2567     };
2568 }();/*
2569  * - LGPL
2570  *
2571  * Input
2572  * 
2573  */
2574
2575 /**
2576  * @class Roo.bootstrap.Input
2577  * @extends Roo.bootstrap.Component
2578  * Bootstrap Input class
2579  * @cfg {Boolean} disabled is it disabled
2580  * @cfg {String} fieldLabel - the label associated
2581  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
2582  * @cfg {String} name name of the input
2583  * @cfg {string} fieldLabel - the label associated
2584  * @cfg {string}  inputType - input / file submit ...
2585  * @cfg {string} placeholder - placeholder to put in text.
2586  * @cfg {string}  before - input group add on before
2587  * @cfg {string} after - input group add on after
2588  * 
2589  * 
2590  * @constructor
2591  * Create a new Input
2592  * @param {Object} config The config object
2593  */
2594
2595 Roo.bootstrap.Input = function(config){
2596     Roo.bootstrap.Input.superclass.constructor.call(this, config);
2597    
2598         this.addEvents({
2599             /**
2600              * @event focus
2601              * Fires when this field receives input focus.
2602              * @param {Roo.form.Field} this
2603              */
2604             focus : true,
2605             /**
2606              * @event blur
2607              * Fires when this field loses input focus.
2608              * @param {Roo.form.Field} this
2609              */
2610             blur : true,
2611             /**
2612              * @event specialkey
2613              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
2614              * {@link Roo.EventObject#getKey} to determine which key was pressed.
2615              * @param {Roo.form.Field} this
2616              * @param {Roo.EventObject} e The event object
2617              */
2618             specialkey : true,
2619             /**
2620              * @event change
2621              * Fires just before the field blurs if the field value has changed.
2622              * @param {Roo.form.Field} this
2623              * @param {Mixed} newValue The new value
2624              * @param {Mixed} oldValue The original value
2625              */
2626             change : true,
2627             /**
2628              * @event invalid
2629              * Fires after the field has been marked as invalid.
2630              * @param {Roo.form.Field} this
2631              * @param {String} msg The validation message
2632              */
2633             invalid : true,
2634             /**
2635              * @event valid
2636              * Fires after the field has been validated with no errors.
2637              * @param {Roo.form.Field} this
2638              */
2639             valid : true,
2640              /**
2641              * @event keyup
2642              * Fires after the key up
2643              * @param {Roo.form.Field} this
2644              * @param {Roo.EventObject}  e The event Object
2645              */
2646             keyup : true
2647         });
2648 };
2649
2650 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
2651      /**
2652      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
2653       automatic validation (defaults to "keyup").
2654      */
2655     validationEvent : "keyup",
2656      /**
2657      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
2658      */
2659     validateOnBlur : true,
2660     /**
2661      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
2662      */
2663     validationDelay : 250,
2664      /**
2665      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
2666      */
2667     focusClass : "x-form-focus",  // not needed???
2668     
2669        
2670     /**
2671      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
2672      */
2673     invalidClass : "has-error",
2674     
2675     /**
2676      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
2677      */
2678     selectOnFocus : false,
2679     
2680      /**
2681      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
2682      */
2683     maskRe : null,
2684        /**
2685      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
2686      */
2687     vtype : null,
2688     
2689       /**
2690      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
2691      */
2692     disableKeyFilter : false,
2693     
2694        /**
2695      * @cfg {Boolean} disabled True to disable the field (defaults to false).
2696      */
2697     disabled : false,
2698      /**
2699      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
2700      */
2701     allowBlank : true,
2702     /**
2703      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
2704      */
2705     blankText : "This field is required",
2706     
2707      /**
2708      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
2709      */
2710     minLength : 0,
2711     /**
2712      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
2713      */
2714     maxLength : Number.MAX_VALUE,
2715     /**
2716      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
2717      */
2718     minLengthText : "The minimum length for this field is {0}",
2719     /**
2720      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
2721      */
2722     maxLengthText : "The maximum length for this field is {0}",
2723   
2724     
2725     /**
2726      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
2727      * If available, this function will be called only after the basic validators all return true, and will be passed the
2728      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
2729      */
2730     validator : null,
2731     /**
2732      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
2733      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
2734      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
2735      */
2736     regex : null,
2737     /**
2738      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
2739      */
2740     regexText : "",
2741     
2742     
2743     
2744     fieldLabel : '',
2745     inputType : 'text',
2746     
2747     name : false,
2748     placeholder: false,
2749     before : false,
2750     after : false,
2751     
2752     // private
2753     hasFocus : false,
2754     preventMark: false,
2755     
2756     getAutoCreate : function(){
2757         
2758         var parent = this.parent();
2759         
2760         var align = parent.labelAlign;
2761         
2762         var id = Roo.id();
2763         
2764         var cfg = {
2765             cls: 'form-group' //input-group
2766         };
2767         
2768         var input =  {
2769             tag: 'input',
2770             id : id,
2771             type : this.inputType,
2772             cls : 'form-control',
2773             placeholder : this.placeholder || '' 
2774             
2775         };
2776         if (this.name) {
2777             input.name = name;
2778         }
2779         
2780         var inputblock = input;
2781         
2782         if (this.before || this.after) {
2783             
2784             inputblock = {
2785                 cls : 'input-group',
2786                 cn :  [] 
2787             };
2788             if (this.before) {
2789                 inputblock.cn.push({
2790                     tag :'span',
2791                     cls : 'input-group-addon',
2792                     html : this.before
2793                 });
2794             }
2795             inputblock.cn.push(input);
2796             if (this.after) {
2797                 inputblock.cn.push({
2798                     tag :'span',
2799                     cls : 'input-group-addon',
2800                     html : this.after
2801                 });
2802             }
2803             
2804         }
2805         
2806         Roo.log(align);
2807         Roo.log(this.fieldLabel.length);
2808         
2809         if (align ==='left' && this.fieldLabel.length) {
2810                 Roo.log("left and has label");
2811                 cfg.cn = [
2812                     
2813                     {
2814                         tag: 'label',
2815                         'for' :  id,
2816                         cls : 'col-sm-2 control-label',
2817                         html : this.fieldLabel
2818                         
2819                     },
2820                     {
2821                         cls : "col-sm-10", 
2822                         cn: [
2823                             inputblock
2824                         ]
2825                     }
2826                     
2827                 ];
2828         } else if ( this.fieldLabel.length) {
2829                 Roo.log(" label");
2830                  cfg.cn = [
2831                    
2832                     {
2833                         tag: 'label',
2834                         //cls : 'input-group-addon',
2835                         html : this.fieldLabel
2836                         
2837                     },
2838                     
2839                     inputblock
2840                     
2841                 ];
2842
2843         } else {
2844             
2845                    Roo.log(" no label && no align");
2846                 cfg.cn = [
2847                     
2848                         inputblock
2849                     
2850                 ];
2851                 
2852                 
2853         }
2854          
2855         
2856         
2857         
2858         if (this.disabled) {
2859             input.disabled=true;
2860         }
2861         return cfg;
2862         
2863     },
2864     /**
2865      * return the real input element.
2866      */
2867     inputEl: function ()
2868     {
2869         return this.el.select('input.form-control',true).first();
2870     },
2871     setDisabled : function(v)
2872     {
2873         var i  = this.inputEl().dom;
2874         if (v) {
2875             i.removeAttribute('disabled');
2876             return;
2877             
2878         }
2879         i.setAttribute('disabled','true');
2880     },
2881     initEvents : function()
2882     {
2883         
2884         this.inputEl().on("keydown" , this.fireKey,  this);
2885         this.inputEl().on("focus", this.onFocus,  this);
2886         this.inputEl().on("blur", this.onBlur,  this);
2887         this.inputEl().relayEvent('keyup', this);
2888
2889         // reference to original value for reset
2890         this.originalValue = this.getValue();
2891         //Roo.form.TextField.superclass.initEvents.call(this);
2892         if(this.validationEvent == 'keyup'){
2893             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
2894             this.inputEl().on('keyup', this.filterValidation, this);
2895         }
2896         else if(this.validationEvent !== false){
2897             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
2898         }
2899         
2900         if(this.selectOnFocus){
2901             this.on("focus", this.preFocus, this);
2902             
2903         }
2904         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
2905             this.inputEl().on("keypress", this.filterKeys, this);
2906         }
2907        /* if(this.grow){
2908             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
2909             this.el.on("click", this.autoSize,  this);
2910         }
2911         */
2912         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
2913             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
2914         }
2915         
2916     },
2917     filterValidation : function(e){
2918         if(!e.isNavKeyPress()){
2919             this.validationTask.delay(this.validationDelay);
2920         }
2921     },
2922      /**
2923      * Validates the field value
2924      * @return {Boolean} True if the value is valid, else false
2925      */
2926     validate : function(){
2927         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
2928         if(this.disabled || this.validateValue(this.getRawValue())){
2929             this.clearInvalid();
2930             return true;
2931         }
2932         return false;
2933     },
2934     
2935     
2936     /**
2937      * Validates a value according to the field's validation rules and marks the field as invalid
2938      * if the validation fails
2939      * @param {Mixed} value The value to validate
2940      * @return {Boolean} True if the value is valid, else false
2941      */
2942     validateValue : function(value){
2943         if(value.length < 1)  { // if it's blank
2944              if(this.allowBlank){
2945                 this.clearInvalid();
2946                 return true;
2947              }else{
2948                 this.markInvalid(this.blankText);
2949                 return false;
2950              }
2951         }
2952         if(value.length < this.minLength){
2953             this.markInvalid(String.format(this.minLengthText, this.minLength));
2954             return false;
2955         }
2956         if(value.length > this.maxLength){
2957             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
2958             return false;
2959         }
2960         if(this.vtype){
2961             var vt = Roo.form.VTypes;
2962             if(!vt[this.vtype](value, this)){
2963                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
2964                 return false;
2965             }
2966         }
2967         if(typeof this.validator == "function"){
2968             var msg = this.validator(value);
2969             if(msg !== true){
2970                 this.markInvalid(msg);
2971                 return false;
2972             }
2973         }
2974         if(this.regex && !this.regex.test(value)){
2975             this.markInvalid(this.regexText);
2976             return false;
2977         }
2978         return true;
2979     },
2980
2981     
2982     
2983      // private
2984     fireKey : function(e){
2985         //Roo.log('field ' + e.getKey());
2986         if(e.isNavKeyPress()){
2987             this.fireEvent("specialkey", this, e);
2988         }
2989     },
2990     onFocus : function(){
2991         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
2992            // this.el.addClass(this.focusClass);
2993         }
2994         if(!this.hasFocus){
2995             this.hasFocus = true;
2996             this.startValue = this.getValue();
2997             this.fireEvent("focus", this);
2998         }
2999     },
3000     
3001     beforeBlur : Roo.emptyFn,
3002
3003     
3004     // private
3005     onBlur : function(){
3006         this.beforeBlur();
3007         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
3008             //this.el.removeClass(this.focusClass);
3009         }
3010         this.hasFocus = false;
3011         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
3012             this.validate();
3013         }
3014         var v = this.getValue();
3015         if(String(v) !== String(this.startValue)){
3016             this.fireEvent('change', this, v, this.startValue);
3017         }
3018         this.fireEvent("blur", this);
3019     },
3020      /**
3021      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
3022      * @return {Mixed} value The field value
3023      */
3024     getValue : function(){
3025         var v = this.inputEl().getValue();
3026         return v;
3027     },
3028     /**
3029      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
3030      * @return {Mixed} value The field value
3031      */
3032     getRawValue : function(){
3033         var v = this.inputEl().getValue();
3034         
3035         return v;
3036     },
3037     /**
3038      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
3039      * @param {Mixed} value The value to set
3040      */
3041     setValue : function(v){
3042         this.value = v;
3043         if(this.rendered){
3044             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
3045             this.validate();
3046         }
3047     },
3048     
3049     /*
3050     processValue : function(value){
3051         if(this.stripCharsRe){
3052             var newValue = value.replace(this.stripCharsRe, '');
3053             if(newValue !== value){
3054                 this.setRawValue(newValue);
3055                 return newValue;
3056             }
3057         }
3058         return value;
3059     },
3060   */
3061     preFocus : function(){
3062         
3063         if(this.selectOnFocus){
3064             this.inputEl().dom.select();
3065         }
3066     },
3067     filterKeys : function(e){
3068         var k = e.getKey();
3069         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
3070             return;
3071         }
3072         var c = e.getCharCode(), cc = String.fromCharCode(c);
3073         if(Roo.isIE && (e.isSpecialKey() || !cc)){
3074             return;
3075         }
3076         if(!this.maskRe.test(cc)){
3077             e.stopEvent();
3078         }
3079     },
3080      /**
3081      * Clear any invalid styles/messages for this field
3082      */
3083     clearInvalid : function(){
3084         
3085         if(!this.el || this.preventMark){ // not rendered
3086             return;
3087         }
3088         this.el.removeClass(this.invalidClass);
3089         /*
3090         switch(this.msgTarget){
3091             case 'qtip':
3092                 this.el.dom.qtip = '';
3093                 break;
3094             case 'title':
3095                 this.el.dom.title = '';
3096                 break;
3097             case 'under':
3098                 if(this.errorEl){
3099                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
3100                 }
3101                 break;
3102             case 'side':
3103                 if(this.errorIcon){
3104                     this.errorIcon.dom.qtip = '';
3105                     this.errorIcon.hide();
3106                     this.un('resize', this.alignErrorIcon, this);
3107                 }
3108                 break;
3109             default:
3110                 var t = Roo.getDom(this.msgTarget);
3111                 t.innerHTML = '';
3112                 t.style.display = 'none';
3113                 break;
3114         }
3115         */
3116         this.fireEvent('valid', this);
3117     },
3118      /**
3119      * Mark this field as invalid
3120      * @param {String} msg The validation message
3121      */
3122     markInvalid : function(msg){
3123         if(!this.el  || this.preventMark){ // not rendered
3124             return;
3125         }
3126         this.el.addClass(this.invalidClass);
3127         /*
3128         msg = msg || this.invalidText;
3129         switch(this.msgTarget){
3130             case 'qtip':
3131                 this.el.dom.qtip = msg;
3132                 this.el.dom.qclass = 'x-form-invalid-tip';
3133                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
3134                     Roo.QuickTips.enable();
3135                 }
3136                 break;
3137             case 'title':
3138                 this.el.dom.title = msg;
3139                 break;
3140             case 'under':
3141                 if(!this.errorEl){
3142                     var elp = this.el.findParent('.x-form-element', 5, true);
3143                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
3144                     this.errorEl.setWidth(elp.getWidth(true)-20);
3145                 }
3146                 this.errorEl.update(msg);
3147                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
3148                 break;
3149             case 'side':
3150                 if(!this.errorIcon){
3151                     var elp = this.el.findParent('.x-form-element', 5, true);
3152                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
3153                 }
3154                 this.alignErrorIcon();
3155                 this.errorIcon.dom.qtip = msg;
3156                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
3157                 this.errorIcon.show();
3158                 this.on('resize', this.alignErrorIcon, this);
3159                 break;
3160             default:
3161                 var t = Roo.getDom(this.msgTarget);
3162                 t.innerHTML = msg;
3163                 t.style.display = this.msgDisplay;
3164                 break;
3165         }
3166         */
3167         this.fireEvent('invalid', this, msg);
3168     },
3169     // private
3170     SafariOnKeyDown : function(event)
3171     {
3172         // this is a workaround for a password hang bug on chrome/ webkit.
3173         
3174         var isSelectAll = false;
3175         
3176         if(this.inputEl().dom.selectionEnd > 0){
3177             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
3178         }
3179         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
3180             event.preventDefault();
3181             this.setValue('');
3182             return;
3183         }
3184         
3185         if(isSelectAll){ // backspace and delete key
3186             
3187             event.preventDefault();
3188             // this is very hacky as keydown always get's upper case.
3189             //
3190             var cc = String.fromCharCode(event.getCharCode());
3191             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
3192             
3193         }
3194         
3195         
3196     }
3197 });
3198
3199