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  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * 
20  * @constructor
21  * Do not use directly - it does not do anything..
22  * @param {Object} config The config object
23  */
24
25
26
27 Roo.bootstrap.Component = function(config){
28     Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 };
30
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
32     
33     
34     allowDomMove : false, // to stop relocations in parent onRender...
35     
36     cls : false,
37     
38     style : false,
39     
40     autoCreate : false,
41     
42     initEvents : function() {  },
43     
44     xattr : false,
45     
46     parentId : false,
47     
48     can_build_overlaid : true,
49     
50     dataId : false,
51     
52     name : false,
53     
54     parent: function() {
55         // returns the parent component..
56         return Roo.ComponentMgr.get(this.parentId)
57         
58         
59     },
60     
61     // private
62     onRender : function(ct, position)
63     {
64        // Roo.log("Call onRender: " + this.xtype);
65         
66         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
67         
68         if(this.el){
69             if (this.el.attr('xtype')) {
70                 this.el.attr('xtypex', this.el.attr('xtype'));
71                 this.el.dom.removeAttribute('xtype');
72                 
73                 this.initEvents();
74             }
75             
76             return;
77         }
78         
79          
80         
81         var cfg = Roo.apply({},  this.getAutoCreate());
82         cfg.id = Roo.id();
83         
84         // fill in the extra attributes 
85         if (this.xattr && typeof(this.xattr) =='object') {
86             for (var i in this.xattr) {
87                 cfg[i] = this.xattr[i];
88             }
89         }
90         
91         if(this.dataId){
92             cfg.dataId = this.dataId;
93         }
94         
95         if (this.cls) {
96             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
97         }
98         
99         if (this.style) { // fixme needs to support more complex style data.
100             cfg.style = this.style;
101         }
102         
103         if(this.name){
104             cfg.name = this.name;
105         }
106         
107         this.el = ct.createChild(cfg, position);
108         
109         if(this.tabIndex !== undefined){
110             this.el.dom.setAttribute('tabIndex', this.tabIndex);
111         }
112         this.initEvents();
113         
114         
115     },
116     
117     getChildContainer : function()
118     {
119         return this.el;
120     },
121     
122     
123     addxtype  : function(tree,cntr)
124     {
125         var cn = this;
126         
127         cn = Roo.factory(tree);
128            
129         cn.parentType = this.xtype; //??
130         cn.parentId = this.id;
131         
132         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
133         
134         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
135         
136         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
137         
138         var build_from_html =  Roo.XComponent.build_from_html;
139           
140         var is_body  = (tree.xtype == 'Body') ;
141           
142         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
143           
144         var self_cntr_el = Roo.get(this[cntr](false));
145         
146         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148                 return this.addxtypeChild(tree,cntr);
149             }
150             
151             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
152                 
153             if(echild){
154                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
155             }
156             
157             Roo.log('skipping render');
158             return cn;
159             
160         }
161         
162         var ret = false;
163         
164         while (true) {
165             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
166             
167             if (!echild) {
168                 break;
169             }
170             
171             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
172                 break;
173             }
174             
175             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
176         }
177         return ret;
178     },
179     
180     addxtypeChild : function (tree, cntr)
181     {
182         Roo.log('addxtypeChild:' + cntr);
183         var cn = this;
184         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
185         
186         
187         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188                     (typeof(tree['flexy:foreach']) != 'undefined');
189           
190         
191         
192         
193         // render the element if it's not BODY.
194         if (tree.xtype != 'Body') {
195            
196             cn = Roo.factory(tree);
197            
198             cn.parentType = this.xtype; //??
199             cn.parentId = this.id;
200             
201             var build_from_html =  Roo.XComponent.build_from_html;
202             
203             
204             // does the container contain child eleemnts with 'xtype' attributes.
205             // that match this xtype..
206             // note - when we render we create these as well..
207             // so we should check to see if body has xtype set.
208             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
209                
210                 var self_cntr_el = Roo.get(this[cntr](false));
211                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
212                 
213                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
215                   
216                   
217                   
218                     cn.el = echild;
219                   //  Roo.log("GOT");
220                     //echild.dom.removeAttribute('xtype');
221                 } else {
222                     Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
223                    
224                 }
225             }
226            
227             
228                
229             // if object has flexy:if - then it may or may not be rendered.
230             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
231                 // skip a flexy if element.
232                 Roo.log('skipping render');
233              } else {
234                  
235                 // actually if flexy:foreach is found, we really want to create 
236                 // multiple copies here...
237                 //Roo.log('render');
238                 //Roo.log(this[cntr]());
239                 cn.render(this[cntr](true));
240              }
241             // then add the element..
242         }
243         
244         
245         // handle the kids..
246         
247         var nitems = [];
248         /*
249         if (typeof (tree.menu) != 'undefined') {
250             tree.menu.parentType = cn.xtype;
251             tree.menu.triggerEl = cn.el;
252             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
253             
254         }
255         */
256         if (!tree.items || !tree.items.length) {
257             cn.items = nitems;
258             return cn;
259         }
260         var items = tree.items;
261         delete tree.items;
262         
263         //Roo.log(items.length);
264             // add the items..
265         for(var i =0;i < items.length;i++) {
266             nitems.push(cn.addxtype(Roo.apply({}, items[i])));
267         }
268         
269         cn.items = nitems;
270         
271         return cn;
272     }
273     
274     
275     
276     
277 });
278
279  /*
280  * - LGPL
281  *
282  * Body
283  * 
284  */
285
286 /**
287  * @class Roo.bootstrap.Body
288  * @extends Roo.bootstrap.Component
289  * Bootstrap Body class
290  * 
291  * @constructor
292  * Create a new body
293  * @param {Object} config The config object
294  */
295
296 Roo.bootstrap.Body = function(config){
297     Roo.bootstrap.Body.superclass.constructor.call(this, config);
298     this.el = Roo.get(document.body);
299     if (this.cls && this.cls.length) {
300         Roo.get(document.body).addClass(this.cls);
301     }
302 };
303
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
305       
306         autoCreate : {
307         cls: 'container'
308     },
309     onRender : function(ct, position)
310     {
311        /* Roo.log("Roo.bootstrap.Body - onRender");
312         if (this.cls && this.cls.length) {
313             Roo.get(document.body).addClass(this.cls);
314         }
315         // style??? xttr???
316         */
317     }
318     
319     
320  
321    
322 });
323
324  /*
325  * - LGPL
326  *
327  * button group
328  * 
329  */
330
331
332 /**
333  * @class Roo.bootstrap.ButtonGroup
334  * @extends Roo.bootstrap.Component
335  * Bootstrap ButtonGroup class
336  * @cfg {String} size lg | sm | xs (default empty normal)
337  * @cfg {String} align vertical | justified  (default none)
338  * @cfg {String} direction up | down (default down)
339  * @cfg {Boolean} toolbar false | true
340  * @cfg {Boolean} btn true | false
341  * 
342  * 
343  * @constructor
344  * Create a new Input
345  * @param {Object} config The config object
346  */
347
348 Roo.bootstrap.ButtonGroup = function(config){
349     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
350 };
351
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
353     
354     size: '',
355     align: '',
356     direction: '',
357     toolbar: false,
358     btn: true,
359
360     getAutoCreate : function(){
361         var cfg = {
362             cls: 'btn-group',
363             html : null
364         }
365         
366         cfg.html = this.html || cfg.html;
367         
368         if (this.toolbar) {
369             cfg = {
370                 cls: 'btn-toolbar',
371                 html: null
372             }
373             
374             return cfg;
375         }
376         
377         if (['vertical','justified'].indexOf(this.align)!==-1) {
378             cfg.cls = 'btn-group-' + this.align;
379             
380             if (this.align == 'justified') {
381                 console.log(this.items);
382             }
383         }
384         
385         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386             cfg.cls += ' btn-group-' + this.size;
387         }
388         
389         if (this.direction == 'up') {
390             cfg.cls += ' dropup' ;
391         }
392         
393         return cfg;
394     }
395    
396 });
397
398  /*
399  * - LGPL
400  *
401  * button
402  * 
403  */
404
405 /**
406  * @class Roo.bootstrap.Button
407  * @extends Roo.bootstrap.Component
408  * Bootstrap Button class
409  * @cfg {String} html The button content
410  * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411  * @cfg {String} size empty | lg | sm | xs
412  * @cfg {String} tag empty | a | input | submit
413  * @cfg {String} href empty or href
414  * @cfg {Boolean} disabled false | true
415  * @cfg {Boolean} isClose false | true
416  * @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
417  * @cfg {String} badge text for badge
418  * @cfg {String} theme default (or empty) | glow
419  * @cfg {Boolean} inverse false | true
420  * @cfg {Boolean} toggle false | true
421  * @cfg {String} ontext text for on toggle state
422  * @cfg {String} offtext text for off toggle state
423  * @cfg {Boolean} defaulton true | false
424  * @cfg {Boolean} preventDefault (true | false) default true
425  * @cfg {Boolean} removeClass true | false remove the standard class..
426  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
427  * 
428  * @constructor
429  * Create a new button
430  * @param {Object} config The config object
431  */
432
433
434 Roo.bootstrap.Button = function(config){
435     Roo.bootstrap.Button.superclass.constructor.call(this, config);
436     this.addEvents({
437         // raw events
438         /**
439          * @event click
440          * When a butotn is pressed
441          * @param {Roo.EventObject} e
442          */
443         "click" : true,
444          /**
445          * @event toggle
446          * After the button has been toggles
447          * @param {Roo.EventObject} e
448          * @param {boolean} pressed (also available as button.pressed)
449          */
450         "toggle" : true
451     });
452 };
453
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
455     html: false,
456     active: false,
457     weight: '',
458     size: '',
459     tag: 'button',
460     href: '',
461     disabled: false,
462     isClose: false,
463     glyphicon: '',
464     badge: '',
465     theme: 'default',
466     inverse: false,
467     
468     toggle: false,
469     ontext: 'ON',
470     offtext: 'OFF',
471     defaulton: true,
472     preventDefault: true,
473     removeClass: false,
474     name: false,
475     target: false,
476     
477     
478     pressed : null,
479      
480     
481     getAutoCreate : function(){
482         
483         var cfg = {
484             tag : 'button',
485             cls : 'roo-button',
486             html: ''
487         };
488         
489         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
491             this.tag = 'button';
492         } else {
493             cfg.tag = this.tag;
494         }
495         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
496         
497         if (this.toggle == true) {
498             cfg={
499                 tag: 'div',
500                 cls: 'slider-frame roo-button',
501                 cn: [
502                     {
503                         tag: 'span',
504                         'data-on-text':'ON',
505                         'data-off-text':'OFF',
506                         cls: 'slider-button',
507                         html: this.offtext
508                     }
509                 ]
510             };
511             
512             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513                 cfg.cls += ' '+this.weight;
514             }
515             
516             return cfg;
517         }
518         
519         if (this.isClose) {
520             cfg.cls += ' close';
521             
522             cfg["aria-hidden"] = true;
523             
524             cfg.html = "&times;";
525             
526             return cfg;
527         }
528         
529          
530         if (this.theme==='default') {
531             cfg.cls = 'btn roo-button';
532             
533             //if (this.parentType != 'Navbar') {
534             this.weight = this.weight.length ?  this.weight : 'default';
535             //}
536             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
537                 
538                 cfg.cls += ' btn-' + this.weight;
539             }
540         } else if (this.theme==='glow') {
541             
542             cfg.tag = 'a';
543             cfg.cls = 'btn-glow roo-button';
544             
545             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546                 
547                 cfg.cls += ' ' + this.weight;
548             }
549         }
550    
551         
552         if (this.inverse) {
553             this.cls += ' inverse';
554         }
555         
556         
557         if (this.active) {
558             cfg.cls += ' active';
559         }
560         
561         if (this.disabled) {
562             cfg.disabled = 'disabled';
563         }
564         
565         if (this.items) {
566             Roo.log('changing to ul' );
567             cfg.tag = 'ul';
568             this.glyphicon = 'caret';
569         }
570         
571         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
572          
573         //gsRoo.log(this.parentType);
574         if (this.parentType === 'Navbar' && !this.parent().bar) {
575             Roo.log('changing to li?');
576             
577             cfg.tag = 'li';
578             
579             cfg.cls = '';
580             cfg.cn =  [{
581                 tag : 'a',
582                 cls : 'roo-button',
583                 html : this.html,
584                 href : this.href || '#'
585             }];
586             if (this.menu) {
587                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
588                 cfg.cls += ' dropdown';
589             }   
590             
591             delete cfg.html;
592             
593         }
594         
595        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
596         
597         if (this.glyphicon) {
598             cfg.html = ' ' + cfg.html;
599             
600             cfg.cn = [
601                 {
602                     tag: 'span',
603                     cls: 'glyphicon glyphicon-' + this.glyphicon
604                 }
605             ];
606         }
607         
608         if (this.badge) {
609             cfg.html += ' ';
610             
611             cfg.tag = 'a';
612             
613 //            cfg.cls='btn roo-button';
614             
615             cfg.href=this.href;
616             
617             var value = cfg.html;
618             
619             if(this.glyphicon){
620                 value = {
621                             tag: 'span',
622                             cls: 'glyphicon glyphicon-' + this.glyphicon,
623                             html: this.html
624                         };
625                 
626             }
627             
628             cfg.cn = [
629                 value,
630                 {
631                     tag: 'span',
632                     cls: 'badge',
633                     html: this.badge
634                 }
635             ];
636             
637             cfg.html='';
638         }
639         
640         if (this.menu) {
641             cfg.cls += ' dropdown';
642             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
643         }
644         
645         if (cfg.tag !== 'a' && this.href !== '') {
646             throw "Tag must be a to set href.";
647         } else if (this.href.length > 0) {
648             cfg.href = this.href;
649         }
650         
651         if(this.removeClass){
652             cfg.cls = '';
653         }
654         
655         if(this.target){
656             cfg.target = this.target;
657         }
658         
659         return cfg;
660     },
661     initEvents: function() {
662        // Roo.log('init events?');
663 //        Roo.log(this.el.dom);
664         // add the menu...
665         
666         if (typeof (this.menu) != 'undefined') {
667             this.menu.parentType = this.xtype;
668             this.menu.triggerEl = this.el;
669             this.addxtype(Roo.apply({}, this.menu));
670         }
671
672
673        if (this.el.hasClass('roo-button')) {
674             this.el.on('click', this.onClick, this);
675        } else {
676             this.el.select('.roo-button').on('click', this.onClick, this);
677        }
678        
679        if(this.removeClass){
680            this.el.on('click', this.onClick, this);
681        }
682        
683        this.el.enableDisplayMode();
684         
685     },
686     onClick : function(e)
687     {
688         if (this.disabled) {
689             return;
690         }
691         
692         Roo.log('button on click ');
693         if(this.preventDefault){
694             e.preventDefault();
695         }
696         if (this.pressed === true || this.pressed === false) {
697             this.pressed = !this.pressed;
698             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699             this.fireEvent('toggle', this, e, this.pressed);
700         }
701         
702         
703         this.fireEvent('click', this, e);
704     },
705     
706     /**
707      * Enables this button
708      */
709     enable : function()
710     {
711         this.disabled = false;
712         this.el.removeClass('disabled');
713     },
714     
715     /**
716      * Disable this button
717      */
718     disable : function()
719     {
720         this.disabled = true;
721         this.el.addClass('disabled');
722     },
723      /**
724      * sets the active state on/off, 
725      * @param {Boolean} state (optional) Force a particular state
726      */
727     setActive : function(v) {
728         
729         this.el[v ? 'addClass' : 'removeClass']('active');
730     },
731      /**
732      * toggles the current active state 
733      */
734     toggleActive : function()
735     {
736        var active = this.el.hasClass('active');
737        this.setActive(!active);
738        
739         
740     },
741     setText : function(str)
742     {
743         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
744     },
745     getText : function()
746     {
747         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
748     },
749     hide: function() {
750        
751      
752         this.el.hide();   
753     },
754     show: function() {
755        
756         this.el.show();   
757     }
758     
759     
760 });
761
762  /*
763  * - LGPL
764  *
765  * column
766  * 
767  */
768
769 /**
770  * @class Roo.bootstrap.Column
771  * @extends Roo.bootstrap.Component
772  * Bootstrap Column class
773  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775  * @cfg {Number} md colspan out of 12 for computer-sized screens
776  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777  * @cfg {String} html content of column.
778  * 
779  * @constructor
780  * Create a new Column
781  * @param {Object} config The config object
782  */
783
784 Roo.bootstrap.Column = function(config){
785     Roo.bootstrap.Column.superclass.constructor.call(this, config);
786 };
787
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
789     
790     xs: null,
791     sm: null,
792     md: null,
793     lg: null,
794     html: '',
795     offset: 0,
796     
797     getAutoCreate : function(){
798         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
799         
800         cfg = {
801             tag: 'div',
802             cls: 'column'
803         };
804         
805         var settings=this;
806         ['xs','sm','md','lg'].map(function(size){
807             if (settings[size]) {
808                 cfg.cls += ' col-' + size + '-' + settings[size];
809             }
810         });
811         if (this.html.length) {
812             cfg.html = this.html;
813         }
814         
815         return cfg;
816     }
817    
818 });
819
820  
821
822  /*
823  * - LGPL
824  *
825  * page container.
826  * 
827  */
828
829
830 /**
831  * @class Roo.bootstrap.Container
832  * @extends Roo.bootstrap.Component
833  * Bootstrap Container class
834  * @cfg {Boolean} jumbotron is it a jumbotron element
835  * @cfg {String} html content of element
836  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838  * @cfg {String} header content of header (for panel)
839  * @cfg {String} footer content of footer (for panel)
840  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841  * @cfg {String} tag (header|aside|section) type of HTML tag.
842
843  *     
844  * @constructor
845  * Create a new Container
846  * @param {Object} config The config object
847  */
848
849 Roo.bootstrap.Container = function(config){
850     Roo.bootstrap.Container.superclass.constructor.call(this, config);
851 };
852
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
854     
855     jumbotron : false,
856     well: '',
857     panel : '',
858     header: '',
859     footer : '',
860     sticky: '',
861     tag : false,
862   
863      
864     getChildContainer : function() {
865         
866         if(!this.el){
867             return false;
868         }
869         
870         if (this.panel.length) {
871             return this.el.select('.panel-body',true).first();
872         }
873         
874         return this.el;
875     },
876     
877     
878     getAutoCreate : function(){
879         
880         var cfg = {
881             tag : this.tag || 'div',
882             html : '',
883             cls : ''
884         };
885         if (this.jumbotron) {
886             cfg.cls = 'jumbotron';
887         }
888         // - this is applied by the parent..
889         //if (this.cls) {
890         //    cfg.cls = this.cls + '';
891         //}
892         
893         if (this.sticky.length) {
894             
895             var bd = Roo.get(document.body);
896             if (!bd.hasClass('bootstrap-sticky')) {
897                 bd.addClass('bootstrap-sticky');
898                 Roo.select('html',true).setStyle('height', '100%');
899             }
900              
901             cfg.cls += 'bootstrap-sticky-' + this.sticky;
902         }
903         
904         
905         if (this.well.length) {
906             switch (this.well) {
907                 case 'lg':
908                 case 'sm':
909                     cfg.cls +=' well well-' +this.well;
910                     break;
911                 default:
912                     cfg.cls +=' well';
913                     break;
914             }
915         }
916         
917         var body = cfg;
918         
919         if (this.panel.length) {
920             cfg.cls += ' panel panel-' + this.panel;
921             cfg.cn = [];
922             if (this.header.length) {
923                 cfg.cn.push({
924                     
925                     cls : 'panel-heading',
926                     cn : [{
927                         tag: 'h3',
928                         cls : 'panel-title',
929                         html : this.header
930                     }]
931                     
932                 });
933             }
934             body = false;
935             cfg.cn.push({
936                 cls : 'panel-body',
937                 html : this.html
938             });
939             
940             
941             if (this.footer.length) {
942                 cfg.cn.push({
943                     cls : 'panel-footer',
944                     html : this.footer
945                     
946                 });
947             }
948             
949         }
950         
951         if (body) {
952             body.html = this.html || cfg.html;
953         }
954         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955             cfg.cls =  'container';
956         }
957         
958         return cfg;
959     },
960     
961     titleEl : function()
962     {
963         if(!this.el || !this.panel.length || !this.header.length){
964             return;
965         }
966         
967         return this.el.select('.panel-title',true).first();
968     },
969     
970     setTitle : function(v)
971     {
972         var titleEl = this.titleEl();
973         
974         if(!titleEl){
975             return;
976         }
977         
978         titleEl.dom.innerHTML = v;
979     },
980     
981     getTitle : function()
982     {
983         
984         var titleEl = this.titleEl();
985         
986         if(!titleEl){
987             return '';
988         }
989         
990         return titleEl.dom.innerHTML;
991     }
992    
993 });
994
995  /*
996  * - LGPL
997  *
998  * image
999  * 
1000  */
1001
1002
1003 /**
1004  * @class Roo.bootstrap.Img
1005  * @extends Roo.bootstrap.Component
1006  * Bootstrap Img class
1007  * @cfg {Boolean} imgResponsive false | true
1008  * @cfg {String} border rounded | circle | thumbnail
1009  * @cfg {String} src image source
1010  * @cfg {String} alt image alternative text
1011  * @cfg {String} href a tag href
1012  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1013  * 
1014  * @constructor
1015  * Create a new Input
1016  * @param {Object} config The config object
1017  */
1018
1019 Roo.bootstrap.Img = function(config){
1020     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1021     
1022     this.addEvents({
1023         // img events
1024         /**
1025          * @event click
1026          * The img click event for the img.
1027          * @param {Roo.EventObject} e
1028          */
1029         "click" : true
1030     });
1031 };
1032
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1034     
1035     imgResponsive: true,
1036     border: '',
1037     src: '',
1038     href: false,
1039     target: false,
1040
1041     getAutoCreate : function(){
1042         
1043         var cfg = {
1044             tag: 'img',
1045             cls: (this.imgResponsive) ? 'img-responsive' : '',
1046             html : null
1047         }
1048         
1049         cfg.html = this.html || cfg.html;
1050         
1051         cfg.src = this.src || cfg.src;
1052         
1053         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054             cfg.cls += ' img-' + this.border;
1055         }
1056         
1057         if(this.alt){
1058             cfg.alt = this.alt;
1059         }
1060         
1061         if(this.href){
1062             var a = {
1063                 tag: 'a',
1064                 href: this.href,
1065                 cn: [
1066                     cfg
1067                 ]
1068             }
1069             
1070             if(this.target){
1071                 a.target = this.target;
1072             }
1073             
1074         }
1075         
1076         
1077         return (this.href) ? a : cfg;
1078     },
1079     
1080     initEvents: function() {
1081         
1082         if(!this.href){
1083             this.el.on('click', this.onClick, this);
1084         }
1085     },
1086     
1087     onClick : function(e)
1088     {
1089         Roo.log('img onclick');
1090         this.fireEvent('click', this, e);
1091     }
1092    
1093 });
1094
1095  /*
1096  * - LGPL
1097  *
1098  * image
1099  * 
1100  */
1101
1102
1103 /**
1104  * @class Roo.bootstrap.Link
1105  * @extends Roo.bootstrap.Component
1106  * Bootstrap Link Class
1107  * @cfg {String} alt image alternative text
1108  * @cfg {String} href a tag href
1109  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110  * @cfg {String} html the content of the link.
1111  * @cfg {Boolean} preventDefault (true | false) default false
1112
1113  * 
1114  * @constructor
1115  * Create a new Input
1116  * @param {Object} config The config object
1117  */
1118
1119 Roo.bootstrap.Link = function(config){
1120     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1121     
1122     this.addEvents({
1123         // img events
1124         /**
1125          * @event click
1126          * The img click event for the img.
1127          * @param {Roo.EventObject} e
1128          */
1129         "click" : true
1130     });
1131 };
1132
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1134     
1135     href: false,
1136     target: false,
1137     preventDefault: false,
1138
1139     getAutoCreate : function(){
1140         
1141         var cfg = {
1142             tag: 'a',
1143             html : this.html || 'html-missing'
1144         }
1145         
1146         
1147         if(this.alt){
1148             cfg.alt = this.alt;
1149         }
1150         cfg.href = this.href || '#';
1151         if(this.target){
1152             cfg.target = this.target;
1153         }
1154         
1155         return cfg;
1156     },
1157     
1158     initEvents: function() {
1159         
1160         if(!this.href){
1161             this.el.on('click', this.onClick, this);
1162         }
1163     },
1164     
1165     onClick : function(e)
1166     {
1167         if(this.preventDefault){
1168             e.preventDefault();
1169         }
1170         //Roo.log('img onclick');
1171         this.fireEvent('click', this, e);
1172     }
1173    
1174 });
1175
1176  /*
1177  * - LGPL
1178  *
1179  * header
1180  * 
1181  */
1182
1183 /**
1184  * @class Roo.bootstrap.Header
1185  * @extends Roo.bootstrap.Component
1186  * Bootstrap Header class
1187  * @cfg {String} html content of header
1188  * @cfg {Number} level (1|2|3|4|5|6) default 1
1189  * 
1190  * @constructor
1191  * Create a new Header
1192  * @param {Object} config The config object
1193  */
1194
1195
1196 Roo.bootstrap.Header  = function(config){
1197     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1198 };
1199
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1201     
1202     //href : false,
1203     html : false,
1204     level : 1,
1205     
1206     
1207     
1208     getAutoCreate : function(){
1209         
1210         var cfg = {
1211             tag: 'h' + (1 *this.level),
1212             html: this.html || 'fill in html'
1213         } ;
1214         
1215         return cfg;
1216     }
1217    
1218 });
1219
1220  
1221
1222  /*
1223  * Based on:
1224  * Ext JS Library 1.1.1
1225  * Copyright(c) 2006-2007, Ext JS, LLC.
1226  *
1227  * Originally Released Under LGPL - original licence link has changed is not relivant.
1228  *
1229  * Fork - LGPL
1230  * <script type="text/javascript">
1231  */
1232  
1233 /**
1234  * @class Roo.bootstrap.MenuMgr
1235  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1236  * @singleton
1237  */
1238 Roo.bootstrap.MenuMgr = function(){
1239    var menus, active, groups = {}, attached = false, lastShow = new Date();
1240
1241    // private - called when first menu is created
1242    function init(){
1243        menus = {};
1244        active = new Roo.util.MixedCollection();
1245        Roo.get(document).addKeyListener(27, function(){
1246            if(active.length > 0){
1247                hideAll();
1248            }
1249        });
1250    }
1251
1252    // private
1253    function hideAll(){
1254        if(active && active.length > 0){
1255            var c = active.clone();
1256            c.each(function(m){
1257                m.hide();
1258            });
1259        }
1260    }
1261
1262    // private
1263    function onHide(m){
1264        active.remove(m);
1265        if(active.length < 1){
1266            Roo.get(document).un("mouseup", onMouseDown);
1267             
1268            attached = false;
1269        }
1270    }
1271
1272    // private
1273    function onShow(m){
1274        var last = active.last();
1275        lastShow = new Date();
1276        active.add(m);
1277        if(!attached){
1278           Roo.get(document).on("mouseup", onMouseDown);
1279            
1280            attached = true;
1281        }
1282        if(m.parentMenu){
1283           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284           m.parentMenu.activeChild = m;
1285        }else if(last && last.isVisible()){
1286           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1287        }
1288    }
1289
1290    // private
1291    function onBeforeHide(m){
1292        if(m.activeChild){
1293            m.activeChild.hide();
1294        }
1295        if(m.autoHideTimer){
1296            clearTimeout(m.autoHideTimer);
1297            delete m.autoHideTimer;
1298        }
1299    }
1300
1301    // private
1302    function onBeforeShow(m){
1303        var pm = m.parentMenu;
1304        if(!pm && !m.allowOtherMenus){
1305            hideAll();
1306        }else if(pm && pm.activeChild && active != m){
1307            pm.activeChild.hide();
1308        }
1309    }
1310
1311    // private
1312    function onMouseDown(e){
1313         Roo.log("on MouseDown");
1314         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1315            hideAll();
1316         }
1317         
1318         
1319    }
1320
1321    // private
1322    function onBeforeCheck(mi, state){
1323        if(state){
1324            var g = groups[mi.group];
1325            for(var i = 0, l = g.length; i < l; i++){
1326                if(g[i] != mi){
1327                    g[i].setChecked(false);
1328                }
1329            }
1330        }
1331    }
1332
1333    return {
1334
1335        /**
1336         * Hides all menus that are currently visible
1337         */
1338        hideAll : function(){
1339             hideAll();  
1340        },
1341
1342        // private
1343        register : function(menu){
1344            if(!menus){
1345                init();
1346            }
1347            menus[menu.id] = menu;
1348            menu.on("beforehide", onBeforeHide);
1349            menu.on("hide", onHide);
1350            menu.on("beforeshow", onBeforeShow);
1351            menu.on("show", onShow);
1352            var g = menu.group;
1353            if(g && menu.events["checkchange"]){
1354                if(!groups[g]){
1355                    groups[g] = [];
1356                }
1357                groups[g].push(menu);
1358                menu.on("checkchange", onCheck);
1359            }
1360        },
1361
1362         /**
1363          * Returns a {@link Roo.menu.Menu} object
1364          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365          * be used to generate and return a new Menu instance.
1366          */
1367        get : function(menu){
1368            if(typeof menu == "string"){ // menu id
1369                return menus[menu];
1370            }else if(menu.events){  // menu instance
1371                return menu;
1372            }
1373            /*else if(typeof menu.length == 'number'){ // array of menu items?
1374                return new Roo.bootstrap.Menu({items:menu});
1375            }else{ // otherwise, must be a config
1376                return new Roo.bootstrap.Menu(menu);
1377            }
1378            */
1379            return false;
1380        },
1381
1382        // private
1383        unregister : function(menu){
1384            delete menus[menu.id];
1385            menu.un("beforehide", onBeforeHide);
1386            menu.un("hide", onHide);
1387            menu.un("beforeshow", onBeforeShow);
1388            menu.un("show", onShow);
1389            var g = menu.group;
1390            if(g && menu.events["checkchange"]){
1391                groups[g].remove(menu);
1392                menu.un("checkchange", onCheck);
1393            }
1394        },
1395
1396        // private
1397        registerCheckable : function(menuItem){
1398            var g = menuItem.group;
1399            if(g){
1400                if(!groups[g]){
1401                    groups[g] = [];
1402                }
1403                groups[g].push(menuItem);
1404                menuItem.on("beforecheckchange", onBeforeCheck);
1405            }
1406        },
1407
1408        // private
1409        unregisterCheckable : function(menuItem){
1410            var g = menuItem.group;
1411            if(g){
1412                groups[g].remove(menuItem);
1413                menuItem.un("beforecheckchange", onBeforeCheck);
1414            }
1415        }
1416    };
1417 }();/*
1418  * - LGPL
1419  *
1420  * menu
1421  * 
1422  */
1423
1424 /**
1425  * @class Roo.bootstrap.Menu
1426  * @extends Roo.bootstrap.Component
1427  * Bootstrap Menu class - container for MenuItems
1428  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1429  * 
1430  * @constructor
1431  * Create a new Menu
1432  * @param {Object} config The config object
1433  */
1434
1435
1436 Roo.bootstrap.Menu = function(config){
1437     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438     if (this.registerMenu) {
1439         Roo.bootstrap.MenuMgr.register(this);
1440     }
1441     this.addEvents({
1442         /**
1443          * @event beforeshow
1444          * Fires before this menu is displayed
1445          * @param {Roo.menu.Menu} this
1446          */
1447         beforeshow : true,
1448         /**
1449          * @event beforehide
1450          * Fires before this menu is hidden
1451          * @param {Roo.menu.Menu} this
1452          */
1453         beforehide : true,
1454         /**
1455          * @event show
1456          * Fires after this menu is displayed
1457          * @param {Roo.menu.Menu} this
1458          */
1459         show : true,
1460         /**
1461          * @event hide
1462          * Fires after this menu is hidden
1463          * @param {Roo.menu.Menu} this
1464          */
1465         hide : true,
1466         /**
1467          * @event click
1468          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469          * @param {Roo.menu.Menu} this
1470          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471          * @param {Roo.EventObject} e
1472          */
1473         click : true,
1474         /**
1475          * @event mouseover
1476          * Fires when the mouse is hovering over this menu
1477          * @param {Roo.menu.Menu} this
1478          * @param {Roo.EventObject} e
1479          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1480          */
1481         mouseover : true,
1482         /**
1483          * @event mouseout
1484          * Fires when the mouse exits this menu
1485          * @param {Roo.menu.Menu} this
1486          * @param {Roo.EventObject} e
1487          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1488          */
1489         mouseout : true,
1490         /**
1491          * @event itemclick
1492          * Fires when a menu item contained in this menu is clicked
1493          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494          * @param {Roo.EventObject} e
1495          */
1496         itemclick: true
1497     });
1498     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1499 };
1500
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1502     
1503    /// html : false,
1504     //align : '',
1505     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1506     type: false,
1507     /**
1508      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1509      */
1510     registerMenu : true,
1511     
1512     menuItems :false, // stores the menu items..
1513     
1514     hidden:true,
1515     
1516     parentMenu : false,
1517     
1518     getChildContainer : function() {
1519         return this.el;  
1520     },
1521     
1522     getAutoCreate : function(){
1523          
1524         //if (['right'].indexOf(this.align)!==-1) {
1525         //    cfg.cn[1].cls += ' pull-right'
1526         //}
1527         
1528         
1529         var cfg = {
1530             tag : 'ul',
1531             cls : 'dropdown-menu' ,
1532             style : 'z-index:1000'
1533             
1534         }
1535         
1536         if (this.type === 'submenu') {
1537             cfg.cls = 'submenu active';
1538         }
1539         if (this.type === 'treeview') {
1540             cfg.cls = 'treeview-menu';
1541         }
1542         
1543         return cfg;
1544     },
1545     initEvents : function() {
1546         
1547        // Roo.log("ADD event");
1548        // Roo.log(this.triggerEl.dom);
1549         this.triggerEl.on('click', this.onTriggerPress, this);
1550         this.triggerEl.addClass('dropdown-toggle');
1551         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1552
1553         this.el.on("mouseover", this.onMouseOver, this);
1554         this.el.on("mouseout", this.onMouseOut, this);
1555         
1556         
1557     },
1558     findTargetItem : function(e){
1559         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1560         if(!t){
1561             return false;
1562         }
1563         //Roo.log(t);         Roo.log(t.id);
1564         if(t && t.id){
1565             //Roo.log(this.menuitems);
1566             return this.menuitems.get(t.id);
1567             
1568             //return this.items.get(t.menuItemId);
1569         }
1570         
1571         return false;
1572     },
1573     onClick : function(e){
1574         Roo.log("menu.onClick");
1575         var t = this.findTargetItem(e);
1576         if(!t){
1577             return;
1578         }
1579         Roo.log(e);
1580         /*
1581         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1582             if(t == this.activeItem && t.shouldDeactivate(e)){
1583                 this.activeItem.deactivate();
1584                 delete this.activeItem;
1585                 return;
1586             }
1587             if(t.canActivate){
1588                 this.setActiveItem(t, true);
1589             }
1590             return;
1591             
1592             
1593         }
1594         */
1595         Roo.log('pass click event');
1596         
1597         t.onClick(e);
1598         
1599         this.fireEvent("click", this, t, e);
1600         
1601         this.hide();
1602     },
1603      onMouseOver : function(e){
1604         var t  = this.findTargetItem(e);
1605         //Roo.log(t);
1606         //if(t){
1607         //    if(t.canActivate && !t.disabled){
1608         //        this.setActiveItem(t, true);
1609         //    }
1610         //}
1611         
1612         this.fireEvent("mouseover", this, e, t);
1613     },
1614     isVisible : function(){
1615         return !this.hidden;
1616     },
1617      onMouseOut : function(e){
1618         var t  = this.findTargetItem(e);
1619         
1620         //if(t ){
1621         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1622         //        this.activeItem.deactivate();
1623         //        delete this.activeItem;
1624         //    }
1625         //}
1626         this.fireEvent("mouseout", this, e, t);
1627     },
1628     
1629     
1630     /**
1631      * Displays this menu relative to another element
1632      * @param {String/HTMLElement/Roo.Element} element The element to align to
1633      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634      * the element (defaults to this.defaultAlign)
1635      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1636      */
1637     show : function(el, pos, parentMenu){
1638         this.parentMenu = parentMenu;
1639         if(!this.el){
1640             this.render();
1641         }
1642         this.fireEvent("beforeshow", this);
1643         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1644     },
1645      /**
1646      * Displays this menu at a specific xy position
1647      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1649      */
1650     showAt : function(xy, parentMenu, /* private: */_e){
1651         this.parentMenu = parentMenu;
1652         if(!this.el){
1653             this.render();
1654         }
1655         if(_e !== false){
1656             this.fireEvent("beforeshow", this);
1657             
1658             //xy = this.el.adjustForConstraints(xy);
1659         }
1660         //this.el.setXY(xy);
1661         //this.el.show();
1662         this.hideMenuItems();
1663         this.hidden = false;
1664         this.triggerEl.addClass('open');
1665         this.focus();
1666         this.fireEvent("show", this);
1667     },
1668     
1669     focus : function(){
1670         return;
1671         if(!this.hidden){
1672             this.doFocus.defer(50, this);
1673         }
1674     },
1675
1676     doFocus : function(){
1677         if(!this.hidden){
1678             this.focusEl.focus();
1679         }
1680     },
1681
1682     /**
1683      * Hides this menu and optionally all parent menus
1684      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1685      */
1686     hide : function(deep){
1687         
1688         this.hideMenuItems();
1689         if(this.el && this.isVisible()){
1690             this.fireEvent("beforehide", this);
1691             if(this.activeItem){
1692                 this.activeItem.deactivate();
1693                 this.activeItem = null;
1694             }
1695             this.triggerEl.removeClass('open');;
1696             this.hidden = true;
1697             this.fireEvent("hide", this);
1698         }
1699         if(deep === true && this.parentMenu){
1700             this.parentMenu.hide(true);
1701         }
1702     },
1703     
1704     onTriggerPress  : function(e)
1705     {
1706         
1707         Roo.log('trigger press');
1708         //Roo.log(e.getTarget());
1709        // Roo.log(this.triggerEl.dom);
1710         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1711             return;
1712         }
1713         if (this.isVisible()) {
1714             Roo.log('hide');
1715             this.hide();
1716         } else {
1717             this.show(this.triggerEl, false, false);
1718         }
1719         
1720         
1721     },
1722     
1723          
1724        
1725     
1726     hideMenuItems : function()
1727     {
1728         //$(backdrop).remove()
1729         Roo.select('.open',true).each(function(aa) {
1730             
1731             aa.removeClass('open');
1732           //var parent = getParent($(this))
1733           //var relatedTarget = { relatedTarget: this }
1734           
1735            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736           //if (e.isDefaultPrevented()) return
1737            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1738         })
1739     },
1740     addxtypeChild : function (tree, cntr) {
1741         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1742           
1743         this.menuitems.add(comp);
1744         return comp;
1745
1746     },
1747     getEl : function()
1748     {
1749         Roo.log(this.el);
1750         return this.el;
1751     }
1752 });
1753
1754  
1755  /*
1756  * - LGPL
1757  *
1758  * menu item
1759  * 
1760  */
1761
1762
1763 /**
1764  * @class Roo.bootstrap.MenuItem
1765  * @extends Roo.bootstrap.Component
1766  * Bootstrap MenuItem class
1767  * @cfg {String} html the menu label
1768  * @cfg {String} href the link
1769  * @cfg {Boolean} preventDefault (true | false) default true
1770  * 
1771  * 
1772  * @constructor
1773  * Create a new MenuItem
1774  * @param {Object} config The config object
1775  */
1776
1777
1778 Roo.bootstrap.MenuItem = function(config){
1779     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1780     this.addEvents({
1781         // raw events
1782         /**
1783          * @event click
1784          * The raw click event for the entire grid.
1785          * @param {Roo.EventObject} e
1786          */
1787         "click" : true
1788     });
1789 };
1790
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1792     
1793     href : false,
1794     html : false,
1795     preventDefault: true,
1796     
1797     getAutoCreate : function(){
1798         var cfg= {
1799             tag: 'li',
1800             cls: 'dropdown-menu-item',
1801             cn: [
1802                     {
1803                         tag : 'a',
1804                         href : '#',
1805                         html : 'Link'
1806                     }
1807                 ]
1808         };
1809         if (this.parent().type == 'treeview') {
1810             cfg.cls = 'treeview-menu';
1811         }
1812         
1813         cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1815         return cfg;
1816     },
1817     
1818     initEvents: function() {
1819         
1820         //this.el.select('a').on('click', this.onClick, this);
1821         
1822     },
1823     onClick : function(e)
1824     {
1825         Roo.log('item on click ');
1826         //if(this.preventDefault){
1827         //    e.preventDefault();
1828         //}
1829         //this.parent().hideMenuItems();
1830         
1831         this.fireEvent('click', this, e);
1832     },
1833     getEl : function()
1834     {
1835         return this.el;
1836     }
1837 });
1838
1839  
1840
1841  /*
1842  * - LGPL
1843  *
1844  * menu separator
1845  * 
1846  */
1847
1848
1849 /**
1850  * @class Roo.bootstrap.MenuSeparator
1851  * @extends Roo.bootstrap.Component
1852  * Bootstrap MenuSeparator class
1853  * 
1854  * @constructor
1855  * Create a new MenuItem
1856  * @param {Object} config The config object
1857  */
1858
1859
1860 Roo.bootstrap.MenuSeparator = function(config){
1861     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1862 };
1863
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
1865     
1866     getAutoCreate : function(){
1867         var cfg = {
1868             cls: 'divider',
1869             tag : 'li'
1870         };
1871         
1872         return cfg;
1873     }
1874    
1875 });
1876
1877  
1878
1879  
1880 /*
1881 <div class="modal fade">
1882   <div class="modal-dialog">
1883     <div class="modal-content">
1884       <div class="modal-header">
1885         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1886         <h4 class="modal-title">Modal title</h4>
1887       </div>
1888       <div class="modal-body">
1889         <p>One fine body&hellip;</p>
1890       </div>
1891       <div class="modal-footer">
1892         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893         <button type="button" class="btn btn-primary">Save changes</button>
1894       </div>
1895     </div><!-- /.modal-content -->
1896   </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1898 */
1899 /*
1900  * - LGPL
1901  *
1902  * page contgainer.
1903  * 
1904  */
1905
1906 /**
1907  * @class Roo.bootstrap.Modal
1908  * @extends Roo.bootstrap.Component
1909  * Bootstrap Modal class
1910  * @cfg {String} title Title of dialog
1911  * @cfg {Boolean} specificTitle (true|false) default false
1912  * @cfg {Array} buttons Array of buttons or standard button set..
1913  * @cfg {String} buttonPosition (left|right|center) default right
1914  * 
1915  * @constructor
1916  * Create a new Modal Dialog
1917  * @param {Object} config The config object
1918  */
1919
1920 Roo.bootstrap.Modal = function(config){
1921     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1922     this.addEvents({
1923         // raw events
1924         /**
1925          * @event btnclick
1926          * The raw btnclick event for the button
1927          * @param {Roo.EventObject} e
1928          */
1929         "btnclick" : true
1930     });
1931     this.buttons = this.buttons || [];
1932 };
1933
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
1935     
1936     title : 'test dialog',
1937    
1938     buttons : false,
1939     
1940     // set on load...
1941     body:  false,
1942     
1943     specificTitle: false,
1944     
1945     buttonPosition: 'right',
1946     
1947     onRender : function(ct, position)
1948     {
1949         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1950      
1951         if(!this.el){
1952             var cfg = Roo.apply({},  this.getAutoCreate());
1953             cfg.id = Roo.id();
1954             //if(!cfg.name){
1955             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1956             //}
1957             //if (!cfg.name.length) {
1958             //    delete cfg.name;
1959            // }
1960             if (this.cls) {
1961                 cfg.cls += ' ' + this.cls;
1962             }
1963             if (this.style) {
1964                 cfg.style = this.style;
1965             }
1966             this.el = Roo.get(document.body).createChild(cfg, position);
1967         }
1968         //var type = this.el.dom.type;
1969         
1970         if(this.tabIndex !== undefined){
1971             this.el.dom.setAttribute('tabIndex', this.tabIndex);
1972         }
1973         
1974         
1975         
1976         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977         this.maskEl.enableDisplayMode("block");
1978         this.maskEl.hide();
1979         //this.el.addClass("x-dlg-modal");
1980     
1981         if (this.buttons.length) {
1982             Roo.each(this.buttons, function(bb) {
1983                 b = Roo.apply({}, bb);
1984                 b.xns = b.xns || Roo.bootstrap;
1985                 b.xtype = b.xtype || 'Button';
1986                 if (typeof(b.listeners) == 'undefined') {
1987                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
1988                 }
1989                 
1990                 var btn = Roo.factory(b);
1991                 
1992                 btn.onRender(this.el.select('.modal-footer div').first());
1993                 
1994             },this);
1995         }
1996         // render the children.
1997         var nitems = [];
1998         
1999         if(typeof(this.items) != 'undefined'){
2000             var items = this.items;
2001             delete this.items;
2002
2003             for(var i =0;i < items.length;i++) {
2004                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2005             }
2006         }
2007         
2008         this.items = nitems;
2009         
2010         this.body = this.el.select('.modal-body',true).first();
2011         this.close = this.el.select('.modal-header .close', true).first();
2012         this.footer = this.el.select('.modal-footer',true).first();
2013         this.initEvents();
2014         //this.el.addClass([this.fieldClass, this.cls]);
2015         
2016     },
2017     getAutoCreate : function(){
2018         
2019         
2020         var bdy = {
2021                 cls : 'modal-body',
2022                 html : this.html || ''
2023         };
2024         
2025         var title = {
2026             tag: 'h4',
2027             cls : 'modal-title',
2028             html : this.title
2029         };
2030         
2031         if(this.specificTitle){
2032             title = this.title;
2033         };
2034         
2035         return modal = {
2036             cls: "modal fade",
2037             style : 'display: none',
2038             cn : [
2039                 {
2040                     cls: "modal-dialog",
2041                     cn : [
2042                         {
2043                             cls : "modal-content",
2044                             cn : [
2045                                 {
2046                                     cls : 'modal-header',
2047                                     cn : [
2048                                         {
2049                                             tag: 'button',
2050                                             cls : 'close',
2051                                             html : '&times'
2052                                         },
2053                                         title
2054                                     ]
2055                                 },
2056                                 bdy,
2057                                 {
2058                                     cls : 'modal-footer',
2059                                     cn : [
2060                                         {
2061                                             tag: 'div',
2062                                             cls: 'btn-' + this.buttonPosition
2063                                         }
2064                                     ]
2065                                     
2066                                 }
2067                                 
2068                                 
2069                             ]
2070                             
2071                         }
2072                     ]
2073                         
2074                 }
2075             ]
2076             
2077             
2078         };
2079           
2080     },
2081     getChildContainer : function() {
2082          
2083          return this.el.select('.modal-body',true).first();
2084         
2085     },
2086     getButtonContainer : function() {
2087          return this.el.select('.modal-footer div',true).first();
2088         
2089     },
2090     initEvents : function()
2091     {
2092         this.el.select('.modal-header .close').on('click', this.hide, this);
2093 //        
2094 //        this.addxtype(this);
2095     },
2096     show : function() {
2097         
2098         if (!this.rendered) {
2099             this.render();
2100         }
2101        
2102         this.el.addClass('on');
2103         this.el.removeClass('fade');
2104         this.el.setStyle('display', 'block');
2105         Roo.get(document.body).addClass("x-body-masked");
2106         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2107         this.maskEl.show();
2108         this.el.setStyle('zIndex', '10001');
2109         this.fireEvent('show', this);
2110         
2111         
2112     },
2113     hide : function()
2114     {
2115         Roo.log('Modal hide?!');
2116         this.maskEl.hide();
2117         Roo.get(document.body).removeClass("x-body-masked");
2118         this.el.removeClass('on');
2119         this.el.addClass('fade');
2120         this.el.setStyle('display', 'none');
2121         this.fireEvent('hide', this);
2122     },
2123     
2124     addButton : function(str, cb)
2125     {
2126          
2127         
2128         var b = Roo.apply({}, { html : str } );
2129         b.xns = b.xns || Roo.bootstrap;
2130         b.xtype = b.xtype || 'Button';
2131         if (typeof(b.listeners) == 'undefined') {
2132             b.listeners = { click : cb.createDelegate(this)  };
2133         }
2134         
2135         var btn = Roo.factory(b);
2136            
2137         btn.onRender(this.el.select('.modal-footer div').first());
2138         
2139         return btn;   
2140        
2141     },
2142     
2143     setDefaultButton : function(btn)
2144     {
2145         //this.el.select('.modal-footer').()
2146     },
2147     resizeTo: function(w,h)
2148     {
2149         // skip..
2150     },
2151     setContentSize  : function(w, h)
2152     {
2153         
2154     },
2155     onButtonClick: function(btn,e)
2156     {
2157         //Roo.log([a,b,c]);
2158         this.fireEvent('btnclick', btn.name, e);
2159     },
2160     setTitle: function(str) {
2161         this.el.select('.modal-title',true).first().dom.innerHTML = str;
2162         
2163     }
2164 });
2165
2166
2167 Roo.apply(Roo.bootstrap.Modal,  {
2168     /**
2169          * Button config that displays a single OK button
2170          * @type Object
2171          */
2172         OK :  [{
2173             name : 'ok',
2174             weight : 'primary',
2175             html : 'OK'
2176         }], 
2177         /**
2178          * Button config that displays Yes and No buttons
2179          * @type Object
2180          */
2181         YESNO : [
2182             {
2183                 name  : 'no',
2184                 html : 'No'
2185             },
2186             {
2187                 name  :'yes',
2188                 weight : 'primary',
2189                 html : 'Yes'
2190             }
2191         ],
2192         
2193         /**
2194          * Button config that displays OK and Cancel buttons
2195          * @type Object
2196          */
2197         OKCANCEL : [
2198             {
2199                name : 'cancel',
2200                 html : 'Cancel'
2201             },
2202             {
2203                 name : 'ok',
2204                 weight : 'primary',
2205                 html : 'OK'
2206             }
2207         ],
2208         /**
2209          * Button config that displays Yes, No and Cancel buttons
2210          * @type Object
2211          */
2212         YESNOCANCEL : [
2213             {
2214                 name : 'yes',
2215                 weight : 'primary',
2216                 html : 'Yes'
2217             },
2218             {
2219                 name : 'no',
2220                 html : 'No'
2221             },
2222             {
2223                 name : 'cancel',
2224                 html : 'Cancel'
2225             }
2226         ]
2227 });
2228  /*
2229  * - LGPL
2230  *
2231  * messagebox - can be used as a replace
2232  * 
2233  */
2234 /**
2235  * @class Roo.MessageBox
2236  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2237  * Example usage:
2238  *<pre><code>
2239 // Basic alert:
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2241
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2244     if (btn == 'ok'){
2245         // process text value...
2246     }
2247 });
2248
2249 // Show a dialog using config options:
2250 Roo.Msg.show({
2251    title:'Save Changes?',
2252    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253    buttons: Roo.Msg.YESNOCANCEL,
2254    fn: processResult,
2255    animEl: 'elId'
2256 });
2257 </code></pre>
2258  * @singleton
2259  */
2260 Roo.bootstrap.MessageBox = function(){
2261     var dlg, opt, mask, waitTimer;
2262     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263     var buttons, activeTextEl, bwidth;
2264
2265     
2266     // private
2267     var handleButton = function(button){
2268         dlg.hide();
2269         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2270     };
2271
2272     // private
2273     var handleHide = function(){
2274         if(opt && opt.cls){
2275             dlg.el.removeClass(opt.cls);
2276         }
2277         //if(waitTimer){
2278         //    Roo.TaskMgr.stop(waitTimer);
2279         //    waitTimer = null;
2280         //}
2281     };
2282
2283     // private
2284     var updateButtons = function(b){
2285         var width = 0;
2286         if(!b){
2287             buttons["ok"].hide();
2288             buttons["cancel"].hide();
2289             buttons["yes"].hide();
2290             buttons["no"].hide();
2291             //dlg.footer.dom.style.display = 'none';
2292             return width;
2293         }
2294         dlg.footer.dom.style.display = '';
2295         for(var k in buttons){
2296             if(typeof buttons[k] != "function"){
2297                 if(b[k]){
2298                     buttons[k].show();
2299                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300                     width += buttons[k].el.getWidth()+15;
2301                 }else{
2302                     buttons[k].hide();
2303                 }
2304             }
2305         }
2306         return width;
2307     };
2308
2309     // private
2310     var handleEsc = function(d, k, e){
2311         if(opt && opt.closable !== false){
2312             dlg.hide();
2313         }
2314         if(e){
2315             e.stopEvent();
2316         }
2317     };
2318
2319     return {
2320         /**
2321          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322          * @return {Roo.BasicDialog} The BasicDialog element
2323          */
2324         getDialog : function(){
2325            if(!dlg){
2326                 dlg = new Roo.bootstrap.Modal( {
2327                     //draggable: true,
2328                     //resizable:false,
2329                     //constraintoviewport:false,
2330                     //fixedcenter:true,
2331                     //collapsible : false,
2332                     //shim:true,
2333                     //modal: true,
2334                   //  width:400,
2335                   //  height:100,
2336                     //buttonAlign:"center",
2337                     closeClick : function(){
2338                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2339                             handleButton("no");
2340                         }else{
2341                             handleButton("cancel");
2342                         }
2343                     }
2344                 });
2345                 dlg.render();
2346                 dlg.on("hide", handleHide);
2347                 mask = dlg.mask;
2348                 //dlg.addKeyListener(27, handleEsc);
2349                 buttons = {};
2350                 this.buttons = buttons;
2351                 var bt = this.buttonText;
2352                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2356                 Roo.log(buttons)
2357                 bodyEl = dlg.body.createChild({
2358
2359                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360                         '<textarea class="roo-mb-textarea"></textarea>' +
2361                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2362                 });
2363                 msgEl = bodyEl.dom.firstChild;
2364                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365                 textboxEl.enableDisplayMode();
2366                 textboxEl.addKeyListener([10,13], function(){
2367                     if(dlg.isVisible() && opt && opt.buttons){
2368                         if(opt.buttons.ok){
2369                             handleButton("ok");
2370                         }else if(opt.buttons.yes){
2371                             handleButton("yes");
2372                         }
2373                     }
2374                 });
2375                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376                 textareaEl.enableDisplayMode();
2377                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378                 progressEl.enableDisplayMode();
2379                 var pf = progressEl.dom.firstChild;
2380                 if (pf) {
2381                     pp = Roo.get(pf.firstChild);
2382                     pp.setHeight(pf.offsetHeight);
2383                 }
2384                 
2385             }
2386             return dlg;
2387         },
2388
2389         /**
2390          * Updates the message box body text
2391          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392          * the XHTML-compliant non-breaking space character '&amp;#160;')
2393          * @return {Roo.MessageBox} This message box
2394          */
2395         updateText : function(text){
2396             if(!dlg.isVisible() && !opt.width){
2397                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2398             }
2399             msgEl.innerHTML = text || '&#160;';
2400       
2401             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2403             var w = Math.max(
2404                     Math.min(opt.width || cw , this.maxWidth), 
2405                     Math.max(opt.minWidth || this.minWidth, bwidth)
2406             );
2407             if(opt.prompt){
2408                 activeTextEl.setWidth(w);
2409             }
2410             if(dlg.isVisible()){
2411                 dlg.fixedcenter = false;
2412             }
2413             // to big, make it scroll. = But as usual stupid IE does not support
2414             // !important..
2415             
2416             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2419             } else {
2420                 bodyEl.dom.style.height = '';
2421                 bodyEl.dom.style.overflowY = '';
2422             }
2423             if (cw > w) {
2424                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2425             } else {
2426                 bodyEl.dom.style.overflowX = '';
2427             }
2428             
2429             dlg.setContentSize(w, bodyEl.getHeight());
2430             if(dlg.isVisible()){
2431                 dlg.fixedcenter = true;
2432             }
2433             return this;
2434         },
2435
2436         /**
2437          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2438          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441          * @return {Roo.MessageBox} This message box
2442          */
2443         updateProgress : function(value, text){
2444             if(text){
2445                 this.updateText(text);
2446             }
2447             if (pp) { // weird bug on my firefox - for some reason this is not defined
2448                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2449             }
2450             return this;
2451         },        
2452
2453         /**
2454          * Returns true if the message box is currently displayed
2455          * @return {Boolean} True if the message box is visible, else false
2456          */
2457         isVisible : function(){
2458             return dlg && dlg.isVisible();  
2459         },
2460
2461         /**
2462          * Hides the message box if it is displayed
2463          */
2464         hide : function(){
2465             if(this.isVisible()){
2466                 dlg.hide();
2467             }  
2468         },
2469
2470         /**
2471          * Displays a new message box, or reinitializes an existing message box, based on the config options
2472          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473          * The following config object properties are supported:
2474          * <pre>
2475 Property    Type             Description
2476 ----------  ---------------  ------------------------------------------------------------------------------------
2477 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2478                                    closes (defaults to undefined)
2479 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2482                                    progress and wait dialogs will ignore this property and always hide the
2483                                    close button as they can only be closed programmatically.
2484 cls               String           A custom CSS class to apply to the message box element
2485 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2486                                    displayed (defaults to 75)
2487 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2488                                    function will be btn (the name of the button that was clicked, if applicable,
2489                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2490                                    Progress and wait dialogs will ignore this option since they do not respond to
2491                                    user actions and can only be closed programmatically, so any required function
2492                                    should be called by the same code after it closes the dialog.
2493 icon              String           A CSS class that provides a background image to be used as an icon for
2494                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2496 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2497 modal             Boolean          False to allow user interaction with the page while the message box is
2498                                    displayed (defaults to true)
2499 msg               String           A string that will replace the existing message box body text (defaults
2500                                    to the XHTML-compliant non-breaking space character '&#160;')
2501 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2502 progress          Boolean          True to display a progress bar (defaults to false)
2503 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2506 title             String           The title text
2507 value             String           The string value to set into the active textbox element if displayed
2508 wait              Boolean          True to display a progress bar (defaults to false)
2509 width             Number           The width of the dialog in pixels
2510 </pre>
2511          *
2512          * Example usage:
2513          * <pre><code>
2514 Roo.Msg.show({
2515    title: 'Address',
2516    msg: 'Please enter your address:',
2517    width: 300,
2518    buttons: Roo.MessageBox.OKCANCEL,
2519    multiline: true,
2520    fn: saveAddress,
2521    animEl: 'addAddressBtn'
2522 });
2523 </code></pre>
2524          * @param {Object} config Configuration options
2525          * @return {Roo.MessageBox} This message box
2526          */
2527         show : function(options)
2528         {
2529             
2530             // this causes nightmares if you show one dialog after another
2531             // especially on callbacks..
2532              
2533             if(this.isVisible()){
2534                 
2535                 this.hide();
2536                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2538                 Roo.log("New Dialog Message:" +  options.msg )
2539                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2541                 
2542             }
2543             var d = this.getDialog();
2544             opt = options;
2545             d.setTitle(opt.title || "&#160;");
2546             d.close.setDisplayed(opt.closable !== false);
2547             activeTextEl = textboxEl;
2548             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2549             if(opt.prompt){
2550                 if(opt.multiline){
2551                     textboxEl.hide();
2552                     textareaEl.show();
2553                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2554                         opt.multiline : this.defaultTextHeight);
2555                     activeTextEl = textareaEl;
2556                 }else{
2557                     textboxEl.show();
2558                     textareaEl.hide();
2559                 }
2560             }else{
2561                 textboxEl.hide();
2562                 textareaEl.hide();
2563             }
2564             progressEl.setDisplayed(opt.progress === true);
2565             this.updateProgress(0);
2566             activeTextEl.dom.value = opt.value || "";
2567             if(opt.prompt){
2568                 dlg.setDefaultButton(activeTextEl);
2569             }else{
2570                 var bs = opt.buttons;
2571                 var db = null;
2572                 if(bs && bs.ok){
2573                     db = buttons["ok"];
2574                 }else if(bs && bs.yes){
2575                     db = buttons["yes"];
2576                 }
2577                 dlg.setDefaultButton(db);
2578             }
2579             bwidth = updateButtons(opt.buttons);
2580             this.updateText(opt.msg);
2581             if(opt.cls){
2582                 d.el.addClass(opt.cls);
2583             }
2584             d.proxyDrag = opt.proxyDrag === true;
2585             d.modal = opt.modal !== false;
2586             d.mask = opt.modal !== false ? mask : false;
2587             if(!d.isVisible()){
2588                 // force it to the end of the z-index stack so it gets a cursor in FF
2589                 document.body.appendChild(dlg.el.dom);
2590                 d.animateTarget = null;
2591                 d.show(options.animEl);
2592             }
2593             return this;
2594         },
2595
2596         /**
2597          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2598          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599          * and closing the message box when the process is complete.
2600          * @param {String} title The title bar text
2601          * @param {String} msg The message box body text
2602          * @return {Roo.MessageBox} This message box
2603          */
2604         progress : function(title, msg){
2605             this.show({
2606                 title : title,
2607                 msg : msg,
2608                 buttons: false,
2609                 progress:true,
2610                 closable:false,
2611                 minWidth: this.minProgressWidth,
2612                 modal : true
2613             });
2614             return this;
2615         },
2616
2617         /**
2618          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619          * If a callback function is passed it will be called after the user clicks the button, and the
2620          * id of the button that was clicked will be passed as the only parameter to the callback
2621          * (could also be the top-right close button).
2622          * @param {String} title The title bar text
2623          * @param {String} msg The message box body text
2624          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625          * @param {Object} scope (optional) The scope of the callback function
2626          * @return {Roo.MessageBox} This message box
2627          */
2628         alert : function(title, msg, fn, scope){
2629             this.show({
2630                 title : title,
2631                 msg : msg,
2632                 buttons: this.OK,
2633                 fn: fn,
2634                 scope : scope,
2635                 modal : true
2636             });
2637             return this;
2638         },
2639
2640         /**
2641          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2642          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643          * You are responsible for closing the message box when the process is complete.
2644          * @param {String} msg The message box body text
2645          * @param {String} title (optional) The title bar text
2646          * @return {Roo.MessageBox} This message box
2647          */
2648         wait : function(msg, title){
2649             this.show({
2650                 title : title,
2651                 msg : msg,
2652                 buttons: false,
2653                 closable:false,
2654                 progress:true,
2655                 modal:true,
2656                 width:300,
2657                 wait:true
2658             });
2659             waitTimer = Roo.TaskMgr.start({
2660                 run: function(i){
2661                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2662                 },
2663                 interval: 1000
2664             });
2665             return this;
2666         },
2667
2668         /**
2669          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672          * @param {String} title The title bar text
2673          * @param {String} msg The message box body text
2674          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675          * @param {Object} scope (optional) The scope of the callback function
2676          * @return {Roo.MessageBox} This message box
2677          */
2678         confirm : function(title, msg, fn, scope){
2679             this.show({
2680                 title : title,
2681                 msg : msg,
2682                 buttons: this.YESNO,
2683                 fn: fn,
2684                 scope : scope,
2685                 modal : true
2686             });
2687             return this;
2688         },
2689
2690         /**
2691          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2693          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694          * (could also be the top-right close button) and the text that was entered will be passed as the two
2695          * parameters to the callback.
2696          * @param {String} title The title bar text
2697          * @param {String} msg The message box body text
2698          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699          * @param {Object} scope (optional) The scope of the callback function
2700          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702          * @return {Roo.MessageBox} This message box
2703          */
2704         prompt : function(title, msg, fn, scope, multiline){
2705             this.show({
2706                 title : title,
2707                 msg : msg,
2708                 buttons: this.OKCANCEL,
2709                 fn: fn,
2710                 minWidth:250,
2711                 scope : scope,
2712                 prompt:true,
2713                 multiline: multiline,
2714                 modal : true
2715             });
2716             return this;
2717         },
2718
2719         /**
2720          * Button config that displays a single OK button
2721          * @type Object
2722          */
2723         OK : {ok:true},
2724         /**
2725          * Button config that displays Yes and No buttons
2726          * @type Object
2727          */
2728         YESNO : {yes:true, no:true},
2729         /**
2730          * Button config that displays OK and Cancel buttons
2731          * @type Object
2732          */
2733         OKCANCEL : {ok:true, cancel:true},
2734         /**
2735          * Button config that displays Yes, No and Cancel buttons
2736          * @type Object
2737          */
2738         YESNOCANCEL : {yes:true, no:true, cancel:true},
2739
2740         /**
2741          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2742          * @type Number
2743          */
2744         defaultTextHeight : 75,
2745         /**
2746          * The maximum width in pixels of the message box (defaults to 600)
2747          * @type Number
2748          */
2749         maxWidth : 600,
2750         /**
2751          * The minimum width in pixels of the message box (defaults to 100)
2752          * @type Number
2753          */
2754         minWidth : 100,
2755         /**
2756          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
2757          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2758          * @type Number
2759          */
2760         minProgressWidth : 250,
2761         /**
2762          * An object containing the default button text strings that can be overriden for localized language support.
2763          * Supported properties are: ok, cancel, yes and no.
2764          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2765          * @type Object
2766          */
2767         buttonText : {
2768             ok : "OK",
2769             cancel : "Cancel",
2770             yes : "Yes",
2771             no : "No"
2772         }
2773     };
2774 }();
2775
2776 /**
2777  * Shorthand for {@link Roo.MessageBox}
2778  */
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox 
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2781 /*
2782  * - LGPL
2783  *
2784  * navbar
2785  * 
2786  */
2787
2788 /**
2789  * @class Roo.bootstrap.Navbar
2790  * @extends Roo.bootstrap.Component
2791  * Bootstrap Navbar class
2792
2793  * @constructor
2794  * Create a new Navbar
2795  * @param {Object} config The config object
2796  */
2797
2798
2799 Roo.bootstrap.Navbar = function(config){
2800     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2801     
2802 };
2803
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
2805     
2806     
2807    
2808     // private
2809     navItems : false,
2810     loadMask : false,
2811     
2812     
2813     getAutoCreate : function(){
2814         
2815         
2816         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2817         
2818     },
2819     
2820     initEvents :function ()
2821     {
2822         //Roo.log(this.el.select('.navbar-toggle',true));
2823         this.el.select('.navbar-toggle',true).on('click', function() {
2824            // Roo.log('click');
2825             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
2826         }, this);
2827         
2828         var mark = {
2829             tag: "div",
2830             cls:"x-dlg-mask"
2831         }
2832         
2833         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2834         
2835         var size = this.el.getSize();
2836         this.maskEl.setSize(size.width, size.height);
2837         this.maskEl.enableDisplayMode("block");
2838         this.maskEl.hide();
2839         
2840         if(this.loadMask){
2841             this.maskEl.show();
2842         }
2843     },
2844     
2845     
2846     getChildContainer : function()
2847     {
2848         if (this.el.select('.collapse').getCount()) {
2849             return this.el.select('.collapse',true).first();
2850         }
2851         
2852         return this.el;
2853     },
2854     
2855     mask : function()
2856     {
2857         this.maskEl.show();
2858     },
2859     
2860     unmask : function()
2861     {
2862         this.maskEl.hide();
2863     } 
2864     
2865     
2866     
2867     
2868 });
2869
2870
2871
2872  
2873
2874  /*
2875  * - LGPL
2876  *
2877  * navbar
2878  * 
2879  */
2880
2881 /**
2882  * @class Roo.bootstrap.NavSimplebar
2883  * @extends Roo.bootstrap.Navbar
2884  * Bootstrap Sidebar class
2885  *
2886  * @cfg {Boolean} inverse is inverted color
2887  * 
2888  * @cfg {String} type (nav | pills | tabs)
2889  * @cfg {Boolean} arrangement stacked | justified
2890  * @cfg {String} align (left | right) alignment
2891  * 
2892  * @cfg {Boolean} main (true|false) main nav bar? default false
2893  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2894  * 
2895  * @cfg {String} tag (header|footer|nav|div) default is nav 
2896
2897  * 
2898  * 
2899  * 
2900  * @constructor
2901  * Create a new Sidebar
2902  * @param {Object} config The config object
2903  */
2904
2905
2906 Roo.bootstrap.NavSimplebar = function(config){
2907     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2908 };
2909
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
2911     
2912     inverse: false,
2913     
2914     type: false,
2915     arrangement: '',
2916     align : false,
2917     
2918     
2919     
2920     main : false,
2921     
2922     
2923     tag : false,
2924     
2925     
2926     getAutoCreate : function(){
2927         
2928         
2929         var cfg = {
2930             tag : this.tag || 'div',
2931             cls : 'navbar'
2932         };
2933           
2934         
2935         cfg.cn = [
2936             {
2937                 cls: 'nav',
2938                 tag : 'ul'
2939             }
2940         ];
2941         
2942          
2943         this.type = this.type || 'nav';
2944         if (['tabs','pills'].indexOf(this.type)!==-1) {
2945             cfg.cn[0].cls += ' nav-' + this.type
2946         
2947         
2948         } else {
2949             if (this.type!=='nav') {
2950                 Roo.log('nav type must be nav/tabs/pills')
2951             }
2952             cfg.cn[0].cls += ' navbar-nav'
2953         }
2954         
2955         
2956         
2957         
2958         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959             cfg.cn[0].cls += ' nav-' + this.arrangement;
2960         }
2961         
2962         
2963         if (this.align === 'right') {
2964             cfg.cn[0].cls += ' navbar-right';
2965         }
2966         
2967         if (this.inverse) {
2968             cfg.cls += ' navbar-inverse';
2969             
2970         }
2971         
2972         
2973         return cfg;
2974     
2975         
2976     }
2977     
2978     
2979     
2980 });
2981
2982
2983
2984  
2985
2986  
2987        /*
2988  * - LGPL
2989  *
2990  * navbar
2991  * 
2992  */
2993
2994 /**
2995  * @class Roo.bootstrap.NavHeaderbar
2996  * @extends Roo.bootstrap.NavSimplebar
2997  * Bootstrap Sidebar class
2998  *
2999  * @cfg {String} brand what is brand
3000  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001  * @cfg {String} brand_href href of the brand
3002  * @cfg {Boolean} srButton generate the sr-only button (true | false) default true
3003  * 
3004  * @constructor
3005  * Create a new Sidebar
3006  * @param {Object} config The config object
3007  */
3008
3009
3010 Roo.bootstrap.NavHeaderbar = function(config){
3011     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3012 };
3013
3014 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3015     
3016     position: '',
3017     brand: '',
3018     brand_href: false,
3019     srButton : true,
3020     
3021     
3022     getAutoCreate : function(){
3023         
3024         var   cfg = {
3025             tag: this.nav || 'nav',
3026             cls: 'navbar',
3027             role: 'navigation',
3028             cn: []
3029         };
3030         
3031         if(this.srButton){
3032             cfg.cn.push({
3033                 tag: 'div',
3034                 cls: 'navbar-header',
3035                 cn: [
3036                     {
3037                         tag: 'button',
3038                         type: 'button',
3039                         cls: 'navbar-toggle',
3040                         'data-toggle': 'collapse',
3041                         cn: [
3042                             {
3043                                 tag: 'span',
3044                                 cls: 'sr-only',
3045                                 html: 'Toggle navigation'
3046                             },
3047                             {
3048                                 tag: 'span',
3049                                 cls: 'icon-bar'
3050                             },
3051                             {
3052                                 tag: 'span',
3053                                 cls: 'icon-bar'
3054                             },
3055                             {
3056                                 tag: 'span',
3057                                 cls: 'icon-bar'
3058                             }
3059                         ]
3060                     }
3061                 ]
3062             });
3063         }
3064         
3065         cfg.cn.push({
3066             tag: 'div',
3067             cls: 'collapse navbar-collapse',
3068             cn : []
3069         });
3070         
3071         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3072         
3073         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3074             cfg.cls += ' navbar-' + this.position;
3075             
3076             // tag can override this..
3077             
3078             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3079         }
3080         
3081         if (this.brand !== '') {
3082             cfg.cn[0].cn.push({
3083                 tag: 'a',
3084                 href: this.brand_href ? this.brand_href : '#',
3085                 cls: 'navbar-brand',
3086                 cn: [
3087                 this.brand
3088                 ]
3089             });
3090         }
3091         
3092         if(this.main){
3093             cfg.cls += ' main-nav';
3094         }
3095         
3096         
3097         return cfg;
3098
3099         
3100     }
3101     
3102     
3103     
3104 });
3105
3106
3107
3108  
3109
3110  /*
3111  * - LGPL
3112  *
3113  * navbar
3114  * 
3115  */
3116
3117 /**
3118  * @class Roo.bootstrap.NavSidebar
3119  * @extends Roo.bootstrap.Navbar
3120  * Bootstrap Sidebar class
3121  * 
3122  * @constructor
3123  * Create a new Sidebar
3124  * @param {Object} config The config object
3125  */
3126
3127
3128 Roo.bootstrap.NavSidebar = function(config){
3129     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3130 };
3131
3132 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3133     
3134     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3135     
3136     getAutoCreate : function(){
3137         
3138         
3139         return  {
3140             tag: 'div',
3141             cls: 'sidebar sidebar-nav'
3142         };
3143     
3144         
3145     }
3146     
3147     
3148     
3149 });
3150
3151
3152
3153  
3154
3155  /*
3156  * - LGPL
3157  *
3158  * nav group
3159  * 
3160  */
3161
3162 /**
3163  * @class Roo.bootstrap.NavGroup
3164  * @extends Roo.bootstrap.Component
3165  * Bootstrap NavGroup class
3166  * @cfg {String} align left | right
3167  * @cfg {Boolean} inverse false | true
3168  * @cfg {String} type (nav|pills|tab) default nav
3169  * @cfg {String} navId - reference Id for navbar.
3170
3171  * 
3172  * @constructor
3173  * Create a new nav group
3174  * @param {Object} config The config object
3175  */
3176
3177 Roo.bootstrap.NavGroup = function(config){
3178     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3179     this.navItems = [];
3180     Roo.bootstrap.NavGroup.register(this);
3181      this.addEvents({
3182         /**
3183              * @event changed
3184              * Fires when the active item changes
3185              * @param {Roo.bootstrap.NavGroup} this
3186              * @param {Roo.bootstrap.Navbar.Item} item The item selected
3187              * @param {Roo.bootstrap.Navbar.Item} item The previously selected item 
3188          */
3189         'changed': true
3190      });
3191     
3192 };
3193
3194 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3195     
3196     align: '',
3197     inverse: false,
3198     form: false,
3199     type: 'nav',
3200     navId : '',
3201     // private
3202     
3203     navItems : false,
3204     
3205     getAutoCreate : function()
3206     {
3207         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3208         
3209         cfg = {
3210             tag : 'ul',
3211             cls: 'nav' 
3212         }
3213         
3214         if (['tabs','pills'].indexOf(this.type)!==-1) {
3215             cfg.cls += ' nav-' + this.type
3216         } else {
3217             if (this.type!=='nav') {
3218                 Roo.log('nav type must be nav/tabs/pills')
3219             }
3220             cfg.cls += ' navbar-nav'
3221         }
3222         
3223         if (this.parent().sidebar) {
3224             cfg = {
3225                 tag: 'ul',
3226                 cls: 'dashboard-menu sidebar-menu'
3227             }
3228             
3229             return cfg;
3230         }
3231         
3232         if (this.form === true) {
3233             cfg = {
3234                 tag: 'form',
3235                 cls: 'navbar-form'
3236             }
3237             
3238             if (this.align === 'right') {
3239                 cfg.cls += ' navbar-right';
3240             } else {
3241                 cfg.cls += ' navbar-left';
3242             }
3243         }
3244         
3245         if (this.align === 'right') {
3246             cfg.cls += ' navbar-right';
3247         }
3248         
3249         if (this.inverse) {
3250             cfg.cls += ' navbar-inverse';
3251             
3252         }
3253         
3254         
3255         return cfg;
3256     },
3257     
3258     setActiveItem : function(item)
3259     {
3260         var prev = false;
3261         Roo.each(this.navItems, function(v){
3262             if (v == item) {
3263                 return ;
3264             }
3265             if (v.isActive()) {
3266                 v.setActive(false, true);
3267                 prev = v;
3268                 
3269             }
3270             
3271         });
3272
3273         item.setActive(true, true);
3274         this.fireEvent('changed', this, item, prev);
3275         
3276         
3277     },
3278     
3279     addItem : function(cfg)
3280     {
3281         var cn = new Roo.bootstrap.NavItem(cfg);
3282         this.register(cn);
3283         cn.parentId = this.id;
3284         cn.onRender(this.el, null);
3285         return cn;
3286     },
3287     
3288     register : function(item)
3289     {
3290         this.navItems.push( item);
3291         item.navId = this.navId;
3292     
3293     },
3294     getNavItem: function(tabId)
3295     {
3296         var ret = false;
3297         Roo.each(this.navItems, function(e) {
3298             if (e.tabId == tabId) {
3299                ret =  e;
3300                return false;
3301             }
3302             return true;
3303             
3304         });
3305         return ret;
3306     }
3307     
3308     
3309     
3310     
3311 });
3312
3313  
3314 Roo.apply(Roo.bootstrap.NavGroup, {
3315     
3316     groups: {},
3317     
3318     register : function(navgrp)
3319     {
3320         this.groups[navgrp.navId] = navgrp;
3321         
3322     },
3323     get: function(navId) {
3324         return this.groups[navId];
3325     }
3326     
3327     
3328     
3329 });
3330
3331  /*
3332  * - LGPL
3333  *
3334  * row
3335  * 
3336  */
3337
3338 /**
3339  * @class Roo.bootstrap.NavItem
3340  * @extends Roo.bootstrap.Component
3341  * Bootstrap Navbar.NavItem class
3342  * @cfg {String} href  link to
3343  * @cfg {String} html content of button
3344  * @cfg {String} badge text inside badge
3345  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3346  * @cfg {String} glyphicon name of glyphicon
3347  * @cfg {String} icon name of font awesome icon
3348  * @cfg {Boolean} active Is item active
3349  * @cfg {Boolean} disabled Is item disabled
3350  
3351  * @cfg {Boolean} preventDefault (true | false) default false
3352  * @cfg {String} tabId the tab that this item activates.
3353  * @cfg {String} tagtype (a|span) render as a href or span?
3354   
3355  * @constructor
3356  * Create a new Navbar Item
3357  * @param {Object} config The config object
3358  */
3359 Roo.bootstrap.NavItem = function(config){
3360     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3361     this.addEvents({
3362         // raw events
3363         /**
3364          * @event click
3365          * The raw click event for the entire grid.
3366          * @param {Roo.EventObject} e
3367          */
3368         "click" : true,
3369          /**
3370             * @event changed
3371             * Fires when the active item active state changes
3372             * @param {Roo.bootstrap.NavItem} this
3373             * @param {boolean} state the new state
3374              
3375          */
3376         'changed': true
3377     });
3378    
3379 };
3380
3381 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3382     
3383     href: false,
3384     html: '',
3385     badge: '',
3386     icon: false,
3387     glyphicon: false,
3388     active: false,
3389     preventDefault : false,
3390     tabId : false,
3391     tagtype : 'a',
3392     disabled : false,
3393     
3394     getAutoCreate : function(){
3395          
3396         var cfg = {
3397             tag: 'li',
3398             cls: 'nav-item'
3399             
3400         }
3401         if (this.active) {
3402             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3403         }
3404         if (this.disabled) {
3405             cfg.cls += ' disabled';
3406         }
3407         
3408         if (this.href || this.html || this.glyphicon || this.icon) {
3409             cfg.cn = [
3410                 {
3411                     tag: this.tagtype,
3412                     href : this.href || "#",
3413                     html: this.html || ''
3414                 }
3415             ];
3416             
3417             if (this.icon) {
3418                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3419             }
3420
3421             if(this.glyphicon) {
3422                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3423             }
3424             
3425             if (this.menu) {
3426                 
3427                 cfg.cn[0].html += " <span class='caret'></span>";
3428              
3429             }
3430             
3431             if (this.badge !== '') {
3432                  
3433                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3434             }
3435         }
3436         
3437         
3438         
3439         return cfg;
3440     },
3441     initEvents: function() {
3442        // Roo.log('init events?');
3443        // Roo.log(this.el.dom);
3444         if (typeof (this.menu) != 'undefined') {
3445             this.menu.parentType = this.xtype;
3446             this.menu.triggerEl = this.el;
3447             this.addxtype(Roo.apply({}, this.menu));
3448         }
3449
3450        
3451         this.el.select('a',true).on('click', this.onClick, this);
3452         // at this point parent should be available..
3453         this.parent().register(this);
3454     },
3455     
3456     onClick : function(e)
3457     {
3458          
3459         if(this.preventDefault){
3460             e.preventDefault();
3461         }
3462         if (this.disabled) {
3463             return;
3464         }
3465         Roo.log("fire event clicked");
3466         if(this.fireEvent('click', this, e) === false){
3467             return;
3468         };
3469         
3470         if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3471             if (typeof(this.parent().setActiveItem) !== 'undefined') {
3472                 this.parent().setActiveItem(this);
3473             }
3474             
3475             
3476             
3477         } 
3478     },
3479     
3480     isActive: function () {
3481         return this.active
3482     },
3483     setActive : function(state, fire)
3484     {
3485         this.active = state;
3486         if (!state ) {
3487             this.el.removeClass('active');
3488         } else if (!this.el.hasClass('active')) {
3489             this.el.addClass('active');
3490         }
3491         if (fire) {
3492             this.fireEvent('changed', this, state);
3493         }
3494         
3495         
3496     },
3497      // this should not be here...
3498     setDisabled : function(state)
3499     {
3500         this.disabled = state;
3501         if (!state ) {
3502             this.el.removeClass('disabled');
3503         } else if (!this.el.hasClass('disabled')) {
3504             this.el.addClass('disabled');
3505         }
3506         
3507     }
3508 });
3509  
3510
3511  /*
3512  * - LGPL
3513  *
3514  * sidebar item
3515  *
3516  *  li
3517  *    <span> icon </span>
3518  *    <span> text </span>
3519  *    <span>badge </span>
3520  */
3521
3522 /**
3523  * @class Roo.bootstrap.NavSidebarItem
3524  * @extends Roo.bootstrap.NavItem
3525  * Bootstrap Navbar.NavSidebarItem class
3526  * @constructor
3527  * Create a new Navbar Button
3528  * @param {Object} config The config object
3529  */
3530 Roo.bootstrap.NavSidebarItem = function(config){
3531     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3532     this.addEvents({
3533         // raw events
3534         /**
3535          * @event click
3536          * The raw click event for the entire grid.
3537          * @param {Roo.EventObject} e
3538          */
3539         "click" : true,
3540          /**
3541             * @event changed
3542             * Fires when the active item active state changes
3543             * @param {Roo.bootstrap.NavSidebarItem} this
3544             * @param {boolean} state the new state
3545              
3546          */
3547         'changed': true
3548     });
3549    
3550 };
3551
3552 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
3553     
3554     
3555     getAutoCreate : function(){
3556         
3557         
3558         var a = {
3559                 tag: 'a',
3560                 href : this.href || '#',
3561                 cls: '',
3562                 html : '',
3563                 cn : []
3564         };
3565         var cfg = {
3566             tag: 'li',
3567             cls: '',
3568             cn: [ a ]
3569         }
3570         var span = {
3571             tag: 'span',
3572             html : this.html || ''
3573         }
3574         
3575         
3576         if (this.active) {
3577             cfg.cls += ' active';
3578         }
3579         
3580         // left icon..
3581         if (this.glyphicon || this.icon) {
3582             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
3583             a.cn.push({ tag : 'i', cls : c }) ;
3584         }
3585         // html..
3586         a.cn.push(span);
3587         // then badge..
3588         if (this.badge !== '') {
3589             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
3590         }
3591         // fi
3592         if (this.menu) {
3593             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3594             a.cls += 'dropdown-toggle treeview' ;
3595             
3596         }
3597         
3598         
3599         
3600         return cfg;
3601          
3602            
3603     }
3604    
3605      
3606  
3607 });
3608  
3609
3610  /*
3611  * - LGPL
3612  *
3613  * row
3614  * 
3615  */
3616
3617 /**
3618  * @class Roo.bootstrap.Row
3619  * @extends Roo.bootstrap.Component
3620  * Bootstrap Row class (contains columns...)
3621  * 
3622  * @constructor
3623  * Create a new Row
3624  * @param {Object} config The config object
3625  */
3626
3627 Roo.bootstrap.Row = function(config){
3628     Roo.bootstrap.Row.superclass.constructor.call(this, config);
3629 };
3630
3631 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
3632     
3633     getAutoCreate : function(){
3634        return {
3635             cls: 'row clearfix'
3636        };
3637     }
3638     
3639     
3640 });
3641
3642  
3643
3644  /*
3645  * - LGPL
3646  *
3647  * element
3648  * 
3649  */
3650
3651 /**
3652  * @class Roo.bootstrap.Element
3653  * @extends Roo.bootstrap.Component
3654  * Bootstrap Element class
3655  * @cfg {String} html contents of the element
3656  * @cfg {String} tag tag of the element
3657  * @cfg {String} cls class of the element
3658  * 
3659  * @constructor
3660  * Create a new Element
3661  * @param {Object} config The config object
3662  */
3663
3664 Roo.bootstrap.Element = function(config){
3665     Roo.bootstrap.Element.superclass.constructor.call(this, config);
3666 };
3667
3668 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
3669     
3670     tag: 'div',
3671     cls: '',
3672     html: '',
3673      
3674     
3675     getAutoCreate : function(){
3676         
3677         var cfg = {
3678             tag: this.tag,
3679             cls: this.cls,
3680             html: this.html
3681         }
3682         
3683         
3684         
3685         return cfg;
3686     }
3687    
3688 });
3689
3690  
3691
3692  /*
3693  * - LGPL
3694  *
3695  * pagination
3696  * 
3697  */
3698
3699 /**
3700  * @class Roo.bootstrap.Pagination
3701  * @extends Roo.bootstrap.Component
3702  * Bootstrap Pagination class
3703  * @cfg {String} size xs | sm | md | lg
3704  * @cfg {Boolean} inverse false | true
3705  * 
3706  * @constructor
3707  * Create a new Pagination
3708  * @param {Object} config The config object
3709  */
3710
3711 Roo.bootstrap.Pagination = function(config){
3712     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3713 };
3714
3715 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
3716     
3717     cls: false,
3718     size: false,
3719     inverse: false,
3720     
3721     getAutoCreate : function(){
3722         var cfg = {
3723             tag: 'ul',
3724                 cls: 'pagination'
3725         };
3726         if (this.inverse) {
3727             cfg.cls += ' inverse';
3728         }
3729         if (this.html) {
3730             cfg.html=this.html;
3731         }
3732         if (this.cls) {
3733             cfg.cls += " " + this.cls;
3734         }
3735         return cfg;
3736     }
3737    
3738 });
3739
3740  
3741
3742  /*
3743  * - LGPL
3744  *
3745  * Pagination item
3746  * 
3747  */
3748
3749
3750 /**
3751  * @class Roo.bootstrap.PaginationItem
3752  * @extends Roo.bootstrap.Component
3753  * Bootstrap PaginationItem class
3754  * @cfg {String} html text
3755  * @cfg {String} href the link
3756  * @cfg {Boolean} preventDefault (true | false) default true
3757  * @cfg {Boolean} active (true | false) default false
3758  * 
3759  * 
3760  * @constructor
3761  * Create a new PaginationItem
3762  * @param {Object} config The config object
3763  */
3764
3765
3766 Roo.bootstrap.PaginationItem = function(config){
3767     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3768     this.addEvents({
3769         // raw events
3770         /**
3771          * @event click
3772          * The raw click event for the entire grid.
3773          * @param {Roo.EventObject} e
3774          */
3775         "click" : true
3776     });
3777 };
3778
3779 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
3780     
3781     href : false,
3782     html : false,
3783     preventDefault: true,
3784     active : false,
3785     cls : false,
3786     
3787     getAutoCreate : function(){
3788         var cfg= {
3789             tag: 'li',
3790             cn: [
3791                 {
3792                     tag : 'a',
3793                     href : this.href ? this.href : '#',
3794                     html : this.html ? this.html : ''
3795                 }
3796             ]
3797         };
3798         
3799         if(this.cls){
3800             cfg.cls = this.cls;
3801         }
3802         
3803         if(this.active){
3804             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3805         }
3806         
3807         return cfg;
3808     },
3809     
3810     initEvents: function() {
3811         
3812         this.el.on('click', this.onClick, this);
3813         
3814     },
3815     onClick : function(e)
3816     {
3817         Roo.log('PaginationItem on click ');
3818         if(this.preventDefault){
3819             e.preventDefault();
3820         }
3821         
3822         this.fireEvent('click', this, e);
3823     }
3824    
3825 });
3826
3827  
3828
3829  /*
3830  * - LGPL
3831  *
3832  * slider
3833  * 
3834  */
3835
3836
3837 /**
3838  * @class Roo.bootstrap.Slider
3839  * @extends Roo.bootstrap.Component
3840  * Bootstrap Slider class
3841  *    
3842  * @constructor
3843  * Create a new Slider
3844  * @param {Object} config The config object
3845  */
3846
3847 Roo.bootstrap.Slider = function(config){
3848     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3849 };
3850
3851 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
3852     
3853     getAutoCreate : function(){
3854         
3855         var cfg = {
3856             tag: 'div',
3857             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3858             cn: [
3859                 {
3860                     tag: 'a',
3861                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
3862                 }
3863             ]
3864         }
3865         
3866         return cfg;
3867     }
3868    
3869 });
3870
3871  /*
3872  * Based on:
3873  * Ext JS Library 1.1.1
3874  * Copyright(c) 2006-2007, Ext JS, LLC.
3875  *
3876  * Originally Released Under LGPL - original licence link has changed is not relivant.
3877  *
3878  * Fork - LGPL
3879  * <script type="text/javascript">
3880  */
3881  
3882
3883 /**
3884  * @class Roo.grid.ColumnModel
3885  * @extends Roo.util.Observable
3886  * This is the default implementation of a ColumnModel used by the Grid. It defines
3887  * the columns in the grid.
3888  * <br>Usage:<br>
3889  <pre><code>
3890  var colModel = new Roo.grid.ColumnModel([
3891         {header: "Ticker", width: 60, sortable: true, locked: true},
3892         {header: "Company Name", width: 150, sortable: true},
3893         {header: "Market Cap.", width: 100, sortable: true},
3894         {header: "$ Sales", width: 100, sortable: true, renderer: money},
3895         {header: "Employees", width: 100, sortable: true, resizable: false}
3896  ]);
3897  </code></pre>
3898  * <p>
3899  
3900  * The config options listed for this class are options which may appear in each
3901  * individual column definition.
3902  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3903  * @constructor
3904  * @param {Object} config An Array of column config objects. See this class's
3905  * config objects for details.
3906 */
3907 Roo.grid.ColumnModel = function(config){
3908         /**
3909      * The config passed into the constructor
3910      */
3911     this.config = config;
3912     this.lookup = {};
3913
3914     // if no id, create one
3915     // if the column does not have a dataIndex mapping,
3916     // map it to the order it is in the config
3917     for(var i = 0, len = config.length; i < len; i++){
3918         var c = config[i];
3919         if(typeof c.dataIndex == "undefined"){
3920             c.dataIndex = i;
3921         }
3922         if(typeof c.renderer == "string"){
3923             c.renderer = Roo.util.Format[c.renderer];
3924         }
3925         if(typeof c.id == "undefined"){
3926             c.id = Roo.id();
3927         }
3928         if(c.editor && c.editor.xtype){
3929             c.editor  = Roo.factory(c.editor, Roo.grid);
3930         }
3931         if(c.editor && c.editor.isFormField){
3932             c.editor = new Roo.grid.GridEditor(c.editor);
3933         }
3934         this.lookup[c.id] = c;
3935     }
3936
3937     /**
3938      * The width of columns which have no width specified (defaults to 100)
3939      * @type Number
3940      */
3941     this.defaultWidth = 100;
3942
3943     /**
3944      * Default sortable of columns which have no sortable specified (defaults to false)
3945      * @type Boolean
3946      */
3947     this.defaultSortable = false;
3948
3949     this.addEvents({
3950         /**
3951              * @event widthchange
3952              * Fires when the width of a column changes.
3953              * @param {ColumnModel} this
3954              * @param {Number} columnIndex The column index
3955              * @param {Number} newWidth The new width
3956              */
3957             "widthchange": true,
3958         /**
3959              * @event headerchange
3960              * Fires when the text of a header changes.
3961              * @param {ColumnModel} this
3962              * @param {Number} columnIndex The column index
3963              * @param {Number} newText The new header text
3964              */
3965             "headerchange": true,
3966         /**
3967              * @event hiddenchange
3968              * Fires when a column is hidden or "unhidden".
3969              * @param {ColumnModel} this
3970              * @param {Number} columnIndex The column index
3971              * @param {Boolean} hidden true if hidden, false otherwise
3972              */
3973             "hiddenchange": true,
3974             /**
3975          * @event columnmoved
3976          * Fires when a column is moved.
3977          * @param {ColumnModel} this
3978          * @param {Number} oldIndex
3979          * @param {Number} newIndex
3980          */
3981         "columnmoved" : true,
3982         /**
3983          * @event columlockchange
3984          * Fires when a column's locked state is changed
3985          * @param {ColumnModel} this
3986          * @param {Number} colIndex
3987          * @param {Boolean} locked true if locked
3988          */
3989         "columnlockchange" : true
3990     });
3991     Roo.grid.ColumnModel.superclass.constructor.call(this);
3992 };
3993 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3994     /**
3995      * @cfg {String} header The header text to display in the Grid view.
3996      */
3997     /**
3998      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3999      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4000      * specified, the column's index is used as an index into the Record's data Array.
4001      */
4002     /**
4003      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4004      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4005      */
4006     /**
4007      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4008      * Defaults to the value of the {@link #defaultSortable} property.
4009      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4010      */
4011     /**
4012      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4013      */
4014     /**
4015      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4016      */
4017     /**
4018      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4019      */
4020     /**
4021      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4022      */
4023     /**
4024      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4025      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4026      * default renderer uses the raw data value.
4027      */
4028        /**
4029      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4030      */
4031     /**
4032      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4033      */
4034
4035     /**
4036      * Returns the id of the column at the specified index.
4037      * @param {Number} index The column index
4038      * @return {String} the id
4039      */
4040     getColumnId : function(index){
4041         return this.config[index].id;
4042     },
4043
4044     /**
4045      * Returns the column for a specified id.
4046      * @param {String} id The column id
4047      * @return {Object} the column
4048      */
4049     getColumnById : function(id){
4050         return this.lookup[id];
4051     },
4052
4053     
4054     /**
4055      * Returns the column for a specified dataIndex.
4056      * @param {String} dataIndex The column dataIndex
4057      * @return {Object|Boolean} the column or false if not found
4058      */
4059     getColumnByDataIndex: function(dataIndex){
4060         var index = this.findColumnIndex(dataIndex);
4061         return index > -1 ? this.config[index] : false;
4062     },
4063     
4064     /**
4065      * Returns the index for a specified column id.
4066      * @param {String} id The column id
4067      * @return {Number} the index, or -1 if not found
4068      */
4069     getIndexById : function(id){
4070         for(var i = 0, len = this.config.length; i < len; i++){
4071             if(this.config[i].id == id){
4072                 return i;
4073             }
4074         }
4075         return -1;
4076     },
4077     
4078     /**
4079      * Returns the index for a specified column dataIndex.
4080      * @param {String} dataIndex The column dataIndex
4081      * @return {Number} the index, or -1 if not found
4082      */
4083     
4084     findColumnIndex : function(dataIndex){
4085         for(var i = 0, len = this.config.length; i < len; i++){
4086             if(this.config[i].dataIndex == dataIndex){
4087                 return i;
4088             }
4089         }
4090         return -1;
4091     },
4092     
4093     
4094     moveColumn : function(oldIndex, newIndex){
4095         var c = this.config[oldIndex];
4096         this.config.splice(oldIndex, 1);
4097         this.config.splice(newIndex, 0, c);
4098         this.dataMap = null;
4099         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4100     },
4101
4102     isLocked : function(colIndex){
4103         return this.config[colIndex].locked === true;
4104     },
4105
4106     setLocked : function(colIndex, value, suppressEvent){
4107         if(this.isLocked(colIndex) == value){
4108             return;
4109         }
4110         this.config[colIndex].locked = value;
4111         if(!suppressEvent){
4112             this.fireEvent("columnlockchange", this, colIndex, value);
4113         }
4114     },
4115
4116     getTotalLockedWidth : function(){
4117         var totalWidth = 0;
4118         for(var i = 0; i < this.config.length; i++){
4119             if(this.isLocked(i) && !this.isHidden(i)){
4120                 this.totalWidth += this.getColumnWidth(i);
4121             }
4122         }
4123         return totalWidth;
4124     },
4125
4126     getLockedCount : function(){
4127         for(var i = 0, len = this.config.length; i < len; i++){
4128             if(!this.isLocked(i)){
4129                 return i;
4130             }
4131         }
4132     },
4133
4134     /**
4135      * Returns the number of columns.
4136      * @return {Number}
4137      */
4138     getColumnCount : function(visibleOnly){
4139         if(visibleOnly === true){
4140             var c = 0;
4141             for(var i = 0, len = this.config.length; i < len; i++){
4142                 if(!this.isHidden(i)){
4143                     c++;
4144                 }
4145             }
4146             return c;
4147         }
4148         return this.config.length;
4149     },
4150
4151     /**
4152      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4153      * @param {Function} fn
4154      * @param {Object} scope (optional)
4155      * @return {Array} result
4156      */
4157     getColumnsBy : function(fn, scope){
4158         var r = [];
4159         for(var i = 0, len = this.config.length; i < len; i++){
4160             var c = this.config[i];
4161             if(fn.call(scope||this, c, i) === true){
4162                 r[r.length] = c;
4163             }
4164         }
4165         return r;
4166     },
4167
4168     /**
4169      * Returns true if the specified column is sortable.
4170      * @param {Number} col The column index
4171      * @return {Boolean}
4172      */
4173     isSortable : function(col){
4174         if(typeof this.config[col].sortable == "undefined"){
4175             return this.defaultSortable;
4176         }
4177         return this.config[col].sortable;
4178     },
4179
4180     /**
4181      * Returns the rendering (formatting) function defined for the column.
4182      * @param {Number} col The column index.
4183      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4184      */
4185     getRenderer : function(col){
4186         if(!this.config[col].renderer){
4187             return Roo.grid.ColumnModel.defaultRenderer;
4188         }
4189         return this.config[col].renderer;
4190     },
4191
4192     /**
4193      * Sets the rendering (formatting) function for a column.
4194      * @param {Number} col The column index
4195      * @param {Function} fn The function to use to process the cell's raw data
4196      * to return HTML markup for the grid view. The render function is called with
4197      * the following parameters:<ul>
4198      * <li>Data value.</li>
4199      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4200      * <li>css A CSS style string to apply to the table cell.</li>
4201      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4202      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4203      * <li>Row index</li>
4204      * <li>Column index</li>
4205      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4206      */
4207     setRenderer : function(col, fn){
4208         this.config[col].renderer = fn;
4209     },
4210
4211     /**
4212      * Returns the width for the specified column.
4213      * @param {Number} col The column index
4214      * @return {Number}
4215      */
4216     getColumnWidth : function(col){
4217         return this.config[col].width * 1 || this.defaultWidth;
4218     },
4219
4220     /**
4221      * Sets the width for a column.
4222      * @param {Number} col The column index
4223      * @param {Number} width The new width
4224      */
4225     setColumnWidth : function(col, width, suppressEvent){
4226         this.config[col].width = width;
4227         this.totalWidth = null;
4228         if(!suppressEvent){
4229              this.fireEvent("widthchange", this, col, width);
4230         }
4231     },
4232
4233     /**
4234      * Returns the total width of all columns.
4235      * @param {Boolean} includeHidden True to include hidden column widths
4236      * @return {Number}
4237      */
4238     getTotalWidth : function(includeHidden){
4239         if(!this.totalWidth){
4240             this.totalWidth = 0;
4241             for(var i = 0, len = this.config.length; i < len; i++){
4242                 if(includeHidden || !this.isHidden(i)){
4243                     this.totalWidth += this.getColumnWidth(i);
4244                 }
4245             }
4246         }
4247         return this.totalWidth;
4248     },
4249
4250     /**
4251      * Returns the header for the specified column.
4252      * @param {Number} col The column index
4253      * @return {String}
4254      */
4255     getColumnHeader : function(col){
4256         return this.config[col].header;
4257     },
4258
4259     /**
4260      * Sets the header for a column.
4261      * @param {Number} col The column index
4262      * @param {String} header The new header
4263      */
4264     setColumnHeader : function(col, header){
4265         this.config[col].header = header;
4266         this.fireEvent("headerchange", this, col, header);
4267     },
4268
4269     /**
4270      * Returns the tooltip for the specified column.
4271      * @param {Number} col The column index
4272      * @return {String}
4273      */
4274     getColumnTooltip : function(col){
4275             return this.config[col].tooltip;
4276     },
4277     /**
4278      * Sets the tooltip for a column.
4279      * @param {Number} col The column index
4280      * @param {String} tooltip The new tooltip
4281      */
4282     setColumnTooltip : function(col, tooltip){
4283             this.config[col].tooltip = tooltip;
4284     },
4285
4286     /**
4287      * Returns the dataIndex for the specified column.
4288      * @param {Number} col The column index
4289      * @return {Number}
4290      */
4291     getDataIndex : function(col){
4292         return this.config[col].dataIndex;
4293     },
4294
4295     /**
4296      * Sets the dataIndex for a column.
4297      * @param {Number} col The column index
4298      * @param {Number} dataIndex The new dataIndex
4299      */
4300     setDataIndex : function(col, dataIndex){
4301         this.config[col].dataIndex = dataIndex;
4302     },
4303
4304     
4305     
4306     /**
4307      * Returns true if the cell is editable.
4308      * @param {Number} colIndex The column index
4309      * @param {Number} rowIndex The row index
4310      * @return {Boolean}
4311      */
4312     isCellEditable : function(colIndex, rowIndex){
4313         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4314     },
4315
4316     /**
4317      * Returns the editor defined for the cell/column.
4318      * return false or null to disable editing.
4319      * @param {Number} colIndex The column index
4320      * @param {Number} rowIndex The row index
4321      * @return {Object}
4322      */
4323     getCellEditor : function(colIndex, rowIndex){
4324         return this.config[colIndex].editor;
4325     },
4326
4327     /**
4328      * Sets if a column is editable.
4329      * @param {Number} col The column index
4330      * @param {Boolean} editable True if the column is editable
4331      */
4332     setEditable : function(col, editable){
4333         this.config[col].editable = editable;
4334     },
4335
4336
4337     /**
4338      * Returns true if the column is hidden.
4339      * @param {Number} colIndex The column index
4340      * @return {Boolean}
4341      */
4342     isHidden : function(colIndex){
4343         return this.config[colIndex].hidden;
4344     },
4345
4346
4347     /**
4348      * Returns true if the column width cannot be changed
4349      */
4350     isFixed : function(colIndex){
4351         return this.config[colIndex].fixed;
4352     },
4353
4354     /**
4355      * Returns true if the column can be resized
4356      * @return {Boolean}
4357      */
4358     isResizable : function(colIndex){
4359         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4360     },
4361     /**
4362      * Sets if a column is hidden.
4363      * @param {Number} colIndex The column index
4364      * @param {Boolean} hidden True if the column is hidden
4365      */
4366     setHidden : function(colIndex, hidden){
4367         this.config[colIndex].hidden = hidden;
4368         this.totalWidth = null;
4369         this.fireEvent("hiddenchange", this, colIndex, hidden);
4370     },
4371
4372     /**
4373      * Sets the editor for a column.
4374      * @param {Number} col The column index
4375      * @param {Object} editor The editor object
4376      */
4377     setEditor : function(col, editor){
4378         this.config[col].editor = editor;
4379     }
4380 });
4381
4382 Roo.grid.ColumnModel.defaultRenderer = function(value){
4383         if(typeof value == "string" && value.length < 1){
4384             return "&#160;";
4385         }
4386         return value;
4387 };
4388
4389 // Alias for backwards compatibility
4390 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4391 /*
4392  * Based on:
4393  * Ext JS Library 1.1.1
4394  * Copyright(c) 2006-2007, Ext JS, LLC.
4395  *
4396  * Originally Released Under LGPL - original licence link has changed is not relivant.
4397  *
4398  * Fork - LGPL
4399  * <script type="text/javascript">
4400  */
4401  
4402 /**
4403  * @class Roo.LoadMask
4404  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4405  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4406  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4407  * element's UpdateManager load indicator and will be destroyed after the initial load.
4408  * @constructor
4409  * Create a new LoadMask
4410  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4411  * @param {Object} config The config object
4412  */
4413 Roo.LoadMask = function(el, config){
4414     this.el = Roo.get(el);
4415     Roo.apply(this, config);
4416     if(this.store){
4417         this.store.on('beforeload', this.onBeforeLoad, this);
4418         this.store.on('load', this.onLoad, this);
4419         this.store.on('loadexception', this.onLoadException, this);
4420         this.removeMask = false;
4421     }else{
4422         var um = this.el.getUpdateManager();
4423         um.showLoadIndicator = false; // disable the default indicator
4424         um.on('beforeupdate', this.onBeforeLoad, this);
4425         um.on('update', this.onLoad, this);
4426         um.on('failure', this.onLoad, this);
4427         this.removeMask = true;
4428     }
4429 };
4430
4431 Roo.LoadMask.prototype = {
4432     /**
4433      * @cfg {Boolean} removeMask
4434      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4435      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4436      */
4437     /**
4438      * @cfg {String} msg
4439      * The text to display in a centered loading message box (defaults to 'Loading...')
4440      */
4441     msg : 'Loading...',
4442     /**
4443      * @cfg {String} msgCls
4444      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4445      */
4446     msgCls : 'x-mask-loading',
4447
4448     /**
4449      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4450      * @type Boolean
4451      */
4452     disabled: false,
4453
4454     /**
4455      * Disables the mask to prevent it from being displayed
4456      */
4457     disable : function(){
4458        this.disabled = true;
4459     },
4460
4461     /**
4462      * Enables the mask so that it can be displayed
4463      */
4464     enable : function(){
4465         this.disabled = false;
4466     },
4467     
4468     onLoadException : function()
4469     {
4470         Roo.log(arguments);
4471         
4472         if (typeof(arguments[3]) != 'undefined') {
4473             Roo.MessageBox.alert("Error loading",arguments[3]);
4474         } 
4475         /*
4476         try {
4477             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4478                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4479             }   
4480         } catch(e) {
4481             
4482         }
4483         */
4484     
4485         
4486         
4487         this.el.unmask(this.removeMask);
4488     },
4489     // private
4490     onLoad : function()
4491     {
4492         this.el.unmask(this.removeMask);
4493     },
4494
4495     // private
4496     onBeforeLoad : function(){
4497         if(!this.disabled){
4498             this.el.mask(this.msg, this.msgCls);
4499         }
4500     },
4501
4502     // private
4503     destroy : function(){
4504         if(this.store){
4505             this.store.un('beforeload', this.onBeforeLoad, this);
4506             this.store.un('load', this.onLoad, this);
4507             this.store.un('loadexception', this.onLoadException, this);
4508         }else{
4509             var um = this.el.getUpdateManager();
4510             um.un('beforeupdate', this.onBeforeLoad, this);
4511             um.un('update', this.onLoad, this);
4512             um.un('failure', this.onLoad, this);
4513         }
4514     }
4515 };/*
4516  * - LGPL
4517  *
4518  * table
4519  * 
4520  */
4521
4522 /**
4523  * @class Roo.bootstrap.Table
4524  * @extends Roo.bootstrap.Component
4525  * Bootstrap Table class
4526  * @cfg {String} cls table class
4527  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4528  * @cfg {String} bgcolor Specifies the background color for a table
4529  * @cfg {Number} border Specifies whether the table cells should have borders or not
4530  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4531  * @cfg {Number} cellspacing Specifies the space between cells
4532  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4533  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4534  * @cfg {String} sortable Specifies that the table should be sortable
4535  * @cfg {String} summary Specifies a summary of the content of a table
4536  * @cfg {Number} width Specifies the width of a table
4537  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4538  * 
4539  * @cfg {boolean} striped Should the rows be alternative striped
4540  * @cfg {boolean} bordered Add borders to the table
4541  * @cfg {boolean} hover Add hover highlighting
4542  * @cfg {boolean} condensed Format condensed
4543  * @cfg {boolean} responsive Format condensed
4544  * @cfg {Boolean} loadMask (true|false) default false
4545  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4546  * @cfg {Boolean} thead (true|false) generate thead, default true
4547  * @cfg {Boolean} RowSelection (true|false) default false
4548  * @cfg {Boolean} CellSelection (true|false) default false
4549  *
4550  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
4551  
4552  * 
4553  * @constructor
4554  * Create a new Table
4555  * @param {Object} config The config object
4556  */
4557
4558 Roo.bootstrap.Table = function(config){
4559     Roo.bootstrap.Table.superclass.constructor.call(this, config);
4560     
4561     if (this.sm) {
4562         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4563         this.sm = this.selModel;
4564         this.sm.xmodule = this.xmodule || false;
4565     }
4566     if (this.cm && typeof(this.cm.config) == 'undefined') {
4567         this.colModel = new Roo.grid.ColumnModel(this.cm);
4568         this.cm = this.colModel;
4569         this.cm.xmodule = this.xmodule || false;
4570     }
4571     if (this.store) {
4572         this.store= Roo.factory(this.store, Roo.data);
4573         this.ds = this.store;
4574         this.ds.xmodule = this.xmodule || false;
4575          
4576     }
4577     if (this.footer && this.store) {
4578         this.footer.dataSource = this.ds;
4579         this.footer = Roo.factory(this.footer);
4580     }
4581     
4582     /** @private */
4583     this.addEvents({
4584         /**
4585          * @event cellclick
4586          * Fires when a cell is clicked
4587          * @param {Roo.bootstrap.Table} this
4588          * @param {Roo.Element} el
4589          * @param {Number} rowIndex
4590          * @param {Number} columnIndex
4591          * @param {Roo.EventObject} e
4592          */
4593         "cellclick" : true,
4594         /**
4595          * @event celldblclick
4596          * Fires when a cell is double clicked
4597          * @param {Roo.bootstrap.Table} this
4598          * @param {Roo.Element} el
4599          * @param {Number} rowIndex
4600          * @param {Number} columnIndex
4601          * @param {Roo.EventObject} e
4602          */
4603         "celldblclick" : true,
4604         /**
4605          * @event rowclick
4606          * Fires when a row is clicked
4607          * @param {Roo.bootstrap.Table} this
4608          * @param {Roo.Element} el
4609          * @param {Number} rowIndex
4610          * @param {Roo.EventObject} e
4611          */
4612         "rowclick" : true,
4613         /**
4614          * @event rowdblclick
4615          * Fires when a row is double clicked
4616          * @param {Roo.bootstrap.Table} this
4617          * @param {Roo.Element} el
4618          * @param {Number} rowIndex
4619          * @param {Roo.EventObject} e
4620          */
4621         "rowdblclick" : true,
4622         /**
4623          * @event mouseover
4624          * Fires when a mouseover occur
4625          * @param {Roo.bootstrap.Table} this
4626          * @param {Roo.Element} el
4627          * @param {Number} rowIndex
4628          * @param {Number} columnIndex
4629          * @param {Roo.EventObject} e
4630          */
4631         "mouseover" : true,
4632         /**
4633          * @event mouseout
4634          * Fires when a mouseout occur
4635          * @param {Roo.bootstrap.Table} this
4636          * @param {Roo.Element} el
4637          * @param {Number} rowIndex
4638          * @param {Number} columnIndex
4639          * @param {Roo.EventObject} e
4640          */
4641         "mouseout" : true,
4642         /**
4643          * @event rowclass
4644          * Fires when a row is rendered, so you can change add a style to it.
4645          * @param {Roo.bootstrap.Table} this
4646          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
4647          */
4648         'rowclass' : true,
4649         /**
4650          * @event afterload
4651          * Fires when record have been loaded
4652          * @param {Roo.bootstrap.Table} this
4653          * @param {Object} records  store records
4654          */
4655         'afterload' : true
4656         
4657     });
4658 };
4659
4660 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
4661     
4662     cls: false,
4663     align: false,
4664     bgcolor: false,
4665     border: false,
4666     cellpadding: false,
4667     cellspacing: false,
4668     frame: false,
4669     rules: false,
4670     sortable: false,
4671     summary: false,
4672     width: false,
4673     striped : false,
4674     bordered: false,
4675     hover:  false,
4676     condensed : false,
4677     responsive : false,
4678     sm : false,
4679     cm : false,
4680     store : false,
4681     loadMask : false,
4682     tfoot : true,
4683     thead : true,
4684     RowSelection : false,
4685     CellSelection : false,
4686     layout : false,
4687     
4688     
4689     getAutoCreate : function(){
4690         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4691         
4692         cfg = {
4693             tag: 'table',
4694             cls : 'table',
4695             cn : []
4696         }
4697             
4698         if (this.striped) {
4699             cfg.cls += ' table-striped';
4700         }
4701         
4702         if (this.hover) {
4703             cfg.cls += ' table-hover';
4704         }
4705         if (this.bordered) {
4706             cfg.cls += ' table-bordered';
4707         }
4708         if (this.condensed) {
4709             cfg.cls += ' table-condensed';
4710         }
4711         if (this.responsive) {
4712             cfg.cls += ' table-responsive';
4713         }
4714         
4715         if (this.cls) {
4716             cfg.cls+=  ' ' +this.cls;
4717         }
4718         
4719         // this lot should be simplifed...
4720         
4721         if (this.align) {
4722             cfg.align=this.align;
4723         }
4724         if (this.bgcolor) {
4725             cfg.bgcolor=this.bgcolor;
4726         }
4727         if (this.border) {
4728             cfg.border=this.border;
4729         }
4730         if (this.cellpadding) {
4731             cfg.cellpadding=this.cellpadding;
4732         }
4733         if (this.cellspacing) {
4734             cfg.cellspacing=this.cellspacing;
4735         }
4736         if (this.frame) {
4737             cfg.frame=this.frame;
4738         }
4739         if (this.rules) {
4740             cfg.rules=this.rules;
4741         }
4742         if (this.sortable) {
4743             cfg.sortable=this.sortable;
4744         }
4745         if (this.summary) {
4746             cfg.summary=this.summary;
4747         }
4748         if (this.width) {
4749             cfg.width=this.width;
4750         }
4751         if (this.layout) {
4752             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4753         }
4754         
4755         if(this.store || this.cm){
4756             if(this.thead){
4757                 cfg.cn.push(this.renderHeader());
4758             }
4759             
4760             cfg.cn.push(this.renderBody());
4761             
4762             if(this.tfoot){
4763                 cfg.cn.push(this.renderFooter());
4764             }
4765             
4766             cfg.cls+=  ' TableGrid';
4767         }
4768         
4769         return { cn : [ cfg ] };
4770     },
4771     
4772     initEvents : function()
4773     {   
4774         if(!this.store || !this.cm){
4775             return;
4776         }
4777         
4778         Roo.log('initEvents with ds!!!!');
4779         
4780         var _this = this;
4781         
4782         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4783             e.on('click', _this.sort, _this);
4784         });
4785         
4786         this.el.on("click", this.onClick, this);
4787         this.el.on("dblclick", this.onDblClick, this);
4788         
4789         this.parent().el.setStyle('position', 'relative');
4790         if (this.footer) {
4791             this.footer.parentId = this.id;
4792             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
4793         }
4794         
4795         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4796         
4797         this.store.on('load', this.onLoad, this);
4798         this.store.on('beforeload', this.onBeforeLoad, this);
4799         
4800     },
4801     
4802     onMouseover : function(e, el)
4803     {
4804         var cell = Roo.get(el);
4805         
4806         if(!cell){
4807             return;
4808         }
4809         
4810         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4811             cell = cell.findParent('td', false, true);
4812         }
4813         
4814         var row = cell.findParent('tr', false, true);
4815         var cellIndex = cell.dom.cellIndex;
4816         var rowIndex = row.dom.rowIndex - 1; // start from 0
4817         
4818         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4819         
4820     },
4821     
4822     onMouseout : function(e, el)
4823     {
4824         var cell = Roo.get(el);
4825         
4826         if(!cell){
4827             return;
4828         }
4829         
4830         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4831             cell = cell.findParent('td', false, true);
4832         }
4833         
4834         var row = cell.findParent('tr', false, true);
4835         var cellIndex = cell.dom.cellIndex;
4836         var rowIndex = row.dom.rowIndex - 1; // start from 0
4837         
4838         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4839         
4840     },
4841     
4842     onClick : function(e, el)
4843     {
4844         var cell = Roo.get(el);
4845         
4846         if(!cell || !this.CellSelection || !this.RowSelection){
4847             return;
4848         }
4849         
4850         
4851         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4852             cell = cell.findParent('td', false, true);
4853         }
4854         
4855         var row = cell.findParent('tr', false, true);
4856         var cellIndex = cell.dom.cellIndex;
4857         var rowIndex = row.dom.rowIndex - 1;
4858         
4859         if(this.CellSelection){
4860             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4861         }
4862         
4863         if(this.RowSelection){
4864             this.fireEvent('rowclick', this, row, rowIndex, e);
4865         }
4866         
4867         
4868     },
4869     
4870     onDblClick : function(e,el)
4871     {
4872         var cell = Roo.get(el);
4873         
4874         if(!cell || !this.CellSelection || !this.RowSelection){
4875             return;
4876         }
4877         
4878         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4879             cell = cell.findParent('td', false, true);
4880         }
4881         
4882         var row = cell.findParent('tr', false, true);
4883         var cellIndex = cell.dom.cellIndex;
4884         var rowIndex = row.dom.rowIndex - 1;
4885         
4886         if(this.CellSelection){
4887             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4888         }
4889         
4890         if(this.RowSelection){
4891             this.fireEvent('rowdblclick', this, row, rowIndex, e);
4892         }
4893     },
4894     
4895     sort : function(e,el)
4896     {
4897         var col = Roo.get(el)
4898         
4899         if(!col.hasClass('sortable')){
4900             return;
4901         }
4902         
4903         var sort = col.attr('sort');
4904         var dir = 'ASC';
4905         
4906         if(col.hasClass('glyphicon-arrow-up')){
4907             dir = 'DESC';
4908         }
4909         
4910         this.store.sortInfo = {field : sort, direction : dir};
4911         
4912         if (this.footer) {
4913             Roo.log("calling footer first");
4914             this.footer.onClick('first');
4915         } else {
4916         
4917             this.store.load({ params : { start : 0 } });
4918         }
4919     },
4920     
4921     renderHeader : function()
4922     {
4923         var header = {
4924             tag: 'thead',
4925             cn : []
4926         };
4927         
4928         var cm = this.cm;
4929         
4930         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4931             
4932             var config = cm.config[i];
4933                     
4934             var c = {
4935                 tag: 'th',
4936                 style : '',
4937                 html: cm.getColumnHeader(i)
4938             };
4939             
4940             if(typeof(config.hidden) != 'undefined' && config.hidden){
4941                 c.style += ' display:none;';
4942             }
4943             
4944             if(typeof(config.dataIndex) != 'undefined'){
4945                 c.sort = config.dataIndex;
4946             }
4947             
4948             if(typeof(config.sortable) != 'undefined' && config.sortable){
4949                 c.cls = 'sortable';
4950             }
4951             
4952 //            if(typeof(config.align) != 'undefined' && config.align.length){
4953 //                c.style += ' text-align:' + config.align + ';';
4954 //            }
4955             
4956             if(typeof(config.width) != 'undefined'){
4957                 c.style += ' width:' + config.width + 'px;';
4958             }
4959             
4960             header.cn.push(c)
4961         }
4962         
4963         return header;
4964     },
4965     
4966     renderBody : function()
4967     {
4968         var body = {
4969             tag: 'tbody',
4970             cn : [
4971                 {
4972                     tag: 'tr',
4973                     cn : [
4974                         {
4975                             tag : 'td',
4976                             colspan :  this.cm.getColumnCount()
4977                         }
4978                     ]
4979                 }
4980             ]
4981         };
4982         
4983         return body;
4984     },
4985     
4986     renderFooter : function()
4987     {
4988         var footer = {
4989             tag: 'tfoot',
4990             cn : [
4991                 {
4992                     tag: 'tr',
4993                     cn : [
4994                         {
4995                             tag : 'td',
4996                             colspan :  this.cm.getColumnCount()
4997                         }
4998                     ]
4999                 }
5000             ]
5001         };
5002         
5003         return footer;
5004     },
5005     
5006     onLoad : function()
5007     {
5008         Roo.log('ds onload');
5009         this.clear();
5010         
5011         var _this = this;
5012         var cm = this.cm;
5013         
5014         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5015             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5016             
5017             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5018                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5019             }
5020             
5021             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5022                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5023             }
5024         });
5025         
5026         var tbody = this.el.select('tbody', true).first();
5027         
5028         var renders = [];
5029                     
5030         if(this.store.getCount() > 0){
5031             this.store.data.each(function(d,rowIndex){
5032                 var row = {
5033                     tag : 'tr',
5034                     cn : []
5035                 };
5036                 
5037                 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5038                     var config = cm.config[i];
5039                     
5040                     var renderer = cm.getRenderer(i);
5041                     var value = '';
5042                     var id = Roo.id();
5043                     
5044                     if(typeof(renderer) !== 'undefined'){
5045                         value = renderer(d.data[cm.getDataIndex(i)], false, d);
5046                     }
5047                     
5048                     if(typeof(value) === 'object'){
5049                         renders.push({
5050                             container : id,
5051                             cfg : value 
5052                         })
5053                     }
5054                     
5055                     var rowcfg = {
5056                         record: d,
5057                         rowIndex : rowIndex,
5058                         colIndex : i,
5059                         rowClass : ''
5060                     }
5061
5062                     _this.fireEvent('rowclass', this, rowcfg);
5063                     
5064                     var td = {
5065                         tag: 'td',
5066                         id: id,
5067                         cls : rowcfg.rowClass,
5068                         style: '',
5069                         html: (typeof(value) === 'object') ? '' : value
5070                     };
5071                     
5072                     if(typeof(config.hidden) != 'undefined' && config.hidden){
5073                         td.style += ' display:none;';
5074                     }
5075                     
5076                     if(typeof(config.align) != 'undefined' && config.align.length){
5077                         td.style += ' text-align:' + config.align + ';';
5078                     }
5079                     
5080                     if(typeof(config.width) != 'undefined'){
5081                         td.style += ' width:' +  config.width + 'px;';
5082                     }
5083                     
5084                     
5085                     row.cn.push(td);
5086                    
5087                 }
5088                 
5089                 tbody.createChild(row);
5090                 
5091             });
5092         }
5093         
5094         
5095         if(renders.length){
5096             var _this = this;
5097             Roo.each(renders, function(r){
5098                 _this.renderColumn(r);
5099             })
5100         }
5101         
5102         Roo.each(this.el.select('tbody td', true).elements, function(e){
5103             e.on('mouseover', _this.onMouseover, _this);
5104         });
5105         
5106         Roo.each(this.el.select('tbody td', true).elements, function(e){
5107             e.on('mouseout', _this.onMouseout, _this);
5108         });
5109
5110         this.fireEvent('afterload', this, this.store.data);
5111         //if(this.loadMask){
5112         //    this.maskEl.hide();
5113         //}
5114     },
5115     
5116     onBeforeLoad : function()
5117     {
5118         //Roo.log('ds onBeforeLoad');
5119         
5120         //this.clear();
5121         
5122         //if(this.loadMask){
5123         //    this.maskEl.show();
5124         //}
5125     },
5126     
5127     clear : function()
5128     {
5129         this.el.select('tbody', true).first().dom.innerHTML = '';
5130     },
5131     
5132     getSelectionModel : function(){
5133         if(!this.selModel){
5134             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5135         }
5136         return this.selModel;
5137     },
5138     
5139     renderColumn : function(r)
5140     {
5141         var _this = this;
5142         
5143         var t = r.cfg.render(r.container);
5144         
5145         if(r.cfg.cn){
5146             Roo.each(r.cfg.cn, function(c){
5147                 var child = {
5148                     container: t.getChildContainer(),
5149                     cfg: c
5150                 }
5151                 _this.renderColumn(child);
5152             })
5153         }
5154     }
5155    
5156 });
5157
5158  
5159
5160  /*
5161  * - LGPL
5162  *
5163  * table cell
5164  * 
5165  */
5166
5167 /**
5168  * @class Roo.bootstrap.TableCell
5169  * @extends Roo.bootstrap.Component
5170  * Bootstrap TableCell class
5171  * @cfg {String} html cell contain text
5172  * @cfg {String} cls cell class
5173  * @cfg {String} tag cell tag (td|th) default td
5174  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5175  * @cfg {String} align Aligns the content in a cell
5176  * @cfg {String} axis Categorizes cells
5177  * @cfg {String} bgcolor Specifies the background color of a cell
5178  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5179  * @cfg {Number} colspan Specifies the number of columns a cell should span
5180  * @cfg {String} headers Specifies one or more header cells a cell is related to
5181  * @cfg {Number} height Sets the height of a cell
5182  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5183  * @cfg {Number} rowspan Sets the number of rows a cell should span
5184  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5185  * @cfg {String} valign Vertical aligns the content in a cell
5186  * @cfg {Number} width Specifies the width of a cell
5187  * 
5188  * @constructor
5189  * Create a new TableCell
5190  * @param {Object} config The config object
5191  */
5192
5193 Roo.bootstrap.TableCell = function(config){
5194     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5195 };
5196
5197 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5198     
5199     html: false,
5200     cls: false,
5201     tag: false,
5202     abbr: false,
5203     align: false,
5204     axis: false,
5205     bgcolor: false,
5206     charoff: false,
5207     colspan: false,
5208     headers: false,
5209     height: false,
5210     nowrap: false,
5211     rowspan: false,
5212     scope: false,
5213     valign: false,
5214     width: false,
5215     
5216     
5217     getAutoCreate : function(){
5218         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5219         
5220         cfg = {
5221             tag: 'td'
5222         }
5223         
5224         if(this.tag){
5225             cfg.tag = this.tag;
5226         }
5227         
5228         if (this.html) {
5229             cfg.html=this.html
5230         }
5231         if (this.cls) {
5232             cfg.cls=this.cls
5233         }
5234         if (this.abbr) {
5235             cfg.abbr=this.abbr
5236         }
5237         if (this.align) {
5238             cfg.align=this.align
5239         }
5240         if (this.axis) {
5241             cfg.axis=this.axis
5242         }
5243         if (this.bgcolor) {
5244             cfg.bgcolor=this.bgcolor
5245         }
5246         if (this.charoff) {
5247             cfg.charoff=this.charoff
5248         }
5249         if (this.colspan) {
5250             cfg.colspan=this.colspan
5251         }
5252         if (this.headers) {
5253             cfg.headers=this.headers
5254         }
5255         if (this.height) {
5256             cfg.height=this.height
5257         }
5258         if (this.nowrap) {
5259             cfg.nowrap=this.nowrap
5260         }
5261         if (this.rowspan) {
5262             cfg.rowspan=this.rowspan
5263         }
5264         if (this.scope) {
5265             cfg.scope=this.scope
5266         }
5267         if (this.valign) {
5268             cfg.valign=this.valign
5269         }
5270         if (this.width) {
5271             cfg.width=this.width
5272         }
5273         
5274         
5275         return cfg;
5276     }
5277    
5278 });
5279
5280  
5281
5282  /*
5283  * - LGPL
5284  *
5285  * table row
5286  * 
5287  */
5288
5289 /**
5290  * @class Roo.bootstrap.TableRow
5291  * @extends Roo.bootstrap.Component
5292  * Bootstrap TableRow class
5293  * @cfg {String} cls row class
5294  * @cfg {String} align Aligns the content in a table row
5295  * @cfg {String} bgcolor Specifies a background color for a table row
5296  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5297  * @cfg {String} valign Vertical aligns the content in a table row
5298  * 
5299  * @constructor
5300  * Create a new TableRow
5301  * @param {Object} config The config object
5302  */
5303
5304 Roo.bootstrap.TableRow = function(config){
5305     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5306 };
5307
5308 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5309     
5310     cls: false,
5311     align: false,
5312     bgcolor: false,
5313     charoff: false,
5314     valign: false,
5315     
5316     getAutoCreate : function(){
5317         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5318         
5319         cfg = {
5320             tag: 'tr'
5321         }
5322             
5323         if(this.cls){
5324             cfg.cls = this.cls;
5325         }
5326         if(this.align){
5327             cfg.align = this.align;
5328         }
5329         if(this.bgcolor){
5330             cfg.bgcolor = this.bgcolor;
5331         }
5332         if(this.charoff){
5333             cfg.charoff = this.charoff;
5334         }
5335         if(this.valign){
5336             cfg.valign = this.valign;
5337         }
5338         
5339         return cfg;
5340     }
5341    
5342 });
5343
5344  
5345
5346  /*
5347  * - LGPL
5348  *
5349  * table body
5350  * 
5351  */
5352
5353 /**
5354  * @class Roo.bootstrap.TableBody
5355  * @extends Roo.bootstrap.Component
5356  * Bootstrap TableBody class
5357  * @cfg {String} cls element class
5358  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5359  * @cfg {String} align Aligns the content inside the element
5360  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5361  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5362  * 
5363  * @constructor
5364  * Create a new TableBody
5365  * @param {Object} config The config object
5366  */
5367
5368 Roo.bootstrap.TableBody = function(config){
5369     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5370 };
5371
5372 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
5373     
5374     cls: false,
5375     tag: false,
5376     align: false,
5377     charoff: false,
5378     valign: false,
5379     
5380     getAutoCreate : function(){
5381         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5382         
5383         cfg = {
5384             tag: 'tbody'
5385         }
5386             
5387         if (this.cls) {
5388             cfg.cls=this.cls
5389         }
5390         if(this.tag){
5391             cfg.tag = this.tag;
5392         }
5393         
5394         if(this.align){
5395             cfg.align = this.align;
5396         }
5397         if(this.charoff){
5398             cfg.charoff = this.charoff;
5399         }
5400         if(this.valign){
5401             cfg.valign = this.valign;
5402         }
5403         
5404         return cfg;
5405     }
5406     
5407     
5408 //    initEvents : function()
5409 //    {
5410 //        
5411 //        if(!this.store){
5412 //            return;
5413 //        }
5414 //        
5415 //        this.store = Roo.factory(this.store, Roo.data);
5416 //        this.store.on('load', this.onLoad, this);
5417 //        
5418 //        this.store.load();
5419 //        
5420 //    },
5421 //    
5422 //    onLoad: function () 
5423 //    {   
5424 //        this.fireEvent('load', this);
5425 //    }
5426 //    
5427 //   
5428 });
5429
5430  
5431
5432  /*
5433  * Based on:
5434  * Ext JS Library 1.1.1
5435  * Copyright(c) 2006-2007, Ext JS, LLC.
5436  *
5437  * Originally Released Under LGPL - original licence link has changed is not relivant.
5438  *
5439  * Fork - LGPL
5440  * <script type="text/javascript">
5441  */
5442
5443 // as we use this in bootstrap.
5444 Roo.namespace('Roo.form');
5445  /**
5446  * @class Roo.form.Action
5447  * Internal Class used to handle form actions
5448  * @constructor
5449  * @param {Roo.form.BasicForm} el The form element or its id
5450  * @param {Object} config Configuration options
5451  */
5452
5453  
5454  
5455 // define the action interface
5456 Roo.form.Action = function(form, options){
5457     this.form = form;
5458     this.options = options || {};
5459 };
5460 /**
5461  * Client Validation Failed
5462  * @const 
5463  */
5464 Roo.form.Action.CLIENT_INVALID = 'client';
5465 /**
5466  * Server Validation Failed
5467  * @const 
5468  */
5469 Roo.form.Action.SERVER_INVALID = 'server';
5470  /**
5471  * Connect to Server Failed
5472  * @const 
5473  */
5474 Roo.form.Action.CONNECT_FAILURE = 'connect';
5475 /**
5476  * Reading Data from Server Failed
5477  * @const 
5478  */
5479 Roo.form.Action.LOAD_FAILURE = 'load';
5480
5481 Roo.form.Action.prototype = {
5482     type : 'default',
5483     failureType : undefined,
5484     response : undefined,
5485     result : undefined,
5486
5487     // interface method
5488     run : function(options){
5489
5490     },
5491
5492     // interface method
5493     success : function(response){
5494
5495     },
5496
5497     // interface method
5498     handleResponse : function(response){
5499
5500     },
5501
5502     // default connection failure
5503     failure : function(response){
5504         
5505         this.response = response;
5506         this.failureType = Roo.form.Action.CONNECT_FAILURE;
5507         this.form.afterAction(this, false);
5508     },
5509
5510     processResponse : function(response){
5511         this.response = response;
5512         if(!response.responseText){
5513             return true;
5514         }
5515         this.result = this.handleResponse(response);
5516         return this.result;
5517     },
5518
5519     // utility functions used internally
5520     getUrl : function(appendParams){
5521         var url = this.options.url || this.form.url || this.form.el.dom.action;
5522         if(appendParams){
5523             var p = this.getParams();
5524             if(p){
5525                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5526             }
5527         }
5528         return url;
5529     },
5530
5531     getMethod : function(){
5532         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5533     },
5534
5535     getParams : function(){
5536         var bp = this.form.baseParams;
5537         var p = this.options.params;
5538         if(p){
5539             if(typeof p == "object"){
5540                 p = Roo.urlEncode(Roo.applyIf(p, bp));
5541             }else if(typeof p == 'string' && bp){
5542                 p += '&' + Roo.urlEncode(bp);
5543             }
5544         }else if(bp){
5545             p = Roo.urlEncode(bp);
5546         }
5547         return p;
5548     },
5549
5550     createCallback : function(){
5551         return {
5552             success: this.success,
5553             failure: this.failure,
5554             scope: this,
5555             timeout: (this.form.timeout*1000),
5556             upload: this.form.fileUpload ? this.success : undefined
5557         };
5558     }
5559 };
5560
5561 Roo.form.Action.Submit = function(form, options){
5562     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5563 };
5564
5565 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5566     type : 'submit',
5567
5568     haveProgress : false,
5569     uploadComplete : false,
5570     
5571     // uploadProgress indicator.
5572     uploadProgress : function()
5573     {
5574         if (!this.form.progressUrl) {
5575             return;
5576         }
5577         
5578         if (!this.haveProgress) {
5579             Roo.MessageBox.progress("Uploading", "Uploading");
5580         }
5581         if (this.uploadComplete) {
5582            Roo.MessageBox.hide();
5583            return;
5584         }
5585         
5586         this.haveProgress = true;
5587    
5588         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5589         
5590         var c = new Roo.data.Connection();
5591         c.request({
5592             url : this.form.progressUrl,
5593             params: {
5594                 id : uid
5595             },
5596             method: 'GET',
5597             success : function(req){
5598                //console.log(data);
5599                 var rdata = false;
5600                 var edata;
5601                 try  {
5602                    rdata = Roo.decode(req.responseText)
5603                 } catch (e) {
5604                     Roo.log("Invalid data from server..");
5605                     Roo.log(edata);
5606                     return;
5607                 }
5608                 if (!rdata || !rdata.success) {
5609                     Roo.log(rdata);
5610                     Roo.MessageBox.alert(Roo.encode(rdata));
5611                     return;
5612                 }
5613                 var data = rdata.data;
5614                 
5615                 if (this.uploadComplete) {
5616                    Roo.MessageBox.hide();
5617                    return;
5618                 }
5619                    
5620                 if (data){
5621                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5622                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5623                     );
5624                 }
5625                 this.uploadProgress.defer(2000,this);
5626             },
5627        
5628             failure: function(data) {
5629                 Roo.log('progress url failed ');
5630                 Roo.log(data);
5631             },
5632             scope : this
5633         });
5634            
5635     },
5636     
5637     
5638     run : function()
5639     {
5640         // run get Values on the form, so it syncs any secondary forms.
5641         this.form.getValues();
5642         
5643         var o = this.options;
5644         var method = this.getMethod();
5645         var isPost = method == 'POST';
5646         if(o.clientValidation === false || this.form.isValid()){
5647             
5648             if (this.form.progressUrl) {
5649                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5650                     (new Date() * 1) + '' + Math.random());
5651                     
5652             } 
5653             
5654             
5655             Roo.Ajax.request(Roo.apply(this.createCallback(), {
5656                 form:this.form.el.dom,
5657                 url:this.getUrl(!isPost),
5658                 method: method,
5659                 params:isPost ? this.getParams() : null,
5660                 isUpload: this.form.fileUpload
5661             }));
5662             
5663             this.uploadProgress();
5664
5665         }else if (o.clientValidation !== false){ // client validation failed
5666             this.failureType = Roo.form.Action.CLIENT_INVALID;
5667             this.form.afterAction(this, false);
5668         }
5669     },
5670
5671     success : function(response)
5672     {
5673         this.uploadComplete= true;
5674         if (this.haveProgress) {
5675             Roo.MessageBox.hide();
5676         }
5677         
5678         
5679         var result = this.processResponse(response);
5680         if(result === true || result.success){
5681             this.form.afterAction(this, true);
5682             return;
5683         }
5684         if(result.errors){
5685             this.form.markInvalid(result.errors);
5686             this.failureType = Roo.form.Action.SERVER_INVALID;
5687         }
5688         this.form.afterAction(this, false);
5689     },
5690     failure : function(response)
5691     {
5692         this.uploadComplete= true;
5693         if (this.haveProgress) {
5694             Roo.MessageBox.hide();
5695         }
5696         
5697         this.response = response;
5698         this.failureType = Roo.form.Action.CONNECT_FAILURE;
5699         this.form.afterAction(this, false);
5700     },
5701     
5702     handleResponse : function(response){
5703         if(this.form.errorReader){
5704             var rs = this.form.errorReader.read(response);
5705             var errors = [];
5706             if(rs.records){
5707                 for(var i = 0, len = rs.records.length; i < len; i++) {
5708                     var r = rs.records[i];
5709                     errors[i] = r.data;
5710                 }
5711             }
5712             if(errors.length < 1){
5713                 errors = null;
5714             }
5715             return {
5716                 success : rs.success,
5717                 errors : errors
5718             };
5719         }
5720         var ret = false;
5721         try {
5722             ret = Roo.decode(response.responseText);
5723         } catch (e) {
5724             ret = {
5725                 success: false,
5726                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5727                 errors : []
5728             };
5729         }
5730         return ret;
5731         
5732     }
5733 });
5734
5735
5736 Roo.form.Action.Load = function(form, options){
5737     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5738     this.reader = this.form.reader;
5739 };
5740
5741 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5742     type : 'load',
5743
5744     run : function(){
5745         
5746         Roo.Ajax.request(Roo.apply(
5747                 this.createCallback(), {
5748                     method:this.getMethod(),
5749                     url:this.getUrl(false),
5750                     params:this.getParams()
5751         }));
5752     },
5753
5754     success : function(response){
5755         
5756         var result = this.processResponse(response);
5757         if(result === true || !result.success || !result.data){
5758             this.failureType = Roo.form.Action.LOAD_FAILURE;
5759             this.form.afterAction(this, false);
5760             return;
5761         }
5762         this.form.clearInvalid();
5763         this.form.setValues(result.data);
5764         this.form.afterAction(this, true);
5765     },
5766
5767     handleResponse : function(response){
5768         if(this.form.reader){
5769             var rs = this.form.reader.read(response);
5770             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5771             return {
5772                 success : rs.success,
5773                 data : data
5774             };
5775         }
5776         return Roo.decode(response.responseText);
5777     }
5778 });
5779
5780 Roo.form.Action.ACTION_TYPES = {
5781     'load' : Roo.form.Action.Load,
5782     'submit' : Roo.form.Action.Submit
5783 };/*
5784  * - LGPL
5785  *
5786  * form
5787  * 
5788  */
5789
5790 /**
5791  * @class Roo.bootstrap.Form
5792  * @extends Roo.bootstrap.Component
5793  * Bootstrap Form class
5794  * @cfg {String} method  GET | POST (default POST)
5795  * @cfg {String} labelAlign top | left (default top)
5796   * @cfg {String} align left  | right - for navbars
5797
5798  * 
5799  * @constructor
5800  * Create a new Form
5801  * @param {Object} config The config object
5802  */
5803
5804
5805 Roo.bootstrap.Form = function(config){
5806     Roo.bootstrap.Form.superclass.constructor.call(this, config);
5807     this.addEvents({
5808         /**
5809          * @event clientvalidation
5810          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5811          * @param {Form} this
5812          * @param {Boolean} valid true if the form has passed client-side validation
5813          */
5814         clientvalidation: true,
5815         /**
5816          * @event beforeaction
5817          * Fires before any action is performed. Return false to cancel the action.
5818          * @param {Form} this
5819          * @param {Action} action The action to be performed
5820          */
5821         beforeaction: true,
5822         /**
5823          * @event actionfailed
5824          * Fires when an action fails.
5825          * @param {Form} this
5826          * @param {Action} action The action that failed
5827          */
5828         actionfailed : true,
5829         /**
5830          * @event actioncomplete
5831          * Fires when an action is completed.
5832          * @param {Form} this
5833          * @param {Action} action The action that completed
5834          */
5835         actioncomplete : true
5836     });
5837     
5838 };
5839
5840 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
5841       
5842      /**
5843      * @cfg {String} method
5844      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5845      */
5846     method : 'POST',
5847     /**
5848      * @cfg {String} url
5849      * The URL to use for form actions if one isn't supplied in the action options.
5850      */
5851     /**
5852      * @cfg {Boolean} fileUpload
5853      * Set to true if this form is a file upload.
5854      */
5855      
5856     /**
5857      * @cfg {Object} baseParams
5858      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5859      */
5860       
5861     /**
5862      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5863      */
5864     timeout: 30,
5865     /**
5866      * @cfg {Sting} align (left|right) for navbar forms
5867      */
5868     align : 'left',
5869
5870     // private
5871     activeAction : null,
5872  
5873     /**
5874      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5875      * element by passing it or its id or mask the form itself by passing in true.
5876      * @type Mixed
5877      */
5878     waitMsgTarget : false,
5879     
5880      
5881     
5882     /**
5883      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5884      * element by passing it or its id or mask the form itself by passing in true.
5885      * @type Mixed
5886      */
5887     
5888     getAutoCreate : function(){
5889         
5890         var cfg = {
5891             tag: 'form',
5892             method : this.method || 'POST',
5893             id : this.id || Roo.id(),
5894             cls : ''
5895         }
5896         if (this.parent().xtype.match(/^Nav/)) {
5897             cfg.cls = 'navbar-form navbar-' + this.align;
5898             
5899         }
5900         
5901         if (this.labelAlign == 'left' ) {
5902             cfg.cls += ' form-horizontal';
5903         }
5904         
5905         
5906         return cfg;
5907     },
5908     initEvents : function()
5909     {
5910         this.el.on('submit', this.onSubmit, this);
5911         // this was added as random key presses on the form where triggering form submit.
5912         this.el.on('keypress', function(e) {
5913             if (e.getCharCode() != 13) {
5914                 return true;
5915             }
5916             // we might need to allow it for textareas.. and some other items.
5917             // check e.getTarget().
5918             
5919             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5920                 return true;
5921             }
5922         
5923             Roo.log("keypress blocked");
5924             
5925             e.preventDefault();
5926             return false;
5927         });
5928         
5929     },
5930     // private
5931     onSubmit : function(e){
5932         e.stopEvent();
5933     },
5934     
5935      /**
5936      * Returns true if client-side validation on the form is successful.
5937      * @return Boolean
5938      */
5939     isValid : function(){
5940         var items = this.getItems();
5941         var valid = true;
5942         items.each(function(f){
5943            if(!f.validate()){
5944                valid = false;
5945                
5946            }
5947         });
5948         return valid;
5949     },
5950     /**
5951      * Returns true if any fields in this form have changed since their original load.
5952      * @return Boolean
5953      */
5954     isDirty : function(){
5955         var dirty = false;
5956         var items = this.getItems();
5957         items.each(function(f){
5958            if(f.isDirty()){
5959                dirty = true;
5960                return false;
5961            }
5962            return true;
5963         });
5964         return dirty;
5965     },
5966      /**
5967      * Performs a predefined action (submit or load) or custom actions you define on this form.
5968      * @param {String} actionName The name of the action type
5969      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
5970      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5971      * accept other config options):
5972      * <pre>
5973 Property          Type             Description
5974 ----------------  ---------------  ----------------------------------------------------------------------------------
5975 url               String           The url for the action (defaults to the form's url)
5976 method            String           The form method to use (defaults to the form's method, or POST if not defined)
5977 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
5978 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
5979                                    validate the form on the client (defaults to false)
5980      * </pre>
5981      * @return {BasicForm} this
5982      */
5983     doAction : function(action, options){
5984         if(typeof action == 'string'){
5985             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5986         }
5987         if(this.fireEvent('beforeaction', this, action) !== false){
5988             this.beforeAction(action);
5989             action.run.defer(100, action);
5990         }
5991         return this;
5992     },
5993     
5994     // private
5995     beforeAction : function(action){
5996         var o = action.options;
5997         
5998         // not really supported yet.. ??
5999         
6000         //if(this.waitMsgTarget === true){
6001             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6002         //}else if(this.waitMsgTarget){
6003         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6004         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6005         //}else {
6006         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6007        // }
6008          
6009     },
6010
6011     // private
6012     afterAction : function(action, success){
6013         this.activeAction = null;
6014         var o = action.options;
6015         
6016         //if(this.waitMsgTarget === true){
6017             this.el.unmask();
6018         //}else if(this.waitMsgTarget){
6019         //    this.waitMsgTarget.unmask();
6020         //}else{
6021         //    Roo.MessageBox.updateProgress(1);
6022         //    Roo.MessageBox.hide();
6023        // }
6024         // 
6025         if(success){
6026             if(o.reset){
6027                 this.reset();
6028             }
6029             Roo.callback(o.success, o.scope, [this, action]);
6030             this.fireEvent('actioncomplete', this, action);
6031             
6032         }else{
6033             
6034             // failure condition..
6035             // we have a scenario where updates need confirming.
6036             // eg. if a locking scenario exists..
6037             // we look for { errors : { needs_confirm : true }} in the response.
6038             if (
6039                 (typeof(action.result) != 'undefined')  &&
6040                 (typeof(action.result.errors) != 'undefined')  &&
6041                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6042            ){
6043                 var _t = this;
6044                 Roo.log("not supported yet");
6045                  /*
6046                 
6047                 Roo.MessageBox.confirm(
6048                     "Change requires confirmation",
6049                     action.result.errorMsg,
6050                     function(r) {
6051                         if (r != 'yes') {
6052                             return;
6053                         }
6054                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6055                     }
6056                     
6057                 );
6058                 */
6059                 
6060                 
6061                 return;
6062             }
6063             
6064             Roo.callback(o.failure, o.scope, [this, action]);
6065             // show an error message if no failed handler is set..
6066             if (!this.hasListener('actionfailed')) {
6067                 Roo.log("need to add dialog support");
6068                 /*
6069                 Roo.MessageBox.alert("Error",
6070                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6071                         action.result.errorMsg :
6072                         "Saving Failed, please check your entries or try again"
6073                 );
6074                 */
6075             }
6076             
6077             this.fireEvent('actionfailed', this, action);
6078         }
6079         
6080     },
6081     /**
6082      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6083      * @param {String} id The value to search for
6084      * @return Field
6085      */
6086     findField : function(id){
6087         var items = this.getItems();
6088         var field = items.get(id);
6089         if(!field){
6090              items.each(function(f){
6091                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6092                     field = f;
6093                     return false;
6094                 }
6095                 return true;
6096             });
6097         }
6098         return field || null;
6099     },
6100      /**
6101      * Mark fields in this form invalid in bulk.
6102      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6103      * @return {BasicForm} this
6104      */
6105     markInvalid : function(errors){
6106         if(errors instanceof Array){
6107             for(var i = 0, len = errors.length; i < len; i++){
6108                 var fieldError = errors[i];
6109                 var f = this.findField(fieldError.id);
6110                 if(f){
6111                     f.markInvalid(fieldError.msg);
6112                 }
6113             }
6114         }else{
6115             var field, id;
6116             for(id in errors){
6117                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6118                     field.markInvalid(errors[id]);
6119                 }
6120             }
6121         }
6122         //Roo.each(this.childForms || [], function (f) {
6123         //    f.markInvalid(errors);
6124         //});
6125         
6126         return this;
6127     },
6128
6129     /**
6130      * Set values for fields in this form in bulk.
6131      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6132      * @return {BasicForm} this
6133      */
6134     setValues : function(values){
6135         if(values instanceof Array){ // array of objects
6136             for(var i = 0, len = values.length; i < len; i++){
6137                 var v = values[i];
6138                 var f = this.findField(v.id);
6139                 if(f){
6140                     f.setValue(v.value);
6141                     if(this.trackResetOnLoad){
6142                         f.originalValue = f.getValue();
6143                     }
6144                 }
6145             }
6146         }else{ // object hash
6147             var field, id;
6148             for(id in values){
6149                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6150                     
6151                     if (field.setFromData && 
6152                         field.valueField && 
6153                         field.displayField &&
6154                         // combos' with local stores can 
6155                         // be queried via setValue()
6156                         // to set their value..
6157                         (field.store && !field.store.isLocal)
6158                         ) {
6159                         // it's a combo
6160                         var sd = { };
6161                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6162                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6163                         field.setFromData(sd);
6164                         
6165                     } else {
6166                         field.setValue(values[id]);
6167                     }
6168                     
6169                     
6170                     if(this.trackResetOnLoad){
6171                         field.originalValue = field.getValue();
6172                     }
6173                 }
6174             }
6175         }
6176          
6177         //Roo.each(this.childForms || [], function (f) {
6178         //    f.setValues(values);
6179         //});
6180                 
6181         return this;
6182     },
6183
6184     /**
6185      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6186      * they are returned as an array.
6187      * @param {Boolean} asString
6188      * @return {Object}
6189      */
6190     getValues : function(asString){
6191         //if (this.childForms) {
6192             // copy values from the child forms
6193         //    Roo.each(this.childForms, function (f) {
6194         //        this.setValues(f.getValues());
6195         //    }, this);
6196         //}
6197         
6198         
6199         
6200         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6201         if(asString === true){
6202             return fs;
6203         }
6204         return Roo.urlDecode(fs);
6205     },
6206     
6207     /**
6208      * Returns the fields in this form as an object with key/value pairs. 
6209      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6210      * @return {Object}
6211      */
6212     getFieldValues : function(with_hidden)
6213     {
6214         var items = this.getItems();
6215         var ret = {};
6216         items.each(function(f){
6217             if (!f.getName()) {
6218                 return;
6219             }
6220             var v = f.getValue();
6221             if (f.inputType =='radio') {
6222                 if (typeof(ret[f.getName()]) == 'undefined') {
6223                     ret[f.getName()] = ''; // empty..
6224                 }
6225                 
6226                 if (!f.el.dom.checked) {
6227                     return;
6228                     
6229                 }
6230                 v = f.el.dom.value;
6231                 
6232             }
6233             
6234             // not sure if this supported any more..
6235             if ((typeof(v) == 'object') && f.getRawValue) {
6236                 v = f.getRawValue() ; // dates..
6237             }
6238             // combo boxes where name != hiddenName...
6239             if (f.name != f.getName()) {
6240                 ret[f.name] = f.getRawValue();
6241             }
6242             ret[f.getName()] = v;
6243         });
6244         
6245         return ret;
6246     },
6247
6248     /**
6249      * Clears all invalid messages in this form.
6250      * @return {BasicForm} this
6251      */
6252     clearInvalid : function(){
6253         var items = this.getItems();
6254         
6255         items.each(function(f){
6256            f.clearInvalid();
6257         });
6258         
6259         
6260         
6261         return this;
6262     },
6263
6264     /**
6265      * Resets this form.
6266      * @return {BasicForm} this
6267      */
6268     reset : function(){
6269         var items = this.getItems();
6270         items.each(function(f){
6271             f.reset();
6272         });
6273         
6274         Roo.each(this.childForms || [], function (f) {
6275             f.reset();
6276         });
6277        
6278         
6279         return this;
6280     },
6281     getItems : function()
6282     {
6283         var r=new Roo.util.MixedCollection(false, function(o){
6284             return o.id || (o.id = Roo.id());
6285         });
6286         var iter = function(el) {
6287             if (el.inputEl) {
6288                 r.add(el);
6289             }
6290             if (!el.items) {
6291                 return;
6292             }
6293             Roo.each(el.items,function(e) {
6294                 iter(e);
6295             });
6296             
6297             
6298         };
6299         iter(this);
6300         return r;
6301         
6302         
6303         
6304         
6305     }
6306     
6307 });
6308
6309  
6310 /*
6311  * Based on:
6312  * Ext JS Library 1.1.1
6313  * Copyright(c) 2006-2007, Ext JS, LLC.
6314  *
6315  * Originally Released Under LGPL - original licence link has changed is not relivant.
6316  *
6317  * Fork - LGPL
6318  * <script type="text/javascript">
6319  */
6320 /**
6321  * @class Roo.form.VTypes
6322  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6323  * @singleton
6324  */
6325 Roo.form.VTypes = function(){
6326     // closure these in so they are only created once.
6327     var alpha = /^[a-zA-Z_]+$/;
6328     var alphanum = /^[a-zA-Z0-9_]+$/;
6329     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6330     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6331
6332     // All these messages and functions are configurable
6333     return {
6334         /**
6335          * The function used to validate email addresses
6336          * @param {String} value The email address
6337          */
6338         'email' : function(v){
6339             return email.test(v);
6340         },
6341         /**
6342          * The error text to display when the email validation function returns false
6343          * @type String
6344          */
6345         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6346         /**
6347          * The keystroke filter mask to be applied on email input
6348          * @type RegExp
6349          */
6350         'emailMask' : /[a-z0-9_\.\-@]/i,
6351
6352         /**
6353          * The function used to validate URLs
6354          * @param {String} value The URL
6355          */
6356         'url' : function(v){
6357             return url.test(v);
6358         },
6359         /**
6360          * The error text to display when the url validation function returns false
6361          * @type String
6362          */
6363         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6364         
6365         /**
6366          * The function used to validate alpha values
6367          * @param {String} value The value
6368          */
6369         'alpha' : function(v){
6370             return alpha.test(v);
6371         },
6372         /**
6373          * The error text to display when the alpha validation function returns false
6374          * @type String
6375          */
6376         'alphaText' : 'This field should only contain letters and _',
6377         /**
6378          * The keystroke filter mask to be applied on alpha input
6379          * @type RegExp
6380          */
6381         'alphaMask' : /[a-z_]/i,
6382
6383         /**
6384          * The function used to validate alphanumeric values
6385          * @param {String} value The value
6386          */
6387         'alphanum' : function(v){
6388             return alphanum.test(v);
6389         },
6390         /**
6391          * The error text to display when the alphanumeric validation function returns false
6392          * @type String
6393          */
6394         'alphanumText' : 'This field should only contain letters, numbers and _',
6395         /**
6396          * The keystroke filter mask to be applied on alphanumeric input
6397          * @type RegExp
6398          */
6399         'alphanumMask' : /[a-z0-9_]/i
6400     };
6401 }();/*
6402  * - LGPL
6403  *
6404  * Input
6405  * 
6406  */
6407
6408 /**
6409  * @class Roo.bootstrap.Input
6410  * @extends Roo.bootstrap.Component
6411  * Bootstrap Input class
6412  * @cfg {Boolean} disabled is it disabled
6413  * @cfg {String} fieldLabel - the label associated
6414  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6415  * @cfg {String} name name of the input
6416  * @cfg {string} fieldLabel - the label associated
6417  * @cfg {string}  inputType - input / file submit ...
6418  * @cfg {string} placeholder - placeholder to put in text.
6419  * @cfg {string}  before - input group add on before
6420  * @cfg {string} after - input group add on after
6421  * @cfg {string} size - (lg|sm) or leave empty..
6422  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6423  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6424  * @cfg {Number} md colspan out of 12 for computer-sized screens
6425  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6426  * @cfg {string} value default value of the input
6427  * @cfg {Number} labelWidth set the width of label (0-12)
6428  * @cfg {String} labelAlign (top|left)
6429  * @cfg {Boolean} readOnly Specifies that the field should be read-only
6430  * @cfg {String} align (left|center|right) Default left
6431  * @cfg {Boolean} formatedValue (true | false) Default false
6432  * 
6433  * 
6434  * @constructor
6435  * Create a new Input
6436  * @param {Object} config The config object
6437  */
6438
6439 Roo.bootstrap.Input = function(config){
6440     Roo.bootstrap.Input.superclass.constructor.call(this, config);
6441    
6442         this.addEvents({
6443             /**
6444              * @event focus
6445              * Fires when this field receives input focus.
6446              * @param {Roo.form.Field} this
6447              */
6448             focus : true,
6449             /**
6450              * @event blur
6451              * Fires when this field loses input focus.
6452              * @param {Roo.form.Field} this
6453              */
6454             blur : true,
6455             /**
6456              * @event specialkey
6457              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
6458              * {@link Roo.EventObject#getKey} to determine which key was pressed.
6459              * @param {Roo.form.Field} this
6460              * @param {Roo.EventObject} e The event object
6461              */
6462             specialkey : true,
6463             /**
6464              * @event change
6465              * Fires just before the field blurs if the field value has changed.
6466              * @param {Roo.form.Field} this
6467              * @param {Mixed} newValue The new value
6468              * @param {Mixed} oldValue The original value
6469              */
6470             change : true,
6471             /**
6472              * @event invalid
6473              * Fires after the field has been marked as invalid.
6474              * @param {Roo.form.Field} this
6475              * @param {String} msg The validation message
6476              */
6477             invalid : true,
6478             /**
6479              * @event valid
6480              * Fires after the field has been validated with no errors.
6481              * @param {Roo.form.Field} this
6482              */
6483             valid : true,
6484              /**
6485              * @event keyup
6486              * Fires after the key up
6487              * @param {Roo.form.Field} this
6488              * @param {Roo.EventObject}  e The event Object
6489              */
6490             keyup : true
6491         });
6492 };
6493
6494 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
6495      /**
6496      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6497       automatic validation (defaults to "keyup").
6498      */
6499     validationEvent : "keyup",
6500      /**
6501      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6502      */
6503     validateOnBlur : true,
6504     /**
6505      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6506      */
6507     validationDelay : 250,
6508      /**
6509      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6510      */
6511     focusClass : "x-form-focus",  // not needed???
6512     
6513        
6514     /**
6515      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6516      */
6517     invalidClass : "has-error",
6518     
6519     /**
6520      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6521      */
6522     selectOnFocus : false,
6523     
6524      /**
6525      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6526      */
6527     maskRe : null,
6528        /**
6529      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6530      */
6531     vtype : null,
6532     
6533       /**
6534      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6535      */
6536     disableKeyFilter : false,
6537     
6538        /**
6539      * @cfg {Boolean} disabled True to disable the field (defaults to false).
6540      */
6541     disabled : false,
6542      /**
6543      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6544      */
6545     allowBlank : true,
6546     /**
6547      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6548      */
6549     blankText : "This field is required",
6550     
6551      /**
6552      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6553      */
6554     minLength : 0,
6555     /**
6556      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6557      */
6558     maxLength : Number.MAX_VALUE,
6559     /**
6560      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6561      */
6562     minLengthText : "The minimum length for this field is {0}",
6563     /**
6564      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6565      */
6566     maxLengthText : "The maximum length for this field is {0}",
6567   
6568     
6569     /**
6570      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6571      * If available, this function will be called only after the basic validators all return true, and will be passed the
6572      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6573      */
6574     validator : null,
6575     /**
6576      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6577      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6578      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
6579      */
6580     regex : null,
6581     /**
6582      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6583      */
6584     regexText : "",
6585     
6586     
6587     
6588     fieldLabel : '',
6589     inputType : 'text',
6590     
6591     name : false,
6592     placeholder: false,
6593     before : false,
6594     after : false,
6595     size : false,
6596     // private
6597     hasFocus : false,
6598     preventMark: false,
6599     isFormField : true,
6600     value : '',
6601     labelWidth : 2,
6602     labelAlign : false,
6603     readOnly : false,
6604     align : false,
6605     formatedValue : false,
6606     
6607     parentLabelAlign : function()
6608     {
6609         var parent = this;
6610         while (parent.parent()) {
6611             parent = parent.parent();
6612             if (typeof(parent.labelAlign) !='undefined') {
6613                 return parent.labelAlign;
6614             }
6615         }
6616         return 'left';
6617         
6618     },
6619     
6620     getAutoCreate : function(){
6621         
6622         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6623         
6624         var id = Roo.id();
6625         
6626         var cfg = {};
6627         
6628         if(this.inputType != 'hidden'){
6629             cfg.cls = 'form-group' //input-group
6630         }
6631         
6632         var input =  {
6633             tag: 'input',
6634             id : id,
6635             type : this.inputType,
6636             value : this.value,
6637             cls : 'form-control',
6638             placeholder : this.placeholder || ''
6639             
6640         };
6641         
6642         if(this.align){
6643             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6644         }
6645         
6646         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6647             input.maxLength = this.maxLength;
6648         }
6649         
6650         if (this.disabled) {
6651             input.disabled=true;
6652         }
6653         
6654         if (this.readOnly) {
6655             input.readonly=true;
6656         }
6657         
6658         if (this.name) {
6659             input.name = this.name;
6660         }
6661         if (this.size) {
6662             input.cls += ' input-' + this.size;
6663         }
6664         var settings=this;
6665         ['xs','sm','md','lg'].map(function(size){
6666             if (settings[size]) {
6667                 cfg.cls += ' col-' + size + '-' + settings[size];
6668             }
6669         });
6670         
6671         var inputblock = input;
6672         
6673         if (this.before || this.after) {
6674             
6675             inputblock = {
6676                 cls : 'input-group',
6677                 cn :  [] 
6678             };
6679             if (this.before && typeof(this.before) == 'string') {
6680                 
6681                 inputblock.cn.push({
6682                     tag :'span',
6683                     cls : 'roo-input-before input-group-addon',
6684                     html : this.before
6685                 });
6686             }
6687             if (this.before && typeof(this.before) == 'object') {
6688                 this.before = Roo.factory(this.before);
6689                 Roo.log(this.before);
6690                 inputblock.cn.push({
6691                     tag :'span',
6692                     cls : 'roo-input-before input-group-' +
6693                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
6694                 });
6695             }
6696             
6697             inputblock.cn.push(input);
6698             
6699             if (this.after && typeof(this.after) == 'string') {
6700                 inputblock.cn.push({
6701                     tag :'span',
6702                     cls : 'roo-input-after input-group-addon',
6703                     html : this.after
6704                 });
6705             }
6706             if (this.after && typeof(this.after) == 'object') {
6707                 this.after = Roo.factory(this.after);
6708                 Roo.log(this.after);
6709                 inputblock.cn.push({
6710                     tag :'span',
6711                     cls : 'roo-input-after input-group-' +
6712                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
6713                 });
6714             }
6715         };
6716         
6717         if (align ==='left' && this.fieldLabel.length) {
6718                 Roo.log("left and has label");
6719                 cfg.cn = [
6720                     
6721                     {
6722                         tag: 'label',
6723                         'for' :  id,
6724                         cls : 'control-label col-sm-' + this.labelWidth,
6725                         html : this.fieldLabel
6726                         
6727                     },
6728                     {
6729                         cls : "col-sm-" + (12 - this.labelWidth), 
6730                         cn: [
6731                             inputblock
6732                         ]
6733                     }
6734                     
6735                 ];
6736         } else if ( this.fieldLabel.length) {
6737                 Roo.log(" label");
6738                  cfg.cn = [
6739                    
6740                     {
6741                         tag: 'label',
6742                         //cls : 'input-group-addon',
6743                         html : this.fieldLabel
6744                         
6745                     },
6746                     
6747                     inputblock
6748                     
6749                 ];
6750
6751         } else {
6752             
6753                 Roo.log(" no label && no align");
6754                 cfg.cn = [
6755                     
6756                         inputblock
6757                     
6758                 ];
6759                 
6760                 
6761         };
6762         Roo.log('input-parentType: ' + this.parentType);
6763         
6764         if (this.parentType === 'Navbar' &&  this.parent().bar) {
6765            cfg.cls += ' navbar-form';
6766            Roo.log(cfg);
6767         }
6768         
6769         return cfg;
6770         
6771     },
6772     /**
6773      * return the real input element.
6774      */
6775     inputEl: function ()
6776     {
6777         return this.el.select('input.form-control',true).first();
6778     },
6779     setDisabled : function(v)
6780     {
6781         var i  = this.inputEl().dom;
6782         if (!v) {
6783             i.removeAttribute('disabled');
6784             return;
6785             
6786         }
6787         i.setAttribute('disabled','true');
6788     },
6789     initEvents : function()
6790     {
6791         
6792         this.inputEl().on("keydown" , this.fireKey,  this);
6793         this.inputEl().on("focus", this.onFocus,  this);
6794         this.inputEl().on("blur", this.onBlur,  this);
6795         
6796         this.inputEl().relayEvent('keyup', this);
6797
6798         // reference to original value for reset
6799         this.originalValue = this.getValue();
6800         //Roo.form.TextField.superclass.initEvents.call(this);
6801         if(this.validationEvent == 'keyup'){
6802             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6803             this.inputEl().on('keyup', this.filterValidation, this);
6804         }
6805         else if(this.validationEvent !== false){
6806             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6807         }
6808         
6809         if(this.selectOnFocus){
6810             this.on("focus", this.preFocus, this);
6811             
6812         }
6813         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6814             this.inputEl().on("keypress", this.filterKeys, this);
6815         }
6816        /* if(this.grow){
6817             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
6818             this.el.on("click", this.autoSize,  this);
6819         }
6820         */
6821         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6822             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6823         }
6824         
6825         if (typeof(this.before) == 'object') {
6826             this.before.render(this.el.select('.roo-input-before',true).first());
6827         }
6828         if (typeof(this.after) == 'object') {
6829             this.after.render(this.el.select('.roo-input-after',true).first());
6830         }
6831         
6832         
6833     },
6834     filterValidation : function(e){
6835         if(!e.isNavKeyPress()){
6836             this.validationTask.delay(this.validationDelay);
6837         }
6838     },
6839      /**
6840      * Validates the field value
6841      * @return {Boolean} True if the value is valid, else false
6842      */
6843     validate : function(){
6844         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6845         if(this.disabled || this.validateValue(this.getRawValue())){
6846             this.clearInvalid();
6847             return true;
6848         }
6849         return false;
6850     },
6851     
6852     
6853     /**
6854      * Validates a value according to the field's validation rules and marks the field as invalid
6855      * if the validation fails
6856      * @param {Mixed} value The value to validate
6857      * @return {Boolean} True if the value is valid, else false
6858      */
6859     validateValue : function(value){
6860         if(value.length < 1)  { // if it's blank
6861              if(this.allowBlank){
6862                 this.clearInvalid();
6863                 return true;
6864              }else{
6865                 this.markInvalid(this.blankText);
6866                 return false;
6867              }
6868         }
6869         if(value.length < this.minLength){
6870             this.markInvalid(String.format(this.minLengthText, this.minLength));
6871             return false;
6872         }
6873         if(value.length > this.maxLength){
6874             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6875             return false;
6876         }
6877         if(this.vtype){
6878             var vt = Roo.form.VTypes;
6879             if(!vt[this.vtype](value, this)){
6880                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6881                 return false;
6882             }
6883         }
6884         if(typeof this.validator == "function"){
6885             var msg = this.validator(value);
6886             if(msg !== true){
6887                 this.markInvalid(msg);
6888                 return false;
6889             }
6890         }
6891         if(this.regex && !this.regex.test(value)){
6892             this.markInvalid(this.regexText);
6893             return false;
6894         }
6895         return true;
6896     },
6897
6898     
6899     
6900      // private
6901     fireKey : function(e){
6902         //Roo.log('field ' + e.getKey());
6903         if(e.isNavKeyPress()){
6904             this.fireEvent("specialkey", this, e);
6905         }
6906     },
6907     focus : function (selectText){
6908         if(this.rendered){
6909             this.inputEl().focus();
6910             if(selectText === true){
6911                 this.inputEl().dom.select();
6912             }
6913         }
6914         return this;
6915     } ,
6916     
6917     onFocus : function(){
6918         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6919            // this.el.addClass(this.focusClass);
6920         }
6921         if(!this.hasFocus){
6922             this.hasFocus = true;
6923             this.startValue = this.getValue();
6924             this.fireEvent("focus", this);
6925         }
6926     },
6927     
6928     beforeBlur : Roo.emptyFn,
6929
6930     
6931     // private
6932     onBlur : function(){
6933         this.beforeBlur();
6934         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6935             //this.el.removeClass(this.focusClass);
6936         }
6937         this.hasFocus = false;
6938         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6939             this.validate();
6940         }
6941         var v = this.getValue();
6942         if(String(v) !== String(this.startValue)){
6943             this.fireEvent('change', this, v, this.startValue);
6944         }
6945         this.fireEvent("blur", this);
6946     },
6947     
6948     /**
6949      * Resets the current field value to the originally loaded value and clears any validation messages
6950      */
6951     reset : function(){
6952         this.setValue(this.originalValue);
6953         this.clearInvalid();
6954     },
6955      /**
6956      * Returns the name of the field
6957      * @return {Mixed} name The name field
6958      */
6959     getName: function(){
6960         return this.name;
6961     },
6962      /**
6963      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
6964      * @return {Mixed} value The field value
6965      */
6966     getValue : function(){
6967         /*
6968          * Not sure why getValue and getRawValue are doing the same thing..
6969          * 
6970          */
6971         if(this.formatedValue){
6972             return this.value;
6973         }
6974         
6975         return this.inputEl().getValue();
6976     },
6977     /**
6978      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
6979      * @return {Mixed} value The field value
6980      */
6981     getRawValue : function(){
6982         var v = this.inputEl().getValue();
6983         
6984         return v;
6985     },
6986     
6987     /**
6988      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
6989      * @param {Mixed} value The value to set
6990      */
6991     setRawValue : function(v){
6992         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6993     },
6994     
6995     selectText : function(start, end){
6996         var v = this.getRawValue();
6997         if(v.length > 0){
6998             start = start === undefined ? 0 : start;
6999             end = end === undefined ? v.length : end;
7000             var d = this.inputEl().dom;
7001             if(d.setSelectionRange){
7002                 d.setSelectionRange(start, end);
7003             }else if(d.createTextRange){
7004                 var range = d.createTextRange();
7005                 range.moveStart("character", start);
7006                 range.moveEnd("character", v.length-end);
7007                 range.select();
7008             }
7009         }
7010     },
7011     
7012     /**
7013      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7014      * @param {Mixed} value The value to set
7015      */
7016     setValue : function(v){
7017         this.value = v;
7018         if(this.rendered){
7019             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7020             this.validate();
7021         }
7022     },
7023     
7024     /*
7025     processValue : function(value){
7026         if(this.stripCharsRe){
7027             var newValue = value.replace(this.stripCharsRe, '');
7028             if(newValue !== value){
7029                 this.setRawValue(newValue);
7030                 return newValue;
7031             }
7032         }
7033         return value;
7034     },
7035   */
7036     preFocus : function(){
7037         
7038         if(this.selectOnFocus){
7039             this.inputEl().dom.select();
7040         }
7041     },
7042     filterKeys : function(e){
7043         var k = e.getKey();
7044         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7045             return;
7046         }
7047         var c = e.getCharCode(), cc = String.fromCharCode(c);
7048         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7049             return;
7050         }
7051         if(!this.maskRe.test(cc)){
7052             e.stopEvent();
7053         }
7054     },
7055      /**
7056      * Clear any invalid styles/messages for this field
7057      */
7058     clearInvalid : function(){
7059         
7060         if(!this.el || this.preventMark){ // not rendered
7061             return;
7062         }
7063         this.el.removeClass(this.invalidClass);
7064         /*
7065         switch(this.msgTarget){
7066             case 'qtip':
7067                 this.el.dom.qtip = '';
7068                 break;
7069             case 'title':
7070                 this.el.dom.title = '';
7071                 break;
7072             case 'under':
7073                 if(this.errorEl){
7074                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7075                 }
7076                 break;
7077             case 'side':
7078                 if(this.errorIcon){
7079                     this.errorIcon.dom.qtip = '';
7080                     this.errorIcon.hide();
7081                     this.un('resize', this.alignErrorIcon, this);
7082                 }
7083                 break;
7084             default:
7085                 var t = Roo.getDom(this.msgTarget);
7086                 t.innerHTML = '';
7087                 t.style.display = 'none';
7088                 break;
7089         }
7090         */
7091         this.fireEvent('valid', this);
7092     },
7093      /**
7094      * Mark this field as invalid
7095      * @param {String} msg The validation message
7096      */
7097     markInvalid : function(msg){
7098         if(!this.el  || this.preventMark){ // not rendered
7099             return;
7100         }
7101         this.el.addClass(this.invalidClass);
7102         /*
7103         msg = msg || this.invalidText;
7104         switch(this.msgTarget){
7105             case 'qtip':
7106                 this.el.dom.qtip = msg;
7107                 this.el.dom.qclass = 'x-form-invalid-tip';
7108                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7109                     Roo.QuickTips.enable();
7110                 }
7111                 break;
7112             case 'title':
7113                 this.el.dom.title = msg;
7114                 break;
7115             case 'under':
7116                 if(!this.errorEl){
7117                     var elp = this.el.findParent('.x-form-element', 5, true);
7118                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7119                     this.errorEl.setWidth(elp.getWidth(true)-20);
7120                 }
7121                 this.errorEl.update(msg);
7122                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7123                 break;
7124             case 'side':
7125                 if(!this.errorIcon){
7126                     var elp = this.el.findParent('.x-form-element', 5, true);
7127                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7128                 }
7129                 this.alignErrorIcon();
7130                 this.errorIcon.dom.qtip = msg;
7131                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7132                 this.errorIcon.show();
7133                 this.on('resize', this.alignErrorIcon, this);
7134                 break;
7135             default:
7136                 var t = Roo.getDom(this.msgTarget);
7137                 t.innerHTML = msg;
7138                 t.style.display = this.msgDisplay;
7139                 break;
7140         }
7141         */
7142         this.fireEvent('invalid', this, msg);
7143     },
7144     // private
7145     SafariOnKeyDown : function(event)
7146     {
7147         // this is a workaround for a password hang bug on chrome/ webkit.
7148         
7149         var isSelectAll = false;
7150         
7151         if(this.inputEl().dom.selectionEnd > 0){
7152             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7153         }
7154         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7155             event.preventDefault();
7156             this.setValue('');
7157             return;
7158         }
7159         
7160         if(isSelectAll){ // backspace and delete key
7161             
7162             event.preventDefault();
7163             // this is very hacky as keydown always get's upper case.
7164             //
7165             var cc = String.fromCharCode(event.getCharCode());
7166             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7167             
7168         }
7169     },
7170     adjustWidth : function(tag, w){
7171         tag = tag.toLowerCase();
7172         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7173             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7174                 if(tag == 'input'){
7175                     return w + 2;
7176                 }
7177                 if(tag == 'textarea'){
7178                     return w-2;
7179                 }
7180             }else if(Roo.isOpera){
7181                 if(tag == 'input'){
7182                     return w + 2;
7183                 }
7184                 if(tag == 'textarea'){
7185                     return w-2;
7186                 }
7187             }
7188         }
7189         return w;
7190     }
7191     
7192 });
7193
7194  
7195 /*
7196  * - LGPL
7197  *
7198  * Input
7199  * 
7200  */
7201
7202 /**
7203  * @class Roo.bootstrap.TextArea
7204  * @extends Roo.bootstrap.Input
7205  * Bootstrap TextArea class
7206  * @cfg {Number} cols Specifies the visible width of a text area
7207  * @cfg {Number} rows Specifies the visible number of lines in a text area
7208  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7209  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7210  * @cfg {string} html text
7211  * 
7212  * @constructor
7213  * Create a new TextArea
7214  * @param {Object} config The config object
7215  */
7216
7217 Roo.bootstrap.TextArea = function(config){
7218     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7219    
7220 };
7221
7222 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7223      
7224     cols : false,
7225     rows : 5,
7226     readOnly : false,
7227     warp : 'soft',
7228     resize : false,
7229     value: false,
7230     html: false,
7231     
7232     getAutoCreate : function(){
7233         
7234         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7235         
7236         var id = Roo.id();
7237         
7238         var cfg = {};
7239         
7240         var input =  {
7241             tag: 'textarea',
7242             id : id,
7243             warp : this.warp,
7244             rows : this.rows,
7245             value : this.value || '',
7246             html: this.html || '',
7247             cls : 'form-control',
7248             placeholder : this.placeholder || '' 
7249             
7250         };
7251         
7252         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7253             input.maxLength = this.maxLength;
7254         }
7255         
7256         if(this.resize){
7257             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7258         }
7259         
7260         if(this.cols){
7261             input.cols = this.cols;
7262         }
7263         
7264         if (this.readOnly) {
7265             input.readonly = true;
7266         }
7267         
7268         if (this.name) {
7269             input.name = this.name;
7270         }
7271         
7272         if (this.size) {
7273             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7274         }
7275         
7276         var settings=this;
7277         ['xs','sm','md','lg'].map(function(size){
7278             if (settings[size]) {
7279                 cfg.cls += ' col-' + size + '-' + settings[size];
7280             }
7281         });
7282         
7283         var inputblock = input;
7284         
7285         if (this.before || this.after) {
7286             
7287             inputblock = {
7288                 cls : 'input-group',
7289                 cn :  [] 
7290             };
7291             if (this.before) {
7292                 inputblock.cn.push({
7293                     tag :'span',
7294                     cls : 'input-group-addon',
7295                     html : this.before
7296                 });
7297             }
7298             inputblock.cn.push(input);
7299             if (this.after) {
7300                 inputblock.cn.push({
7301                     tag :'span',
7302                     cls : 'input-group-addon',
7303                     html : this.after
7304                 });
7305             }
7306             
7307         }
7308         
7309         if (align ==='left' && this.fieldLabel.length) {
7310                 Roo.log("left and has label");
7311                 cfg.cn = [
7312                     
7313                     {
7314                         tag: 'label',
7315                         'for' :  id,
7316                         cls : 'control-label col-sm-' + this.labelWidth,
7317                         html : this.fieldLabel
7318                         
7319                     },
7320                     {
7321                         cls : "col-sm-" + (12 - this.labelWidth), 
7322                         cn: [
7323                             inputblock
7324                         ]
7325                     }
7326                     
7327                 ];
7328         } else if ( this.fieldLabel.length) {
7329                 Roo.log(" label");
7330                  cfg.cn = [
7331                    
7332                     {
7333                         tag: 'label',
7334                         //cls : 'input-group-addon',
7335                         html : this.fieldLabel
7336                         
7337                     },
7338                     
7339                     inputblock
7340                     
7341                 ];
7342
7343         } else {
7344             
7345                    Roo.log(" no label && no align");
7346                 cfg.cn = [
7347                     
7348                         inputblock
7349                     
7350                 ];
7351                 
7352                 
7353         }
7354         
7355         if (this.disabled) {
7356             input.disabled=true;
7357         }
7358         
7359         return cfg;
7360         
7361     },
7362     /**
7363      * return the real textarea element.
7364      */
7365     inputEl: function ()
7366     {
7367         return this.el.select('textarea.form-control',true).first();
7368     }
7369 });
7370
7371  
7372 /*
7373  * - LGPL
7374  *
7375  * trigger field - base class for combo..
7376  * 
7377  */
7378  
7379 /**
7380  * @class Roo.bootstrap.TriggerField
7381  * @extends Roo.bootstrap.Input
7382  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7383  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7384  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7385  * for which you can provide a custom implementation.  For example:
7386  * <pre><code>
7387 var trigger = new Roo.bootstrap.TriggerField();
7388 trigger.onTriggerClick = myTriggerFn;
7389 trigger.applyTo('my-field');
7390 </code></pre>
7391  *
7392  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7393  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7394  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
7395  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7396  * @constructor
7397  * Create a new TriggerField.
7398  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7399  * to the base TextField)
7400  */
7401 Roo.bootstrap.TriggerField = function(config){
7402     this.mimicing = false;
7403     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7404 };
7405
7406 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
7407     /**
7408      * @cfg {String} triggerClass A CSS class to apply to the trigger
7409      */
7410      /**
7411      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7412      */
7413     hideTrigger:false,
7414
7415     /** @cfg {Boolean} grow @hide */
7416     /** @cfg {Number} growMin @hide */
7417     /** @cfg {Number} growMax @hide */
7418
7419     /**
7420      * @hide 
7421      * @method
7422      */
7423     autoSize: Roo.emptyFn,
7424     // private
7425     monitorTab : true,
7426     // private
7427     deferHeight : true,
7428
7429     
7430     actionMode : 'wrap',
7431     
7432     
7433     
7434     getAutoCreate : function(){
7435        
7436         var parent = this.parent();
7437         
7438         var align = this.labelAlign || this.parentLabelAlign();
7439         
7440         var id = Roo.id();
7441         
7442         var cfg = {
7443             cls: 'form-group' //input-group
7444         };
7445         
7446         
7447         var input =  {
7448             tag: 'input',
7449             id : id,
7450             type : this.inputType,
7451             cls : 'form-control',
7452             autocomplete: 'off',
7453             placeholder : this.placeholder || '' 
7454             
7455         };
7456         if (this.name) {
7457             input.name = this.name;
7458         }
7459         if (this.size) {
7460             input.cls += ' input-' + this.size;
7461         }
7462         
7463         if (this.disabled) {
7464             input.disabled=true;
7465         }
7466         
7467         var inputblock = input;
7468         
7469         if (this.before || this.after) {
7470             
7471             inputblock = {
7472                 cls : 'input-group',
7473                 cn :  [] 
7474             };
7475             if (this.before) {
7476                 inputblock.cn.push({
7477                     tag :'span',
7478                     cls : 'input-group-addon',
7479                     html : this.before
7480                 });
7481             }
7482             inputblock.cn.push(input);
7483             if (this.after) {
7484                 inputblock.cn.push({
7485                     tag :'span',
7486                     cls : 'input-group-addon',
7487                     html : this.after
7488                 });
7489             }
7490             
7491         };
7492         
7493         var box = {
7494             tag: 'div',
7495             cn: [
7496                 {
7497                     tag: 'input',
7498                     type : 'hidden',
7499                     cls: 'form-hidden-field'
7500                 },
7501                 inputblock
7502             ]
7503             
7504         };
7505         
7506         if(this.multiple){
7507             Roo.log('multiple');
7508             
7509             box = {
7510                 tag: 'div',
7511                 cn: [
7512                     {
7513                         tag: 'input',
7514                         type : 'hidden',
7515                         cls: 'form-hidden-field'
7516                     },
7517                     {
7518                         tag: 'ul',
7519                         cls: 'select2-choices',
7520                         cn:[
7521                             {
7522                                 tag: 'li',
7523                                 cls: 'select2-search-field',
7524                                 cn: [
7525
7526                                     inputblock
7527                                 ]
7528                             }
7529                         ]
7530                     }
7531                 ]
7532             }
7533         };
7534         
7535         var combobox = {
7536             cls: 'select2-container input-group',
7537             cn: [
7538                 box,
7539                 {
7540                     tag: 'ul',
7541                     cls: 'typeahead typeahead-long dropdown-menu',
7542                     style: 'display:none'
7543                 }
7544             ]
7545         };
7546         
7547         if(!this.multiple){
7548             combobox.cn.push({
7549                 tag :'span',
7550                 cls : 'input-group-addon btn dropdown-toggle',
7551                 cn : [
7552                     {
7553                         tag: 'span',
7554                         cls: 'caret'
7555                     },
7556                     {
7557                         tag: 'span',
7558                         cls: 'combobox-clear',
7559                         cn  : [
7560                             {
7561                                 tag : 'i',
7562                                 cls: 'icon-remove'
7563                             }
7564                         ]
7565                     }
7566                 ]
7567
7568             })
7569         }
7570         
7571         if(this.multiple){
7572             combobox.cls += ' select2-container-multi';
7573         }
7574         
7575         if (align ==='left' && this.fieldLabel.length) {
7576             
7577                 Roo.log("left and has label");
7578                 cfg.cn = [
7579                     
7580                     {
7581                         tag: 'label',
7582                         'for' :  id,
7583                         cls : 'control-label col-sm-' + this.labelWidth,
7584                         html : this.fieldLabel
7585                         
7586                     },
7587                     {
7588                         cls : "col-sm-" + (12 - this.labelWidth), 
7589                         cn: [
7590                             combobox
7591                         ]
7592                     }
7593                     
7594                 ];
7595         } else if ( this.fieldLabel.length) {
7596                 Roo.log(" label");
7597                  cfg.cn = [
7598                    
7599                     {
7600                         tag: 'label',
7601                         //cls : 'input-group-addon',
7602                         html : this.fieldLabel
7603                         
7604                     },
7605                     
7606                     combobox
7607                     
7608                 ];
7609
7610         } else {
7611             
7612                 Roo.log(" no label && no align");
7613                 cfg = combobox
7614                      
7615                 
7616         }
7617          
7618         var settings=this;
7619         ['xs','sm','md','lg'].map(function(size){
7620             if (settings[size]) {
7621                 cfg.cls += ' col-' + size + '-' + settings[size];
7622             }
7623         });
7624         
7625         return cfg;
7626         
7627     },
7628     
7629     
7630     
7631     // private
7632     onResize : function(w, h){
7633 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7634 //        if(typeof w == 'number'){
7635 //            var x = w - this.trigger.getWidth();
7636 //            this.inputEl().setWidth(this.adjustWidth('input', x));
7637 //            this.trigger.setStyle('left', x+'px');
7638 //        }
7639     },
7640
7641     // private
7642     adjustSize : Roo.BoxComponent.prototype.adjustSize,
7643
7644     // private
7645     getResizeEl : function(){
7646         return this.inputEl();
7647     },
7648
7649     // private
7650     getPositionEl : function(){
7651         return this.inputEl();
7652     },
7653
7654     // private
7655     alignErrorIcon : function(){
7656         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7657     },
7658
7659     // private
7660     initEvents : function(){
7661         
7662         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7663         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7664         if(!this.multiple){
7665             this.trigger = this.el.select('span.dropdown-toggle',true).first();
7666             if(this.hideTrigger){
7667                 this.trigger.setDisplayed(false);
7668             }
7669             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7670         }
7671         
7672         if(this.multiple){
7673             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7674         }
7675         
7676         //this.trigger.addClassOnOver('x-form-trigger-over');
7677         //this.trigger.addClassOnClick('x-form-trigger-click');
7678         
7679         //if(!this.width){
7680         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7681         //}
7682     },
7683
7684     // private
7685     initTrigger : function(){
7686        
7687     },
7688
7689     // private
7690     onDestroy : function(){
7691         if(this.trigger){
7692             this.trigger.removeAllListeners();
7693           //  this.trigger.remove();
7694         }
7695         //if(this.wrap){
7696         //    this.wrap.remove();
7697         //}
7698         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7699     },
7700
7701     // private
7702     onFocus : function(){
7703         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7704         /*
7705         if(!this.mimicing){
7706             this.wrap.addClass('x-trigger-wrap-focus');
7707             this.mimicing = true;
7708             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7709             if(this.monitorTab){
7710                 this.el.on("keydown", this.checkTab, this);
7711             }
7712         }
7713         */
7714     },
7715
7716     // private
7717     checkTab : function(e){
7718         if(e.getKey() == e.TAB){
7719             this.triggerBlur();
7720         }
7721     },
7722
7723     // private
7724     onBlur : function(){
7725         // do nothing
7726     },
7727
7728     // private
7729     mimicBlur : function(e, t){
7730         /*
7731         if(!this.wrap.contains(t) && this.validateBlur()){
7732             this.triggerBlur();
7733         }
7734         */
7735     },
7736
7737     // private
7738     triggerBlur : function(){
7739         this.mimicing = false;
7740         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7741         if(this.monitorTab){
7742             this.el.un("keydown", this.checkTab, this);
7743         }
7744         //this.wrap.removeClass('x-trigger-wrap-focus');
7745         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7746     },
7747
7748     // private
7749     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7750     validateBlur : function(e, t){
7751         return true;
7752     },
7753
7754     // private
7755     onDisable : function(){
7756         this.inputEl().dom.disabled = true;
7757         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7758         //if(this.wrap){
7759         //    this.wrap.addClass('x-item-disabled');
7760         //}
7761     },
7762
7763     // private
7764     onEnable : function(){
7765         this.inputEl().dom.disabled = false;
7766         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7767         //if(this.wrap){
7768         //    this.el.removeClass('x-item-disabled');
7769         //}
7770     },
7771
7772     // private
7773     onShow : function(){
7774         var ae = this.getActionEl();
7775         
7776         if(ae){
7777             ae.dom.style.display = '';
7778             ae.dom.style.visibility = 'visible';
7779         }
7780     },
7781
7782     // private
7783     
7784     onHide : function(){
7785         var ae = this.getActionEl();
7786         ae.dom.style.display = 'none';
7787     },
7788
7789     /**
7790      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
7791      * by an implementing function.
7792      * @method
7793      * @param {EventObject} e
7794      */
7795     onTriggerClick : Roo.emptyFn
7796 });
7797  /*
7798  * Based on:
7799  * Ext JS Library 1.1.1
7800  * Copyright(c) 2006-2007, Ext JS, LLC.
7801  *
7802  * Originally Released Under LGPL - original licence link has changed is not relivant.
7803  *
7804  * Fork - LGPL
7805  * <script type="text/javascript">
7806  */
7807
7808
7809 /**
7810  * @class Roo.data.SortTypes
7811  * @singleton
7812  * Defines the default sorting (casting?) comparison functions used when sorting data.
7813  */
7814 Roo.data.SortTypes = {
7815     /**
7816      * Default sort that does nothing
7817      * @param {Mixed} s The value being converted
7818      * @return {Mixed} The comparison value
7819      */
7820     none : function(s){
7821         return s;
7822     },
7823     
7824     /**
7825      * The regular expression used to strip tags
7826      * @type {RegExp}
7827      * @property
7828      */
7829     stripTagsRE : /<\/?[^>]+>/gi,
7830     
7831     /**
7832      * Strips all HTML tags to sort on text only
7833      * @param {Mixed} s The value being converted
7834      * @return {String} The comparison value
7835      */
7836     asText : function(s){
7837         return String(s).replace(this.stripTagsRE, "");
7838     },
7839     
7840     /**
7841      * Strips all HTML tags to sort on text only - Case insensitive
7842      * @param {Mixed} s The value being converted
7843      * @return {String} The comparison value
7844      */
7845     asUCText : function(s){
7846         return String(s).toUpperCase().replace(this.stripTagsRE, "");
7847     },
7848     
7849     /**
7850      * Case insensitive string
7851      * @param {Mixed} s The value being converted
7852      * @return {String} The comparison value
7853      */
7854     asUCString : function(s) {
7855         return String(s).toUpperCase();
7856     },
7857     
7858     /**
7859      * Date sorting
7860      * @param {Mixed} s The value being converted
7861      * @return {Number} The comparison value
7862      */
7863     asDate : function(s) {
7864         if(!s){
7865             return 0;
7866         }
7867         if(s instanceof Date){
7868             return s.getTime();
7869         }
7870         return Date.parse(String(s));
7871     },
7872     
7873     /**
7874      * Float sorting
7875      * @param {Mixed} s The value being converted
7876      * @return {Float} The comparison value
7877      */
7878     asFloat : function(s) {
7879         var val = parseFloat(String(s).replace(/,/g, ""));
7880         if(isNaN(val)) val = 0;
7881         return val;
7882     },
7883     
7884     /**
7885      * Integer sorting
7886      * @param {Mixed} s The value being converted
7887      * @return {Number} The comparison value
7888      */
7889     asInt : function(s) {
7890         var val = parseInt(String(s).replace(/,/g, ""));
7891         if(isNaN(val)) val = 0;
7892         return val;
7893     }
7894 };/*
7895  * Based on:
7896  * Ext JS Library 1.1.1
7897  * Copyright(c) 2006-2007, Ext JS, LLC.
7898  *
7899  * Originally Released Under LGPL - original licence link has changed is not relivant.
7900  *
7901  * Fork - LGPL
7902  * <script type="text/javascript">
7903  */
7904
7905 /**
7906 * @class Roo.data.Record
7907  * Instances of this class encapsulate both record <em>definition</em> information, and record
7908  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7909  * to access Records cached in an {@link Roo.data.Store} object.<br>
7910  * <p>
7911  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7912  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7913  * objects.<br>
7914  * <p>
7915  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7916  * @constructor
7917  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7918  * {@link #create}. The parameters are the same.
7919  * @param {Array} data An associative Array of data values keyed by the field name.
7920  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7921  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7922  * not specified an integer id is generated.
7923  */
7924 Roo.data.Record = function(data, id){
7925     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7926     this.data = data;
7927 };
7928
7929 /**
7930  * Generate a constructor for a specific record layout.
7931  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7932  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7933  * Each field definition object may contain the following properties: <ul>
7934  * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
7935  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7936  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7937  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7938  * is being used, then this is a string containing the javascript expression to reference the data relative to 
7939  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7940  * to the data item relative to the record element. If the mapping expression is the same as the field name,
7941  * this may be omitted.</p></li>
7942  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7943  * <ul><li>auto (Default, implies no conversion)</li>
7944  * <li>string</li>
7945  * <li>int</li>
7946  * <li>float</li>
7947  * <li>boolean</li>
7948  * <li>date</li></ul></p></li>
7949  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7950  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7951  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7952  * by the Reader into an object that will be stored in the Record. It is passed the
7953  * following parameters:<ul>
7954  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7955  * </ul></p></li>
7956  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7957  * </ul>
7958  * <br>usage:<br><pre><code>
7959 var TopicRecord = Roo.data.Record.create(
7960     {name: 'title', mapping: 'topic_title'},
7961     {name: 'author', mapping: 'username'},
7962     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7963     {name: 'lastPost', mapping: 'post_time', type: 'date'},
7964     {name: 'lastPoster', mapping: 'user2'},
7965     {name: 'excerpt', mapping: 'post_text'}
7966 );
7967
7968 var myNewRecord = new TopicRecord({
7969     title: 'Do my job please',
7970     author: 'noobie',
7971     totalPosts: 1,
7972     lastPost: new Date(),
7973     lastPoster: 'Animal',
7974     excerpt: 'No way dude!'
7975 });
7976 myStore.add(myNewRecord);
7977 </code></pre>
7978  * @method create
7979  * @static
7980  */
7981 Roo.data.Record.create = function(o){
7982     var f = function(){
7983         f.superclass.constructor.apply(this, arguments);
7984     };
7985     Roo.extend(f, Roo.data.Record);
7986     var p = f.prototype;
7987     p.fields = new Roo.util.MixedCollection(false, function(field){
7988         return field.name;
7989     });
7990     for(var i = 0, len = o.length; i < len; i++){
7991         p.fields.add(new Roo.data.Field(o[i]));
7992     }
7993     f.getField = function(name){
7994         return p.fields.get(name);  
7995     };
7996     return f;
7997 };
7998
7999 Roo.data.Record.AUTO_ID = 1000;
8000 Roo.data.Record.EDIT = 'edit';
8001 Roo.data.Record.REJECT = 'reject';
8002 Roo.data.Record.COMMIT = 'commit';
8003
8004 Roo.data.Record.prototype = {
8005     /**
8006      * Readonly flag - true if this record has been modified.
8007      * @type Boolean
8008      */
8009     dirty : false,
8010     editing : false,
8011     error: null,
8012     modified: null,
8013
8014     // private
8015     join : function(store){
8016         this.store = store;
8017     },
8018
8019     /**
8020      * Set the named field to the specified value.
8021      * @param {String} name The name of the field to set.
8022      * @param {Object} value The value to set the field to.
8023      */
8024     set : function(name, value){
8025         if(this.data[name] == value){
8026             return;
8027         }
8028         this.dirty = true;
8029         if(!this.modified){
8030             this.modified = {};
8031         }
8032         if(typeof this.modified[name] == 'undefined'){
8033             this.modified[name] = this.data[name];
8034         }
8035         this.data[name] = value;
8036         if(!this.editing && this.store){
8037             this.store.afterEdit(this);
8038         }       
8039     },
8040
8041     /**
8042      * Get the value of the named field.
8043      * @param {String} name The name of the field to get the value of.
8044      * @return {Object} The value of the field.
8045      */
8046     get : function(name){
8047         return this.data[name]; 
8048     },
8049
8050     // private
8051     beginEdit : function(){
8052         this.editing = true;
8053         this.modified = {}; 
8054     },
8055
8056     // private
8057     cancelEdit : function(){
8058         this.editing = false;
8059         delete this.modified;
8060     },
8061
8062     // private
8063     endEdit : function(){
8064         this.editing = false;
8065         if(this.dirty && this.store){
8066             this.store.afterEdit(this);
8067         }
8068     },
8069
8070     /**
8071      * Usually called by the {@link Roo.data.Store} which owns the Record.
8072      * Rejects all changes made to the Record since either creation, or the last commit operation.
8073      * Modified fields are reverted to their original values.
8074      * <p>
8075      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8076      * of reject operations.
8077      */
8078     reject : function(){
8079         var m = this.modified;
8080         for(var n in m){
8081             if(typeof m[n] != "function"){
8082                 this.data[n] = m[n];
8083             }
8084         }
8085         this.dirty = false;
8086         delete this.modified;
8087         this.editing = false;
8088         if(this.store){
8089             this.store.afterReject(this);
8090         }
8091     },
8092
8093     /**
8094      * Usually called by the {@link Roo.data.Store} which owns the Record.
8095      * Commits all changes made to the Record since either creation, or the last commit operation.
8096      * <p>
8097      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8098      * of commit operations.
8099      */
8100     commit : function(){
8101         this.dirty = false;
8102         delete this.modified;
8103         this.editing = false;
8104         if(this.store){
8105             this.store.afterCommit(this);
8106         }
8107     },
8108
8109     // private
8110     hasError : function(){
8111         return this.error != null;
8112     },
8113
8114     // private
8115     clearError : function(){
8116         this.error = null;
8117     },
8118
8119     /**
8120      * Creates a copy of this record.
8121      * @param {String} id (optional) A new record id if you don't want to use this record's id
8122      * @return {Record}
8123      */
8124     copy : function(newId) {
8125         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8126     }
8127 };/*
8128  * Based on:
8129  * Ext JS Library 1.1.1
8130  * Copyright(c) 2006-2007, Ext JS, LLC.
8131  *
8132  * Originally Released Under LGPL - original licence link has changed is not relivant.
8133  *
8134  * Fork - LGPL
8135  * <script type="text/javascript">
8136  */
8137
8138
8139
8140 /**
8141  * @class Roo.data.Store
8142  * @extends Roo.util.Observable
8143  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8144  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8145  * <p>
8146  * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8147  * has no knowledge of the format of the data returned by the Proxy.<br>
8148  * <p>
8149  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8150  * instances from the data object. These records are cached and made available through accessor functions.
8151  * @constructor
8152  * Creates a new Store.
8153  * @param {Object} config A config object containing the objects needed for the Store to access data,
8154  * and read the data into Records.
8155  */
8156 Roo.data.Store = function(config){
8157     this.data = new Roo.util.MixedCollection(false);
8158     this.data.getKey = function(o){
8159         return o.id;
8160     };
8161     this.baseParams = {};
8162     // private
8163     this.paramNames = {
8164         "start" : "start",
8165         "limit" : "limit",
8166         "sort" : "sort",
8167         "dir" : "dir",
8168         "multisort" : "_multisort"
8169     };
8170
8171     if(config && config.data){
8172         this.inlineData = config.data;
8173         delete config.data;
8174     }
8175
8176     Roo.apply(this, config);
8177     
8178     if(this.reader){ // reader passed
8179         this.reader = Roo.factory(this.reader, Roo.data);
8180         this.reader.xmodule = this.xmodule || false;
8181         if(!this.recordType){
8182             this.recordType = this.reader.recordType;
8183         }
8184         if(this.reader.onMetaChange){
8185             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8186         }
8187     }
8188
8189     if(this.recordType){
8190         this.fields = this.recordType.prototype.fields;
8191     }
8192     this.modified = [];
8193
8194     this.addEvents({
8195         /**
8196          * @event datachanged
8197          * Fires when the data cache has changed, and a widget which is using this Store
8198          * as a Record cache should refresh its view.
8199          * @param {Store} this
8200          */
8201         datachanged : true,
8202         /**
8203          * @event metachange
8204          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8205          * @param {Store} this
8206          * @param {Object} meta The JSON metadata
8207          */
8208         metachange : true,
8209         /**
8210          * @event add
8211          * Fires when Records have been added to the Store
8212          * @param {Store} this
8213          * @param {Roo.data.Record[]} records The array of Records added
8214          * @param {Number} index The index at which the record(s) were added
8215          */
8216         add : true,
8217         /**
8218          * @event remove
8219          * Fires when a Record has been removed from the Store
8220          * @param {Store} this
8221          * @param {Roo.data.Record} record The Record that was removed
8222          * @param {Number} index The index at which the record was removed
8223          */
8224         remove : true,
8225         /**
8226          * @event update
8227          * Fires when a Record has been updated
8228          * @param {Store} this
8229          * @param {Roo.data.Record} record The Record that was updated
8230          * @param {String} operation The update operation being performed.  Value may be one of:
8231          * <pre><code>
8232  Roo.data.Record.EDIT
8233  Roo.data.Record.REJECT
8234  Roo.data.Record.COMMIT
8235          * </code></pre>
8236          */
8237         update : true,
8238         /**
8239          * @event clear
8240          * Fires when the data cache has been cleared.
8241          * @param {Store} this
8242          */
8243         clear : true,
8244         /**
8245          * @event beforeload
8246          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8247          * the load action will be canceled.
8248          * @param {Store} this
8249          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8250          */
8251         beforeload : true,
8252         /**
8253          * @event beforeloadadd
8254          * Fires after a new set of Records has been loaded.
8255          * @param {Store} this
8256          * @param {Roo.data.Record[]} records The Records that were loaded
8257          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8258          */
8259         beforeloadadd : true,
8260         /**
8261          * @event load
8262          * Fires after a new set of Records has been loaded, before they are added to the store.
8263          * @param {Store} this
8264          * @param {Roo.data.Record[]} records The Records that were loaded
8265          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8266          * @params {Object} return from reader
8267          */
8268         load : true,
8269         /**
8270          * @event loadexception
8271          * Fires if an exception occurs in the Proxy during loading.
8272          * Called with the signature of the Proxy's "loadexception" event.
8273          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8274          * 
8275          * @param {Proxy} 
8276          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8277          * @param {Object} load options 
8278          * @param {Object} jsonData from your request (normally this contains the Exception)
8279          */
8280         loadexception : true
8281     });
8282     
8283     if(this.proxy){
8284         this.proxy = Roo.factory(this.proxy, Roo.data);
8285         this.proxy.xmodule = this.xmodule || false;
8286         this.relayEvents(this.proxy,  ["loadexception"]);
8287     }
8288     this.sortToggle = {};
8289     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8290
8291     Roo.data.Store.superclass.constructor.call(this);
8292
8293     if(this.inlineData){
8294         this.loadData(this.inlineData);
8295         delete this.inlineData;
8296     }
8297 };
8298
8299 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8300      /**
8301     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8302     * without a remote query - used by combo/forms at present.
8303     */
8304     
8305     /**
8306     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8307     */
8308     /**
8309     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8310     */
8311     /**
8312     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8313     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8314     */
8315     /**
8316     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8317     * on any HTTP request
8318     */
8319     /**
8320     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8321     */
8322     /**
8323     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8324     */
8325     multiSort: false,
8326     /**
8327     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8328     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8329     */
8330     remoteSort : false,
8331
8332     /**
8333     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8334      * loaded or when a record is removed. (defaults to false).
8335     */
8336     pruneModifiedRecords : false,
8337
8338     // private
8339     lastOptions : null,
8340
8341     /**
8342      * Add Records to the Store and fires the add event.
8343      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8344      */
8345     add : function(records){
8346         records = [].concat(records);
8347         for(var i = 0, len = records.length; i < len; i++){
8348             records[i].join(this);
8349         }
8350         var index = this.data.length;
8351         this.data.addAll(records);
8352         this.fireEvent("add", this, records, index);
8353     },
8354
8355     /**
8356      * Remove a Record from the Store and fires the remove event.
8357      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8358      */
8359     remove : function(record){
8360         var index = this.data.indexOf(record);
8361         this.data.removeAt(index);
8362         if(this.pruneModifiedRecords){
8363             this.modified.remove(record);
8364         }
8365         this.fireEvent("remove", this, record, index);
8366     },
8367
8368     /**
8369      * Remove all Records from the Store and fires the clear event.
8370      */
8371     removeAll : function(){
8372         this.data.clear();
8373         if(this.pruneModifiedRecords){
8374             this.modified = [];
8375         }
8376         this.fireEvent("clear", this);
8377     },
8378
8379     /**
8380      * Inserts Records to the Store at the given index and fires the add event.
8381      * @param {Number} index The start index at which to insert the passed Records.
8382      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8383      */
8384     insert : function(index, records){
8385         records = [].concat(records);
8386         for(var i = 0, len = records.length; i < len; i++){
8387             this.data.insert(index, records[i]);
8388             records[i].join(this);
8389         }
8390         this.fireEvent("add", this, records, index);
8391     },
8392
8393     /**
8394      * Get the index within the cache of the passed Record.
8395      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8396      * @return {Number} The index of the passed Record. Returns -1 if not found.
8397      */
8398     indexOf : function(record){
8399         return this.data.indexOf(record);
8400     },
8401
8402     /**
8403      * Get the index within the cache of the Record with the passed id.
8404      * @param {String} id The id of the Record to find.
8405      * @return {Number} The index of the Record. Returns -1 if not found.
8406      */
8407     indexOfId : function(id){
8408         return this.data.indexOfKey(id);
8409     },
8410
8411     /**
8412      * Get the Record with the specified id.
8413      * @param {String} id The id of the Record to find.
8414      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8415      */
8416     getById : function(id){
8417         return this.data.key(id);
8418     },
8419
8420     /**
8421      * Get the Record at the specified index.
8422      * @param {Number} index The index of the Record to find.
8423      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8424      */
8425     getAt : function(index){
8426         return this.data.itemAt(index);
8427     },
8428
8429     /**
8430      * Returns a range of Records between specified indices.
8431      * @param {Number} startIndex (optional) The starting index (defaults to 0)
8432      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8433      * @return {Roo.data.Record[]} An array of Records
8434      */
8435     getRange : function(start, end){
8436         return this.data.getRange(start, end);
8437     },
8438
8439     // private
8440     storeOptions : function(o){
8441         o = Roo.apply({}, o);
8442         delete o.callback;
8443         delete o.scope;
8444         this.lastOptions = o;
8445     },
8446
8447     /**
8448      * Loads the Record cache from the configured Proxy using the configured Reader.
8449      * <p>
8450      * If using remote paging, then the first load call must specify the <em>start</em>
8451      * and <em>limit</em> properties in the options.params property to establish the initial
8452      * position within the dataset, and the number of Records to cache on each read from the Proxy.
8453      * <p>
8454      * <strong>It is important to note that for remote data sources, loading is asynchronous,
8455      * and this call will return before the new data has been loaded. Perform any post-processing
8456      * in a callback function, or in a "load" event handler.</strong>
8457      * <p>
8458      * @param {Object} options An object containing properties which control loading options:<ul>
8459      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8460      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8461      * passed the following arguments:<ul>
8462      * <li>r : Roo.data.Record[]</li>
8463      * <li>options: Options object from the load call</li>
8464      * <li>success: Boolean success indicator</li></ul></li>
8465      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8466      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8467      * </ul>
8468      */
8469     load : function(options){
8470         options = options || {};
8471         if(this.fireEvent("beforeload", this, options) !== false){
8472             this.storeOptions(options);
8473             var p = Roo.apply(options.params || {}, this.baseParams);
8474             // if meta was not loaded from remote source.. try requesting it.
8475             if (!this.reader.metaFromRemote) {
8476                 p._requestMeta = 1;
8477             }
8478             if(this.sortInfo && this.remoteSort){
8479                 var pn = this.paramNames;
8480                 p[pn["sort"]] = this.sortInfo.field;
8481                 p[pn["dir"]] = this.sortInfo.direction;
8482             }
8483             if (this.multiSort) {
8484                 var pn = this.paramNames;
8485                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8486             }
8487             
8488             this.proxy.load(p, this.reader, this.loadRecords, this, options);
8489         }
8490     },
8491
8492     /**
8493      * Reloads the Record cache from the configured Proxy using the configured Reader and
8494      * the options from the last load operation performed.
8495      * @param {Object} options (optional) An object containing properties which may override the options
8496      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8497      * the most recently used options are reused).
8498      */
8499     reload : function(options){
8500         this.load(Roo.applyIf(options||{}, this.lastOptions));
8501     },
8502
8503     // private
8504     // Called as a callback by the Reader during a load operation.
8505     loadRecords : function(o, options, success){
8506         if(!o || success === false){
8507             if(success !== false){
8508                 this.fireEvent("load", this, [], options, o);
8509             }
8510             if(options.callback){
8511                 options.callback.call(options.scope || this, [], options, false);
8512             }
8513             return;
8514         }
8515         // if data returned failure - throw an exception.
8516         if (o.success === false) {
8517             // show a message if no listener is registered.
8518             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8519                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8520             }
8521             // loadmask wil be hooked into this..
8522             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8523             return;
8524         }
8525         var r = o.records, t = o.totalRecords || r.length;
8526         
8527         this.fireEvent("beforeloadadd", this, r, options, o);
8528         
8529         if(!options || options.add !== true){
8530             if(this.pruneModifiedRecords){
8531                 this.modified = [];
8532             }
8533             for(var i = 0, len = r.length; i < len; i++){
8534                 r[i].join(this);
8535             }
8536             if(this.snapshot){
8537                 this.data = this.snapshot;
8538                 delete this.snapshot;
8539             }
8540             this.data.clear();
8541             this.data.addAll(r);
8542             this.totalLength = t;
8543             this.applySort();
8544             this.fireEvent("datachanged", this);
8545         }else{
8546             this.totalLength = Math.max(t, this.data.length+r.length);
8547             this.add(r);
8548         }
8549         this.fireEvent("load", this, r, options, o);
8550         if(options.callback){
8551             options.callback.call(options.scope || this, r, options, true);
8552         }
8553     },
8554
8555
8556     /**
8557      * Loads data from a passed data block. A Reader which understands the format of the data
8558      * must have been configured in the constructor.
8559      * @param {Object} data The data block from which to read the Records.  The format of the data expected
8560      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8561      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8562      */
8563     loadData : function(o, append){
8564         var r = this.reader.readRecords(o);
8565         this.loadRecords(r, {add: append}, true);
8566     },
8567
8568     /**
8569      * Gets the number of cached records.
8570      * <p>
8571      * <em>If using paging, this may not be the total size of the dataset. If the data object
8572      * used by the Reader contains the dataset size, then the getTotalCount() function returns
8573      * the data set size</em>
8574      */
8575     getCount : function(){
8576         return this.data.length || 0;
8577     },
8578
8579     /**
8580      * Gets the total number of records in the dataset as returned by the server.
8581      * <p>
8582      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8583      * the dataset size</em>
8584      */
8585     getTotalCount : function(){
8586         return this.totalLength || 0;
8587     },
8588
8589     /**
8590      * Returns the sort state of the Store as an object with two properties:
8591      * <pre><code>
8592  field {String} The name of the field by which the Records are sorted
8593  direction {String} The sort order, "ASC" or "DESC"
8594      * </code></pre>
8595      */
8596     getSortState : function(){
8597         return this.sortInfo;
8598     },
8599
8600     // private
8601     applySort : function(){
8602         if(this.sortInfo && !this.remoteSort){
8603             var s = this.sortInfo, f = s.field;
8604             var st = this.fields.get(f).sortType;
8605             var fn = function(r1, r2){
8606                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8607                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8608             };
8609             this.data.sort(s.direction, fn);
8610             if(this.snapshot && this.snapshot != this.data){
8611                 this.snapshot.sort(s.direction, fn);
8612             }
8613         }
8614     },
8615
8616     /**
8617      * Sets the default sort column and order to be used by the next load operation.
8618      * @param {String} fieldName The name of the field to sort by.
8619      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8620      */
8621     setDefaultSort : function(field, dir){
8622         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8623     },
8624
8625     /**
8626      * Sort the Records.
8627      * If remote sorting is used, the sort is performed on the server, and the cache is
8628      * reloaded. If local sorting is used, the cache is sorted internally.
8629      * @param {String} fieldName The name of the field to sort by.
8630      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8631      */
8632     sort : function(fieldName, dir){
8633         var f = this.fields.get(fieldName);
8634         if(!dir){
8635             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8636             
8637             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8638                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8639             }else{
8640                 dir = f.sortDir;
8641             }
8642         }
8643         this.sortToggle[f.name] = dir;
8644         this.sortInfo = {field: f.name, direction: dir};
8645         if(!this.remoteSort){
8646             this.applySort();
8647             this.fireEvent("datachanged", this);
8648         }else{
8649             this.load(this.lastOptions);
8650         }
8651     },
8652
8653     /**
8654      * Calls the specified function for each of the Records in the cache.
8655      * @param {Function} fn The function to call. The Record is passed as the first parameter.
8656      * Returning <em>false</em> aborts and exits the iteration.
8657      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8658      */
8659     each : function(fn, scope){
8660         this.data.each(fn, scope);
8661     },
8662
8663     /**
8664      * Gets all records modified since the last commit.  Modified records are persisted across load operations
8665      * (e.g., during paging).
8666      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8667      */
8668     getModifiedRecords : function(){
8669         return this.modified;
8670     },
8671
8672     // private
8673     createFilterFn : function(property, value, anyMatch){
8674         if(!value.exec){ // not a regex
8675             value = String(value);
8676             if(value.length == 0){
8677                 return false;
8678             }
8679             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8680         }
8681         return function(r){
8682             return value.test(r.data[property]);
8683         };
8684     },
8685
8686     /**
8687      * Sums the value of <i>property</i> for each record between start and end and returns the result.
8688      * @param {String} property A field on your records
8689      * @param {Number} start The record index to start at (defaults to 0)
8690      * @param {Number} end The last record index to include (defaults to length - 1)
8691      * @return {Number} The sum
8692      */
8693     sum : function(property, start, end){
8694         var rs = this.data.items, v = 0;
8695         start = start || 0;
8696         end = (end || end === 0) ? end : rs.length-1;
8697
8698         for(var i = start; i <= end; i++){
8699             v += (rs[i].data[property] || 0);
8700         }
8701         return v;
8702     },
8703
8704     /**
8705      * Filter the records by a specified property.
8706      * @param {String} field A field on your records
8707      * @param {String/RegExp} value Either a string that the field
8708      * should start with or a RegExp to test against the field
8709      * @param {Boolean} anyMatch True to match any part not just the beginning
8710      */
8711     filter : function(property, value, anyMatch){
8712         var fn = this.createFilterFn(property, value, anyMatch);
8713         return fn ? this.filterBy(fn) : this.clearFilter();
8714     },
8715
8716     /**
8717      * Filter by a function. The specified function will be called with each
8718      * record in this data source. If the function returns true the record is included,
8719      * otherwise it is filtered.
8720      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8721      * @param {Object} scope (optional) The scope of the function (defaults to this)
8722      */
8723     filterBy : function(fn, scope){
8724         this.snapshot = this.snapshot || this.data;
8725         this.data = this.queryBy(fn, scope||this);
8726         this.fireEvent("datachanged", this);
8727     },
8728
8729     /**
8730      * Query the records by a specified property.
8731      * @param {String} field A field on your records
8732      * @param {String/RegExp} value Either a string that the field
8733      * should start with or a RegExp to test against the field
8734      * @param {Boolean} anyMatch True to match any part not just the beginning
8735      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8736      */
8737     query : function(property, value, anyMatch){
8738         var fn = this.createFilterFn(property, value, anyMatch);
8739         return fn ? this.queryBy(fn) : this.data.clone();
8740     },
8741
8742     /**
8743      * Query by a function. The specified function will be called with each
8744      * record in this data source. If the function returns true the record is included
8745      * in the results.
8746      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8747      * @param {Object} scope (optional) The scope of the function (defaults to this)
8748       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8749      **/
8750     queryBy : function(fn, scope){
8751         var data = this.snapshot || this.data;
8752         return data.filterBy(fn, scope||this);
8753     },
8754
8755     /**
8756      * Collects unique values for a particular dataIndex from this store.
8757      * @param {String} dataIndex The property to collect
8758      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8759      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8760      * @return {Array} An array of the unique values
8761      **/
8762     collect : function(dataIndex, allowNull, bypassFilter){
8763         var d = (bypassFilter === true && this.snapshot) ?
8764                 this.snapshot.items : this.data.items;
8765         var v, sv, r = [], l = {};
8766         for(var i = 0, len = d.length; i < len; i++){
8767             v = d[i].data[dataIndex];
8768             sv = String(v);
8769             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8770                 l[sv] = true;
8771                 r[r.length] = v;
8772             }
8773         }
8774         return r;
8775     },
8776
8777     /**
8778      * Revert to a view of the Record cache with no filtering applied.
8779      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8780      */
8781     clearFilter : function(suppressEvent){
8782         if(this.snapshot && this.snapshot != this.data){
8783             this.data = this.snapshot;
8784             delete this.snapshot;
8785             if(suppressEvent !== true){
8786                 this.fireEvent("datachanged", this);
8787             }
8788         }
8789     },
8790
8791     // private
8792     afterEdit : function(record){
8793         if(this.modified.indexOf(record) == -1){
8794             this.modified.push(record);
8795         }
8796         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8797     },
8798     
8799     // private
8800     afterReject : function(record){
8801         this.modified.remove(record);
8802         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8803     },
8804
8805     // private
8806     afterCommit : function(record){
8807         this.modified.remove(record);
8808         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8809     },
8810
8811     /**
8812      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8813      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8814      */
8815     commitChanges : function(){
8816         var m = this.modified.slice(0);
8817         this.modified = [];
8818         for(var i = 0, len = m.length; i < len; i++){
8819             m[i].commit();
8820         }
8821     },
8822
8823     /**
8824      * Cancel outstanding changes on all changed records.
8825      */
8826     rejectChanges : function(){
8827         var m = this.modified.slice(0);
8828         this.modified = [];
8829         for(var i = 0, len = m.length; i < len; i++){
8830             m[i].reject();
8831         }
8832     },
8833
8834     onMetaChange : function(meta, rtype, o){
8835         this.recordType = rtype;
8836         this.fields = rtype.prototype.fields;
8837         delete this.snapshot;
8838         this.sortInfo = meta.sortInfo || this.sortInfo;
8839         this.modified = [];
8840         this.fireEvent('metachange', this, this.reader.meta);
8841     },
8842     
8843     moveIndex : function(data, type)
8844     {
8845         var index = this.indexOf(data);
8846         
8847         var newIndex = index + type;
8848         
8849         this.remove(data);
8850         
8851         this.insert(newIndex, data);
8852         
8853     }
8854 });/*
8855  * Based on:
8856  * Ext JS Library 1.1.1
8857  * Copyright(c) 2006-2007, Ext JS, LLC.
8858  *
8859  * Originally Released Under LGPL - original licence link has changed is not relivant.
8860  *
8861  * Fork - LGPL
8862  * <script type="text/javascript">
8863  */
8864
8865 /**
8866  * @class Roo.data.SimpleStore
8867  * @extends Roo.data.Store
8868  * Small helper class to make creating Stores from Array data easier.
8869  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8870  * @cfg {Array} fields An array of field definition objects, or field name strings.
8871  * @cfg {Array} data The multi-dimensional array of data
8872  * @constructor
8873  * @param {Object} config
8874  */
8875 Roo.data.SimpleStore = function(config){
8876     Roo.data.SimpleStore.superclass.constructor.call(this, {
8877         isLocal : true,
8878         reader: new Roo.data.ArrayReader({
8879                 id: config.id
8880             },
8881             Roo.data.Record.create(config.fields)
8882         ),
8883         proxy : new Roo.data.MemoryProxy(config.data)
8884     });
8885     this.load();
8886 };
8887 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8888  * Based on:
8889  * Ext JS Library 1.1.1
8890  * Copyright(c) 2006-2007, Ext JS, LLC.
8891  *
8892  * Originally Released Under LGPL - original licence link has changed is not relivant.
8893  *
8894  * Fork - LGPL
8895  * <script type="text/javascript">
8896  */
8897
8898 /**
8899 /**
8900  * @extends Roo.data.Store
8901  * @class Roo.data.JsonStore
8902  * Small helper class to make creating Stores for JSON data easier. <br/>
8903 <pre><code>
8904 var store = new Roo.data.JsonStore({
8905     url: 'get-images.php',
8906     root: 'images',
8907     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8908 });
8909 </code></pre>
8910  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8911  * JsonReader and HttpProxy (unless inline data is provided).</b>
8912  * @cfg {Array} fields An array of field definition objects, or field name strings.
8913  * @constructor
8914  * @param {Object} config
8915  */
8916 Roo.data.JsonStore = function(c){
8917     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8918         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8919         reader: new Roo.data.JsonReader(c, c.fields)
8920     }));
8921 };
8922 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8923  * Based on:
8924  * Ext JS Library 1.1.1
8925  * Copyright(c) 2006-2007, Ext JS, LLC.
8926  *
8927  * Originally Released Under LGPL - original licence link has changed is not relivant.
8928  *
8929  * Fork - LGPL
8930  * <script type="text/javascript">
8931  */
8932
8933  
8934 Roo.data.Field = function(config){
8935     if(typeof config == "string"){
8936         config = {name: config};
8937     }
8938     Roo.apply(this, config);
8939     
8940     if(!this.type){
8941         this.type = "auto";
8942     }
8943     
8944     var st = Roo.data.SortTypes;
8945     // named sortTypes are supported, here we look them up
8946     if(typeof this.sortType == "string"){
8947         this.sortType = st[this.sortType];
8948     }
8949     
8950     // set default sortType for strings and dates
8951     if(!this.sortType){
8952         switch(this.type){
8953             case "string":
8954                 this.sortType = st.asUCString;
8955                 break;
8956             case "date":
8957                 this.sortType = st.asDate;
8958                 break;
8959             default:
8960                 this.sortType = st.none;
8961         }
8962     }
8963
8964     // define once
8965     var stripRe = /[\$,%]/g;
8966
8967     // prebuilt conversion function for this field, instead of
8968     // switching every time we're reading a value
8969     if(!this.convert){
8970         var cv, dateFormat = this.dateFormat;
8971         switch(this.type){
8972             case "":
8973             case "auto":
8974             case undefined:
8975                 cv = function(v){ return v; };
8976                 break;
8977             case "string":
8978                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8979                 break;
8980             case "int":
8981                 cv = function(v){
8982                     return v !== undefined && v !== null && v !== '' ?
8983                            parseInt(String(v).replace(stripRe, ""), 10) : '';
8984                     };
8985                 break;
8986             case "float":
8987                 cv = function(v){
8988                     return v !== undefined && v !== null && v !== '' ?
8989                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
8990                     };
8991                 break;
8992             case "bool":
8993             case "boolean":
8994                 cv = function(v){ return v === true || v === "true" || v == 1; };
8995                 break;
8996             case "date":
8997                 cv = function(v){
8998                     if(!v){
8999                         return '';
9000                     }
9001                     if(v instanceof Date){
9002                         return v;
9003                     }
9004                     if(dateFormat){
9005                         if(dateFormat == "timestamp"){
9006                             return new Date(v*1000);
9007                         }
9008                         return Date.parseDate(v, dateFormat);
9009                     }
9010                     var parsed = Date.parse(v);
9011                     return parsed ? new Date(parsed) : null;
9012                 };
9013              break;
9014             
9015         }
9016         this.convert = cv;
9017     }
9018 };
9019
9020 Roo.data.Field.prototype = {
9021     dateFormat: null,
9022     defaultValue: "",
9023     mapping: null,
9024     sortType : null,
9025     sortDir : "ASC"
9026 };/*
9027  * Based on:
9028  * Ext JS Library 1.1.1
9029  * Copyright(c) 2006-2007, Ext JS, LLC.
9030  *
9031  * Originally Released Under LGPL - original licence link has changed is not relivant.
9032  *
9033  * Fork - LGPL
9034  * <script type="text/javascript">
9035  */
9036  
9037 // Base class for reading structured data from a data source.  This class is intended to be
9038 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9039
9040 /**
9041  * @class Roo.data.DataReader
9042  * Base class for reading structured data from a data source.  This class is intended to be
9043  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9044  */
9045
9046 Roo.data.DataReader = function(meta, recordType){
9047     
9048     this.meta = meta;
9049     
9050     this.recordType = recordType instanceof Array ? 
9051         Roo.data.Record.create(recordType) : recordType;
9052 };
9053
9054 Roo.data.DataReader.prototype = {
9055      /**
9056      * Create an empty record
9057      * @param {Object} data (optional) - overlay some values
9058      * @return {Roo.data.Record} record created.
9059      */
9060     newRow :  function(d) {
9061         var da =  {};
9062         this.recordType.prototype.fields.each(function(c) {
9063             switch( c.type) {
9064                 case 'int' : da[c.name] = 0; break;
9065                 case 'date' : da[c.name] = new Date(); break;
9066                 case 'float' : da[c.name] = 0.0; break;
9067                 case 'boolean' : da[c.name] = false; break;
9068                 default : da[c.name] = ""; break;
9069             }
9070             
9071         });
9072         return new this.recordType(Roo.apply(da, d));
9073     }
9074     
9075 };/*
9076  * Based on:
9077  * Ext JS Library 1.1.1
9078  * Copyright(c) 2006-2007, Ext JS, LLC.
9079  *
9080  * Originally Released Under LGPL - original licence link has changed is not relivant.
9081  *
9082  * Fork - LGPL
9083  * <script type="text/javascript">
9084  */
9085
9086 /**
9087  * @class Roo.data.DataProxy
9088  * @extends Roo.data.Observable
9089  * This class is an abstract base class for implementations which provide retrieval of
9090  * unformatted data objects.<br>
9091  * <p>
9092  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9093  * (of the appropriate type which knows how to parse the data object) to provide a block of
9094  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9095  * <p>
9096  * Custom implementations must implement the load method as described in
9097  * {@link Roo.data.HttpProxy#load}.
9098  */
9099 Roo.data.DataProxy = function(){
9100     this.addEvents({
9101         /**
9102          * @event beforeload
9103          * Fires before a network request is made to retrieve a data object.
9104          * @param {Object} This DataProxy object.
9105          * @param {Object} params The params parameter to the load function.
9106          */
9107         beforeload : true,
9108         /**
9109          * @event load
9110          * Fires before the load method's callback is called.
9111          * @param {Object} This DataProxy object.
9112          * @param {Object} o The data object.
9113          * @param {Object} arg The callback argument object passed to the load function.
9114          */
9115         load : true,
9116         /**
9117          * @event loadexception
9118          * Fires if an Exception occurs during data retrieval.
9119          * @param {Object} This DataProxy object.
9120          * @param {Object} o The data object.
9121          * @param {Object} arg The callback argument object passed to the load function.
9122          * @param {Object} e The Exception.
9123          */
9124         loadexception : true
9125     });
9126     Roo.data.DataProxy.superclass.constructor.call(this);
9127 };
9128
9129 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9130
9131     /**
9132      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9133      */
9134 /*
9135  * Based on:
9136  * Ext JS Library 1.1.1
9137  * Copyright(c) 2006-2007, Ext JS, LLC.
9138  *
9139  * Originally Released Under LGPL - original licence link has changed is not relivant.
9140  *
9141  * Fork - LGPL
9142  * <script type="text/javascript">
9143  */
9144 /**
9145  * @class Roo.data.MemoryProxy
9146  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9147  * to the Reader when its load method is called.
9148  * @constructor
9149  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9150  */
9151 Roo.data.MemoryProxy = function(data){
9152     if (data.data) {
9153         data = data.data;
9154     }
9155     Roo.data.MemoryProxy.superclass.constructor.call(this);
9156     this.data = data;
9157 };
9158
9159 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9160     /**
9161      * Load data from the requested source (in this case an in-memory
9162      * data object passed to the constructor), read the data object into
9163      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9164      * process that block using the passed callback.
9165      * @param {Object} params This parameter is not used by the MemoryProxy class.
9166      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9167      * object into a block of Roo.data.Records.
9168      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9169      * The function must be passed <ul>
9170      * <li>The Record block object</li>
9171      * <li>The "arg" argument from the load function</li>
9172      * <li>A boolean success indicator</li>
9173      * </ul>
9174      * @param {Object} scope The scope in which to call the callback
9175      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9176      */
9177     load : function(params, reader, callback, scope, arg){
9178         params = params || {};
9179         var result;
9180         try {
9181             result = reader.readRecords(this.data);
9182         }catch(e){
9183             this.fireEvent("loadexception", this, arg, null, e);
9184             callback.call(scope, null, arg, false);
9185             return;
9186         }
9187         callback.call(scope, result, arg, true);
9188     },
9189     
9190     // private
9191     update : function(params, records){
9192         
9193     }
9194 });/*
9195  * Based on:
9196  * Ext JS Library 1.1.1
9197  * Copyright(c) 2006-2007, Ext JS, LLC.
9198  *
9199  * Originally Released Under LGPL - original licence link has changed is not relivant.
9200  *
9201  * Fork - LGPL
9202  * <script type="text/javascript">
9203  */
9204 /**
9205  * @class Roo.data.HttpProxy
9206  * @extends Roo.data.DataProxy
9207  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9208  * configured to reference a certain URL.<br><br>
9209  * <p>
9210  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9211  * from which the running page was served.<br><br>
9212  * <p>
9213  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9214  * <p>
9215  * Be aware that to enable the browser to parse an XML document, the server must set
9216  * the Content-Type header in the HTTP response to "text/xml".
9217  * @constructor
9218  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9219  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9220  * will be used to make the request.
9221  */
9222 Roo.data.HttpProxy = function(conn){
9223     Roo.data.HttpProxy.superclass.constructor.call(this);
9224     // is conn a conn config or a real conn?
9225     this.conn = conn;
9226     this.useAjax = !conn || !conn.events;
9227   
9228 };
9229
9230 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9231     // thse are take from connection...
9232     
9233     /**
9234      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9235      */
9236     /**
9237      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9238      * extra parameters to each request made by this object. (defaults to undefined)
9239      */
9240     /**
9241      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9242      *  to each request made by this object. (defaults to undefined)
9243      */
9244     /**
9245      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
9246      */
9247     /**
9248      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9249      */
9250      /**
9251      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9252      * @type Boolean
9253      */
9254   
9255
9256     /**
9257      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9258      * @type Boolean
9259      */
9260     /**
9261      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9262      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9263      * a finer-grained basis than the DataProxy events.
9264      */
9265     getConnection : function(){
9266         return this.useAjax ? Roo.Ajax : this.conn;
9267     },
9268
9269     /**
9270      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9271      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9272      * process that block using the passed callback.
9273      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9274      * for the request to the remote server.
9275      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9276      * object into a block of Roo.data.Records.
9277      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9278      * The function must be passed <ul>
9279      * <li>The Record block object</li>
9280      * <li>The "arg" argument from the load function</li>
9281      * <li>A boolean success indicator</li>
9282      * </ul>
9283      * @param {Object} scope The scope in which to call the callback
9284      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9285      */
9286     load : function(params, reader, callback, scope, arg){
9287         if(this.fireEvent("beforeload", this, params) !== false){
9288             var  o = {
9289                 params : params || {},
9290                 request: {
9291                     callback : callback,
9292                     scope : scope,
9293                     arg : arg
9294                 },
9295                 reader: reader,
9296                 callback : this.loadResponse,
9297                 scope: this
9298             };
9299             if(this.useAjax){
9300                 Roo.applyIf(o, this.conn);
9301                 if(this.activeRequest){
9302                     Roo.Ajax.abort(this.activeRequest);
9303                 }
9304                 this.activeRequest = Roo.Ajax.request(o);
9305             }else{
9306                 this.conn.request(o);
9307             }
9308         }else{
9309             callback.call(scope||this, null, arg, false);
9310         }
9311     },
9312
9313     // private
9314     loadResponse : function(o, success, response){
9315         delete this.activeRequest;
9316         if(!success){
9317             this.fireEvent("loadexception", this, o, response);
9318             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9319             return;
9320         }
9321         var result;
9322         try {
9323             result = o.reader.read(response);
9324         }catch(e){
9325             this.fireEvent("loadexception", this, o, response, e);
9326             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9327             return;
9328         }
9329         
9330         this.fireEvent("load", this, o, o.request.arg);
9331         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9332     },
9333
9334     // private
9335     update : function(dataSet){
9336
9337     },
9338
9339     // private
9340     updateResponse : function(dataSet){
9341
9342     }
9343 });/*
9344  * Based on:
9345  * Ext JS Library 1.1.1
9346  * Copyright(c) 2006-2007, Ext JS, LLC.
9347  *
9348  * Originally Released Under LGPL - original licence link has changed is not relivant.
9349  *
9350  * Fork - LGPL
9351  * <script type="text/javascript">
9352  */
9353
9354 /**
9355  * @class Roo.data.ScriptTagProxy
9356  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9357  * other than the originating domain of the running page.<br><br>
9358  * <p>
9359  * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
9360  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9361  * <p>
9362  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9363  * source code that is used as the source inside a &lt;script> tag.<br><br>
9364  * <p>
9365  * In order for the browser to process the returned data, the server must wrap the data object
9366  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9367  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9368  * depending on whether the callback name was passed:
9369  * <p>
9370  * <pre><code>
9371 boolean scriptTag = false;
9372 String cb = request.getParameter("callback");
9373 if (cb != null) {
9374     scriptTag = true;
9375     response.setContentType("text/javascript");
9376 } else {
9377     response.setContentType("application/x-json");
9378 }
9379 Writer out = response.getWriter();
9380 if (scriptTag) {
9381     out.write(cb + "(");
9382 }
9383 out.print(dataBlock.toJsonString());
9384 if (scriptTag) {
9385     out.write(");");
9386 }
9387 </pre></code>
9388  *
9389  * @constructor
9390  * @param {Object} config A configuration object.
9391  */
9392 Roo.data.ScriptTagProxy = function(config){
9393     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9394     Roo.apply(this, config);
9395     this.head = document.getElementsByTagName("head")[0];
9396 };
9397
9398 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9399
9400 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9401     /**
9402      * @cfg {String} url The URL from which to request the data object.
9403      */
9404     /**
9405      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9406      */
9407     timeout : 30000,
9408     /**
9409      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9410      * the server the name of the callback function set up by the load call to process the returned data object.
9411      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9412      * javascript output which calls this named function passing the data object as its only parameter.
9413      */
9414     callbackParam : "callback",
9415     /**
9416      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9417      * name to the request.
9418      */
9419     nocache : true,
9420
9421     /**
9422      * Load data from the configured URL, read the data object into
9423      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9424      * process that block using the passed callback.
9425      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9426      * for the request to the remote server.
9427      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9428      * object into a block of Roo.data.Records.
9429      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9430      * The function must be passed <ul>
9431      * <li>The Record block object</li>
9432      * <li>The "arg" argument from the load function</li>
9433      * <li>A boolean success indicator</li>
9434      * </ul>
9435      * @param {Object} scope The scope in which to call the callback
9436      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9437      */
9438     load : function(params, reader, callback, scope, arg){
9439         if(this.fireEvent("beforeload", this, params) !== false){
9440
9441             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9442
9443             var url = this.url;
9444             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9445             if(this.nocache){
9446                 url += "&_dc=" + (new Date().getTime());
9447             }
9448             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9449             var trans = {
9450                 id : transId,
9451                 cb : "stcCallback"+transId,
9452                 scriptId : "stcScript"+transId,
9453                 params : params,
9454                 arg : arg,
9455                 url : url,
9456                 callback : callback,
9457                 scope : scope,
9458                 reader : reader
9459             };
9460             var conn = this;
9461
9462             window[trans.cb] = function(o){
9463                 conn.handleResponse(o, trans);
9464             };
9465
9466             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9467
9468             if(this.autoAbort !== false){
9469                 this.abort();
9470             }
9471
9472             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9473
9474             var script = document.createElement("script");
9475             script.setAttribute("src", url);
9476             script.setAttribute("type", "text/javascript");
9477             script.setAttribute("id", trans.scriptId);
9478             this.head.appendChild(script);
9479
9480             this.trans = trans;
9481         }else{
9482             callback.call(scope||this, null, arg, false);
9483         }
9484     },
9485
9486     // private
9487     isLoading : function(){
9488         return this.trans ? true : false;
9489     },
9490
9491     /**
9492      * Abort the current server request.
9493      */
9494     abort : function(){
9495         if(this.isLoading()){
9496             this.destroyTrans(this.trans);
9497         }
9498     },
9499
9500     // private
9501     destroyTrans : function(trans, isLoaded){
9502         this.head.removeChild(document.getElementById(trans.scriptId));
9503         clearTimeout(trans.timeoutId);
9504         if(isLoaded){
9505             window[trans.cb] = undefined;
9506             try{
9507                 delete window[trans.cb];
9508             }catch(e){}
9509         }else{
9510             // if hasn't been loaded, wait for load to remove it to prevent script error
9511             window[trans.cb] = function(){
9512                 window[trans.cb] = undefined;
9513                 try{
9514                     delete window[trans.cb];
9515                 }catch(e){}
9516             };
9517         }
9518     },
9519
9520     // private
9521     handleResponse : function(o, trans){
9522         this.trans = false;
9523         this.destroyTrans(trans, true);
9524         var result;
9525         try {
9526             result = trans.reader.readRecords(o);
9527         }catch(e){
9528             this.fireEvent("loadexception", this, o, trans.arg, e);
9529             trans.callback.call(trans.scope||window, null, trans.arg, false);
9530             return;
9531         }
9532         this.fireEvent("load", this, o, trans.arg);
9533         trans.callback.call(trans.scope||window, result, trans.arg, true);
9534     },
9535
9536     // private
9537     handleFailure : function(trans){
9538         this.trans = false;
9539         this.destroyTrans(trans, false);
9540         this.fireEvent("loadexception", this, null, trans.arg);
9541         trans.callback.call(trans.scope||window, null, trans.arg, false);
9542     }
9543 });/*
9544  * Based on:
9545  * Ext JS Library 1.1.1
9546  * Copyright(c) 2006-2007, Ext JS, LLC.
9547  *
9548  * Originally Released Under LGPL - original licence link has changed is not relivant.
9549  *
9550  * Fork - LGPL
9551  * <script type="text/javascript">
9552  */
9553
9554 /**
9555  * @class Roo.data.JsonReader
9556  * @extends Roo.data.DataReader
9557  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9558  * based on mappings in a provided Roo.data.Record constructor.
9559  * 
9560  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9561  * in the reply previously. 
9562  * 
9563  * <p>
9564  * Example code:
9565  * <pre><code>
9566 var RecordDef = Roo.data.Record.create([
9567     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
9568     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
9569 ]);
9570 var myReader = new Roo.data.JsonReader({
9571     totalProperty: "results",    // The property which contains the total dataset size (optional)
9572     root: "rows",                // The property which contains an Array of row objects
9573     id: "id"                     // The property within each row object that provides an ID for the record (optional)
9574 }, RecordDef);
9575 </code></pre>
9576  * <p>
9577  * This would consume a JSON file like this:
9578  * <pre><code>
9579 { 'results': 2, 'rows': [
9580     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9581     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9582 }
9583 </code></pre>
9584  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9585  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9586  * paged from the remote server.
9587  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9588  * @cfg {String} root name of the property which contains the Array of row objects.
9589  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9590  * @constructor
9591  * Create a new JsonReader
9592  * @param {Object} meta Metadata configuration options
9593  * @param {Object} recordType Either an Array of field definition objects,
9594  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9595  */
9596 Roo.data.JsonReader = function(meta, recordType){
9597     
9598     meta = meta || {};
9599     // set some defaults:
9600     Roo.applyIf(meta, {
9601         totalProperty: 'total',
9602         successProperty : 'success',
9603         root : 'data',
9604         id : 'id'
9605     });
9606     
9607     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9608 };
9609 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9610     
9611     /**
9612      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
9613      * Used by Store query builder to append _requestMeta to params.
9614      * 
9615      */
9616     metaFromRemote : false,
9617     /**
9618      * This method is only used by a DataProxy which has retrieved data from a remote server.
9619      * @param {Object} response The XHR object which contains the JSON data in its responseText.
9620      * @return {Object} data A data block which is used by an Roo.data.Store object as
9621      * a cache of Roo.data.Records.
9622      */
9623     read : function(response){
9624         var json = response.responseText;
9625        
9626         var o = /* eval:var:o */ eval("("+json+")");
9627         if(!o) {
9628             throw {message: "JsonReader.read: Json object not found"};
9629         }
9630         
9631         if(o.metaData){
9632             
9633             delete this.ef;
9634             this.metaFromRemote = true;
9635             this.meta = o.metaData;
9636             this.recordType = Roo.data.Record.create(o.metaData.fields);
9637             this.onMetaChange(this.meta, this.recordType, o);
9638         }
9639         return this.readRecords(o);
9640     },
9641
9642     // private function a store will implement
9643     onMetaChange : function(meta, recordType, o){
9644
9645     },
9646
9647     /**
9648          * @ignore
9649          */
9650     simpleAccess: function(obj, subsc) {
9651         return obj[subsc];
9652     },
9653
9654         /**
9655          * @ignore
9656          */
9657     getJsonAccessor: function(){
9658         var re = /[\[\.]/;
9659         return function(expr) {
9660             try {
9661                 return(re.test(expr))
9662                     ? new Function("obj", "return obj." + expr)
9663                     : function(obj){
9664                         return obj[expr];
9665                     };
9666             } catch(e){}
9667             return Roo.emptyFn;
9668         };
9669     }(),
9670
9671     /**
9672      * Create a data block containing Roo.data.Records from an XML document.
9673      * @param {Object} o An object which contains an Array of row objects in the property specified
9674      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9675      * which contains the total size of the dataset.
9676      * @return {Object} data A data block which is used by an Roo.data.Store object as
9677      * a cache of Roo.data.Records.
9678      */
9679     readRecords : function(o){
9680         /**
9681          * After any data loads, the raw JSON data is available for further custom processing.
9682          * @type Object
9683          */
9684         this.o = o;
9685         var s = this.meta, Record = this.recordType,
9686             f = Record.prototype.fields, fi = f.items, fl = f.length;
9687
9688 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
9689         if (!this.ef) {
9690             if(s.totalProperty) {
9691                     this.getTotal = this.getJsonAccessor(s.totalProperty);
9692                 }
9693                 if(s.successProperty) {
9694                     this.getSuccess = this.getJsonAccessor(s.successProperty);
9695                 }
9696                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9697                 if (s.id) {
9698                         var g = this.getJsonAccessor(s.id);
9699                         this.getId = function(rec) {
9700                                 var r = g(rec);
9701                                 return (r === undefined || r === "") ? null : r;
9702                         };
9703                 } else {
9704                         this.getId = function(){return null;};
9705                 }
9706             this.ef = [];
9707             for(var jj = 0; jj < fl; jj++){
9708                 f = fi[jj];
9709                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9710                 this.ef[jj] = this.getJsonAccessor(map);
9711             }
9712         }
9713
9714         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9715         if(s.totalProperty){
9716             var vt = parseInt(this.getTotal(o), 10);
9717             if(!isNaN(vt)){
9718                 totalRecords = vt;
9719             }
9720         }
9721         if(s.successProperty){
9722             var vs = this.getSuccess(o);
9723             if(vs === false || vs === 'false'){
9724                 success = false;
9725             }
9726         }
9727         var records = [];
9728             for(var i = 0; i < c; i++){
9729                     var n = root[i];
9730                 var values = {};
9731                 var id = this.getId(n);
9732                 for(var j = 0; j < fl; j++){
9733                     f = fi[j];
9734                 var v = this.ef[j](n);
9735                 if (!f.convert) {
9736                     Roo.log('missing convert for ' + f.name);
9737                     Roo.log(f);
9738                     continue;
9739                 }
9740                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9741                 }
9742                 var record = new Record(values, id);
9743                 record.json = n;
9744                 records[i] = record;
9745             }
9746             return {
9747             raw : o,
9748                 success : success,
9749                 records : records,
9750                 totalRecords : totalRecords
9751             };
9752     }
9753 });/*
9754  * Based on:
9755  * Ext JS Library 1.1.1
9756  * Copyright(c) 2006-2007, Ext JS, LLC.
9757  *
9758  * Originally Released Under LGPL - original licence link has changed is not relivant.
9759  *
9760  * Fork - LGPL
9761  * <script type="text/javascript">
9762  */
9763
9764 /**
9765  * @class Roo.data.ArrayReader
9766  * @extends Roo.data.DataReader
9767  * Data reader class to create an Array of Roo.data.Record objects from an Array.
9768  * Each element of that Array represents a row of data fields. The
9769  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9770  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9771  * <p>
9772  * Example code:.
9773  * <pre><code>
9774 var RecordDef = Roo.data.Record.create([
9775     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
9776     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
9777 ]);
9778 var myReader = new Roo.data.ArrayReader({
9779     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
9780 }, RecordDef);
9781 </code></pre>
9782  * <p>
9783  * This would consume an Array like this:
9784  * <pre><code>
9785 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9786   </code></pre>
9787  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9788  * @constructor
9789  * Create a new JsonReader
9790  * @param {Object} meta Metadata configuration options.
9791  * @param {Object} recordType Either an Array of field definition objects
9792  * as specified to {@link Roo.data.Record#create},
9793  * or an {@link Roo.data.Record} object
9794  * created using {@link Roo.data.Record#create}.
9795  */
9796 Roo.data.ArrayReader = function(meta, recordType){
9797     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9798 };
9799
9800 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9801     /**
9802      * Create a data block containing Roo.data.Records from an XML document.
9803      * @param {Object} o An Array of row objects which represents the dataset.
9804      * @return {Object} data A data block which is used by an Roo.data.Store object as
9805      * a cache of Roo.data.Records.
9806      */
9807     readRecords : function(o){
9808         var sid = this.meta ? this.meta.id : null;
9809         var recordType = this.recordType, fields = recordType.prototype.fields;
9810         var records = [];
9811         var root = o;
9812             for(var i = 0; i < root.length; i++){
9813                     var n = root[i];
9814                 var values = {};
9815                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9816                 for(var j = 0, jlen = fields.length; j < jlen; j++){
9817                 var f = fields.items[j];
9818                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9819                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9820                 v = f.convert(v);
9821                 values[f.name] = v;
9822             }
9823                 var record = new recordType(values, id);
9824                 record.json = n;
9825                 records[records.length] = record;
9826             }
9827             return {
9828                 records : records,
9829                 totalRecords : records.length
9830             };
9831     }
9832 });/*
9833  * - LGPL
9834  * * 
9835  */
9836
9837 /**
9838  * @class Roo.bootstrap.ComboBox
9839  * @extends Roo.bootstrap.TriggerField
9840  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9841  * @cfg {Boolean} append (true|false) default false
9842  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9843  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9844  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9845  * @constructor
9846  * Create a new ComboBox.
9847  * @param {Object} config Configuration options
9848  */
9849 Roo.bootstrap.ComboBox = function(config){
9850     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9851     this.addEvents({
9852         /**
9853          * @event expand
9854          * Fires when the dropdown list is expanded
9855              * @param {Roo.bootstrap.ComboBox} combo This combo box
9856              */
9857         'expand' : true,
9858         /**
9859          * @event collapse
9860          * Fires when the dropdown list is collapsed
9861              * @param {Roo.bootstrap.ComboBox} combo This combo box
9862              */
9863         'collapse' : true,
9864         /**
9865          * @event beforeselect
9866          * Fires before a list item is selected. Return false to cancel the selection.
9867              * @param {Roo.bootstrap.ComboBox} combo This combo box
9868              * @param {Roo.data.Record} record The data record returned from the underlying store
9869              * @param {Number} index The index of the selected item in the dropdown list
9870              */
9871         'beforeselect' : true,
9872         /**
9873          * @event select
9874          * Fires when a list item is selected
9875              * @param {Roo.bootstrap.ComboBox} combo This combo box
9876              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9877              * @param {Number} index The index of the selected item in the dropdown list
9878              */
9879         'select' : true,
9880         /**
9881          * @event beforequery
9882          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9883          * The event object passed has these properties:
9884              * @param {Roo.bootstrap.ComboBox} combo This combo box
9885              * @param {String} query The query
9886              * @param {Boolean} forceAll true to force "all" query
9887              * @param {Boolean} cancel true to cancel the query
9888              * @param {Object} e The query event object
9889              */
9890         'beforequery': true,
9891          /**
9892          * @event add
9893          * Fires when the 'add' icon is pressed (add a listener to enable add button)
9894              * @param {Roo.bootstrap.ComboBox} combo This combo box
9895              */
9896         'add' : true,
9897         /**
9898          * @event edit
9899          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9900              * @param {Roo.bootstrap.ComboBox} combo This combo box
9901              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9902              */
9903         'edit' : true,
9904         /**
9905          * @event remove
9906          * Fires when the remove value from the combobox array
9907              * @param {Roo.bootstrap.ComboBox} combo This combo box
9908              */
9909         'remove' : true
9910         
9911     });
9912     
9913     this.item = [];
9914     this.tickItems = [];
9915     
9916     this.selectedIndex = -1;
9917     if(this.mode == 'local'){
9918         if(config.queryDelay === undefined){
9919             this.queryDelay = 10;
9920         }
9921         if(config.minChars === undefined){
9922             this.minChars = 0;
9923         }
9924     }
9925 };
9926
9927 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9928      
9929     /**
9930      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9931      * rendering into an Roo.Editor, defaults to false)
9932      */
9933     /**
9934      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9935      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9936      */
9937     /**
9938      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9939      */
9940     /**
9941      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9942      * the dropdown list (defaults to undefined, with no header element)
9943      */
9944
9945      /**
9946      * @cfg {String/Roo.Template} tpl The template to use to render the output
9947      */
9948      
9949      /**
9950      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9951      */
9952     listWidth: undefined,
9953     /**
9954      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9955      * mode = 'remote' or 'text' if mode = 'local')
9956      */
9957     displayField: undefined,
9958     /**
9959      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9960      * mode = 'remote' or 'value' if mode = 'local'). 
9961      * Note: use of a valueField requires the user make a selection
9962      * in order for a value to be mapped.
9963      */
9964     valueField: undefined,
9965     
9966     
9967     /**
9968      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9969      * field's data value (defaults to the underlying DOM element's name)
9970      */
9971     hiddenName: undefined,
9972     /**
9973      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9974      */
9975     listClass: '',
9976     /**
9977      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9978      */
9979     selectedClass: 'active',
9980     
9981     /**
9982      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9983      */
9984     shadow:'sides',
9985     /**
9986      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9987      * anchor positions (defaults to 'tl-bl')
9988      */
9989     listAlign: 'tl-bl?',
9990     /**
9991      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9992      */
9993     maxHeight: 300,
9994     /**
9995      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
9996      * query specified by the allQuery config option (defaults to 'query')
9997      */
9998     triggerAction: 'query',
9999     /**
10000      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10001      * (defaults to 4, does not apply if editable = false)
10002      */
10003     minChars : 4,
10004     /**
10005      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10006      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10007      */
10008     typeAhead: false,
10009     /**
10010      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10011      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10012      */
10013     queryDelay: 500,
10014     /**
10015      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10016      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10017      */
10018     pageSize: 0,
10019     /**
10020      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10021      * when editable = true (defaults to false)
10022      */
10023     selectOnFocus:false,
10024     /**
10025      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10026      */
10027     queryParam: 'query',
10028     /**
10029      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10030      * when mode = 'remote' (defaults to 'Loading...')
10031      */
10032     loadingText: 'Loading...',
10033     /**
10034      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10035      */
10036     resizable: false,
10037     /**
10038      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10039      */
10040     handleHeight : 8,
10041     /**
10042      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10043      * traditional select (defaults to true)
10044      */
10045     editable: true,
10046     /**
10047      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10048      */
10049     allQuery: '',
10050     /**
10051      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10052      */
10053     mode: 'remote',
10054     /**
10055      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10056      * listWidth has a higher value)
10057      */
10058     minListWidth : 70,
10059     /**
10060      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10061      * allow the user to set arbitrary text into the field (defaults to false)
10062      */
10063     forceSelection:false,
10064     /**
10065      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10066      * if typeAhead = true (defaults to 250)
10067      */
10068     typeAheadDelay : 250,
10069     /**
10070      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10071      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10072      */
10073     valueNotFoundText : undefined,
10074     /**
10075      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10076      */
10077     blockFocus : false,
10078     
10079     /**
10080      * @cfg {Boolean} disableClear Disable showing of clear button.
10081      */
10082     disableClear : false,
10083     /**
10084      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10085      */
10086     alwaysQuery : false,
10087     
10088     /**
10089      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10090      */
10091     multiple : false,
10092     
10093     //private
10094     addicon : false,
10095     editicon: false,
10096     
10097     page: 0,
10098     hasQuery: false,
10099     append: false,
10100     loadNext: false,
10101     autoFocus : true,
10102     tickable : false,
10103     btnPosition : 'right',
10104     
10105     // element that contains real text value.. (when hidden is used..)
10106     
10107     getAutoCreate : function()
10108     {
10109         var cfg = false;
10110         
10111         /*
10112          *  Normal ComboBox
10113          */
10114         if(!this.tickable){
10115             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10116             return cfg;
10117         }
10118         
10119         /*
10120          *  ComboBox with tickable selections
10121          */
10122              
10123         var align = this.labelAlign || this.parentLabelAlign();
10124         
10125         cfg = {
10126             cls : 'form-group roo-combobox-tickable' //input-group
10127         };
10128         
10129         
10130         var buttons = {
10131             tag : 'div',
10132             cls : 'tickable-buttons',
10133             cn : [
10134                 {
10135                     tag : 'button',
10136                     type : 'button',
10137                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10138                     html : 'Edit'
10139                 },
10140                 {
10141                     tag : 'button',
10142                     type : 'button',
10143                     name : 'ok',
10144                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10145                     html : 'Done'
10146                 },
10147                 {
10148                     tag : 'button',
10149                     type : 'button',
10150                     name : 'cancel',
10151                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10152                     html : 'Cancel'
10153                 }
10154             ]
10155         };
10156         
10157         var _this = this;
10158         Roo.each(buttons.cn, function(c){
10159             if (_this.size) {
10160                 c.cls += ' btn-' + _this.size;
10161             }
10162
10163             if (_this.disabled) {
10164                 c.disabled = true;
10165             }
10166         });
10167         
10168         var box = {
10169             tag: 'div',
10170             cn: [
10171                 {
10172                     tag: 'input',
10173                     type : 'hidden',
10174                     cls: 'form-hidden-field'
10175                 },
10176                 {
10177                     tag: 'ul',
10178                     cls: 'select2-choices',
10179                     cn:[
10180                         {
10181                             tag: 'li',
10182                             cls: 'select2-search-field',
10183                             cn: [
10184
10185                                 buttons
10186                             ]
10187                         }
10188                     ]
10189                 }
10190             ]
10191         }
10192         
10193         var combobox = {
10194             cls: 'select2-container input-group select2-container-multi',
10195             cn: [
10196                 box,
10197                 {
10198                     tag: 'ul',
10199                     cls: 'typeahead typeahead-long dropdown-menu',
10200                     style: 'display:none; max-height:' + this.maxHeight + 'px;'
10201                 }
10202             ]
10203         };
10204         
10205         if (align ==='left' && this.fieldLabel.length) {
10206             
10207                 Roo.log("left and has label");
10208                 cfg.cn = [
10209                     
10210                     {
10211                         tag: 'label',
10212                         'for' :  id,
10213                         cls : 'control-label col-sm-' + this.labelWidth,
10214                         html : this.fieldLabel
10215                         
10216                     },
10217                     {
10218                         cls : "col-sm-" + (12 - this.labelWidth), 
10219                         cn: [
10220                             combobox
10221                         ]
10222                     }
10223                     
10224                 ];
10225         } else if ( this.fieldLabel.length) {
10226                 Roo.log(" label");
10227                  cfg.cn = [
10228                    
10229                     {
10230                         tag: 'label',
10231                         //cls : 'input-group-addon',
10232                         html : this.fieldLabel
10233                         
10234                     },
10235                     
10236                     combobox
10237                     
10238                 ];
10239
10240         } else {
10241             
10242                 Roo.log(" no label && no align");
10243                 cfg = combobox
10244                      
10245                 
10246         }
10247          
10248         var settings=this;
10249         ['xs','sm','md','lg'].map(function(size){
10250             if (settings[size]) {
10251                 cfg.cls += ' col-' + size + '-' + settings[size];
10252             }
10253         });
10254         
10255         return cfg;
10256         
10257     },
10258     
10259     // private
10260     initEvents: function()
10261     {
10262         
10263         if (!this.store) {
10264             throw "can not find store for combo";
10265         }
10266         this.store = Roo.factory(this.store, Roo.data);
10267         
10268         if(this.tickable){
10269             this.initTickableEvnets();
10270             return;
10271         }
10272         
10273         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10274         
10275         
10276         if(this.hiddenName){
10277             
10278             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10279             
10280             this.hiddenField.dom.value =
10281                 this.hiddenValue !== undefined ? this.hiddenValue :
10282                 this.value !== undefined ? this.value : '';
10283
10284             // prevent input submission
10285             this.el.dom.removeAttribute('name');
10286             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10287              
10288              
10289         }
10290         //if(Roo.isGecko){
10291         //    this.el.dom.setAttribute('autocomplete', 'off');
10292         //}
10293
10294         var cls = 'x-combo-list';
10295         this.list = this.el.select('ul.dropdown-menu',true).first();
10296
10297         //this.list = new Roo.Layer({
10298         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10299         //});
10300         
10301         var _this = this;
10302         
10303         (function(){
10304             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10305             _this.list.setWidth(lw);
10306         }).defer(100);
10307         
10308         this.list.on('mouseover', this.onViewOver, this);
10309         this.list.on('mousemove', this.onViewMove, this);
10310         
10311         this.list.on('scroll', this.onViewScroll, this);
10312         
10313         /*
10314         this.list.swallowEvent('mousewheel');
10315         this.assetHeight = 0;
10316
10317         if(this.title){
10318             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10319             this.assetHeight += this.header.getHeight();
10320         }
10321
10322         this.innerList = this.list.createChild({cls:cls+'-inner'});
10323         this.innerList.on('mouseover', this.onViewOver, this);
10324         this.innerList.on('mousemove', this.onViewMove, this);
10325         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10326         
10327         if(this.allowBlank && !this.pageSize && !this.disableClear){
10328             this.footer = this.list.createChild({cls:cls+'-ft'});
10329             this.pageTb = new Roo.Toolbar(this.footer);
10330            
10331         }
10332         if(this.pageSize){
10333             this.footer = this.list.createChild({cls:cls+'-ft'});
10334             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10335                     {pageSize: this.pageSize});
10336             
10337         }
10338         
10339         if (this.pageTb && this.allowBlank && !this.disableClear) {
10340             var _this = this;
10341             this.pageTb.add(new Roo.Toolbar.Fill(), {
10342                 cls: 'x-btn-icon x-btn-clear',
10343                 text: '&#160;',
10344                 handler: function()
10345                 {
10346                     _this.collapse();
10347                     _this.clearValue();
10348                     _this.onSelect(false, -1);
10349                 }
10350             });
10351         }
10352         if (this.footer) {
10353             this.assetHeight += this.footer.getHeight();
10354         }
10355         */
10356             
10357         if(!this.tpl){
10358             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10359         }
10360
10361         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10362             singleSelect:true, store: this.store, selectedClass: this.selectedClass
10363         });
10364         //this.view.wrapEl.setDisplayed(false);
10365         this.view.on('click', this.onViewClick, this);
10366         
10367         
10368         
10369         this.store.on('beforeload', this.onBeforeLoad, this);
10370         this.store.on('load', this.onLoad, this);
10371         this.store.on('loadexception', this.onLoadException, this);
10372         /*
10373         if(this.resizable){
10374             this.resizer = new Roo.Resizable(this.list,  {
10375                pinned:true, handles:'se'
10376             });
10377             this.resizer.on('resize', function(r, w, h){
10378                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10379                 this.listWidth = w;
10380                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10381                 this.restrictHeight();
10382             }, this);
10383             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10384         }
10385         */
10386         if(!this.editable){
10387             this.editable = true;
10388             this.setEditable(false);
10389         }
10390         
10391         /*
10392         
10393         if (typeof(this.events.add.listeners) != 'undefined') {
10394             
10395             this.addicon = this.wrap.createChild(
10396                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
10397        
10398             this.addicon.on('click', function(e) {
10399                 this.fireEvent('add', this);
10400             }, this);
10401         }
10402         if (typeof(this.events.edit.listeners) != 'undefined') {
10403             
10404             this.editicon = this.wrap.createChild(
10405                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
10406             if (this.addicon) {
10407                 this.editicon.setStyle('margin-left', '40px');
10408             }
10409             this.editicon.on('click', function(e) {
10410                 
10411                 // we fire even  if inothing is selected..
10412                 this.fireEvent('edit', this, this.lastData );
10413                 
10414             }, this);
10415         }
10416         */
10417         
10418         this.keyNav = new Roo.KeyNav(this.inputEl(), {
10419             "up" : function(e){
10420                 this.inKeyMode = true;
10421                 this.selectPrev();
10422             },
10423
10424             "down" : function(e){
10425                 if(!this.isExpanded()){
10426                     this.onTriggerClick();
10427                 }else{
10428                     this.inKeyMode = true;
10429                     this.selectNext();
10430                 }
10431             },
10432
10433             "enter" : function(e){
10434 //                this.onViewClick();
10435                 //return true;
10436                 this.collapse();
10437                 
10438                 if(this.fireEvent("specialkey", this, e)){
10439                     this.onViewClick(false);
10440                 }
10441                 
10442                 return true;
10443             },
10444
10445             "esc" : function(e){
10446                 this.collapse();
10447             },
10448
10449             "tab" : function(e){
10450                 this.collapse();
10451                 
10452                 if(this.fireEvent("specialkey", this, e)){
10453                     this.onViewClick(false);
10454                 }
10455                 
10456                 return true;
10457             },
10458
10459             scope : this,
10460
10461             doRelay : function(foo, bar, hname){
10462                 if(hname == 'down' || this.scope.isExpanded()){
10463                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10464                 }
10465                 return true;
10466             },
10467
10468             forceKeyDown: true
10469         });
10470         
10471         
10472         this.queryDelay = Math.max(this.queryDelay || 10,
10473                 this.mode == 'local' ? 10 : 250);
10474         
10475         
10476         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10477         
10478         if(this.typeAhead){
10479             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10480         }
10481         if(this.editable !== false){
10482             this.inputEl().on("keyup", this.onKeyUp, this);
10483         }
10484         if(this.forceSelection){
10485             this.inputEl().on('blur', this.doForce, this);
10486         }
10487         
10488         if(this.multiple){
10489             this.choices = this.el.select('ul.select2-choices', true).first();
10490             this.searchField = this.el.select('ul li.select2-search-field', true).first();
10491         }
10492     },
10493     
10494     initTickableEvnets: function()
10495     {   
10496         if(this.hiddenName){
10497             
10498             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10499             
10500             this.hiddenField.dom.value =
10501                 this.hiddenValue !== undefined ? this.hiddenValue :
10502                 this.value !== undefined ? this.value : '';
10503
10504             // prevent input submission
10505             this.el.dom.removeAttribute('name');
10506             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10507              
10508              
10509         }
10510         
10511         this.list = this.el.select('ul.dropdown-menu',true).first();
10512         
10513         this.choices = this.el.select('ul.select2-choices', true).first();
10514         this.searchField = this.el.select('ul li.select2-search-field', true).first();
10515         
10516         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10517         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10518         
10519         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10520         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10521         
10522         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10523         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10524         
10525         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10526         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10527         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10528         
10529         this.okBtn.hide();
10530         this.cancelBtn.hide();
10531         
10532         var _this = this;
10533         
10534         (function(){
10535             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10536             _this.list.setWidth(lw);
10537         }).defer(100);
10538         
10539         this.list.on('mouseover', this.onViewOver, this);
10540         this.list.on('mousemove', this.onViewMove, this);
10541         
10542         this.list.on('scroll', this.onViewScroll, this);
10543         
10544         if(!this.tpl){
10545             this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
10546         }
10547
10548         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10549             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10550         });
10551         
10552         //this.view.wrapEl.setDisplayed(false);
10553         this.view.on('click', this.onViewClick, this);
10554         
10555         
10556         
10557         this.store.on('beforeload', this.onBeforeLoad, this);
10558         this.store.on('load', this.onLoad, this);
10559         this.store.on('loadexception', this.onLoadException, this);
10560         
10561 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
10562 //            "up" : function(e){
10563 //                this.inKeyMode = true;
10564 //                this.selectPrev();
10565 //            },
10566 //
10567 //            "down" : function(e){
10568 //                if(!this.isExpanded()){
10569 //                    this.onTriggerClick();
10570 //                }else{
10571 //                    this.inKeyMode = true;
10572 //                    this.selectNext();
10573 //                }
10574 //            },
10575 //
10576 //            "enter" : function(e){
10577 ////                this.onViewClick();
10578 //                //return true;
10579 //                this.collapse();
10580 //                
10581 //                if(this.fireEvent("specialkey", this, e)){
10582 //                    this.onViewClick(false);
10583 //                }
10584 //                
10585 //                return true;
10586 //            },
10587 //
10588 //            "esc" : function(e){
10589 //                this.collapse();
10590 //            },
10591 //
10592 //            "tab" : function(e){
10593 //                this.collapse();
10594 //                
10595 //                if(this.fireEvent("specialkey", this, e)){
10596 //                    this.onViewClick(false);
10597 //                }
10598 //                
10599 //                return true;
10600 //            },
10601 //
10602 //            scope : this,
10603 //
10604 //            doRelay : function(foo, bar, hname){
10605 //                if(hname == 'down' || this.scope.isExpanded()){
10606 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10607 //                }
10608 //                return true;
10609 //            },
10610 //
10611 //            forceKeyDown: true
10612 //        });
10613         
10614         
10615         this.queryDelay = Math.max(this.queryDelay || 10,
10616                 this.mode == 'local' ? 10 : 250);
10617         
10618         
10619         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10620         
10621         if(this.typeAhead){
10622             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10623         }
10624     },
10625
10626     onDestroy : function(){
10627         if(this.view){
10628             this.view.setStore(null);
10629             this.view.el.removeAllListeners();
10630             this.view.el.remove();
10631             this.view.purgeListeners();
10632         }
10633         if(this.list){
10634             this.list.dom.innerHTML  = '';
10635         }
10636         
10637         if(this.store){
10638             this.store.un('beforeload', this.onBeforeLoad, this);
10639             this.store.un('load', this.onLoad, this);
10640             this.store.un('loadexception', this.onLoadException, this);
10641         }
10642         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10643     },
10644
10645     // private
10646     fireKey : function(e){
10647         if(e.isNavKeyPress() && !this.list.isVisible()){
10648             this.fireEvent("specialkey", this, e);
10649         }
10650     },
10651
10652     // private
10653     onResize: function(w, h){
10654 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10655 //        
10656 //        if(typeof w != 'number'){
10657 //            // we do not handle it!?!?
10658 //            return;
10659 //        }
10660 //        var tw = this.trigger.getWidth();
10661 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
10662 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
10663 //        var x = w - tw;
10664 //        this.inputEl().setWidth( this.adjustWidth('input', x));
10665 //            
10666 //        //this.trigger.setStyle('left', x+'px');
10667 //        
10668 //        if(this.list && this.listWidth === undefined){
10669 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10670 //            this.list.setWidth(lw);
10671 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10672 //        }
10673         
10674     
10675         
10676     },
10677
10678     /**
10679      * Allow or prevent the user from directly editing the field text.  If false is passed,
10680      * the user will only be able to select from the items defined in the dropdown list.  This method
10681      * is the runtime equivalent of setting the 'editable' config option at config time.
10682      * @param {Boolean} value True to allow the user to directly edit the field text
10683      */
10684     setEditable : function(value){
10685         if(value == this.editable){
10686             return;
10687         }
10688         this.editable = value;
10689         if(!value){
10690             this.inputEl().dom.setAttribute('readOnly', true);
10691             this.inputEl().on('mousedown', this.onTriggerClick,  this);
10692             this.inputEl().addClass('x-combo-noedit');
10693         }else{
10694             this.inputEl().dom.setAttribute('readOnly', false);
10695             this.inputEl().un('mousedown', this.onTriggerClick,  this);
10696             this.inputEl().removeClass('x-combo-noedit');
10697         }
10698     },
10699
10700     // private
10701     
10702     onBeforeLoad : function(combo,opts){
10703         if(!this.hasFocus){
10704             return;
10705         }
10706          if (!opts.add) {
10707             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10708          }
10709         this.restrictHeight();
10710         this.selectedIndex = -1;
10711     },
10712
10713     // private
10714     onLoad : function(){
10715         
10716         this.hasQuery = false;
10717         
10718         if(!this.hasFocus){
10719             return;
10720         }
10721         
10722         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10723             this.loading.hide();
10724         }
10725         
10726         if(this.store.getCount() > 0){
10727             this.expand();
10728             this.restrictHeight();
10729             if(this.lastQuery == this.allQuery){
10730                 if(this.editable && !this.tickable){
10731                     this.inputEl().dom.select();
10732                 }
10733                 if(!this.selectByValue(this.value, true) && this.autoFocus){
10734                     this.select(0, true);
10735                 }
10736             }else{
10737                 if(this.autoFocus){
10738                     this.selectNext();
10739                 }
10740                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10741                     this.taTask.delay(this.typeAheadDelay);
10742                 }
10743             }
10744         }else{
10745             this.onEmptyResults();
10746         }
10747         
10748         //this.el.focus();
10749     },
10750     // private
10751     onLoadException : function()
10752     {
10753         this.hasQuery = false;
10754         
10755         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10756             this.loading.hide();
10757         }
10758         
10759         this.collapse();
10760         Roo.log(this.store.reader.jsonData);
10761         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10762             // fixme
10763             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10764         }
10765         
10766         
10767     },
10768     // private
10769     onTypeAhead : function(){
10770         if(this.store.getCount() > 0){
10771             var r = this.store.getAt(0);
10772             var newValue = r.data[this.displayField];
10773             var len = newValue.length;
10774             var selStart = this.getRawValue().length;
10775             
10776             if(selStart != len){
10777                 this.setRawValue(newValue);
10778                 this.selectText(selStart, newValue.length);
10779             }
10780         }
10781     },
10782
10783     // private
10784     onSelect : function(record, index){
10785         
10786         if(this.fireEvent('beforeselect', this, record, index) !== false){
10787         
10788             this.setFromData(index > -1 ? record.data : false);
10789             
10790             this.collapse();
10791             this.fireEvent('select', this, record, index);
10792         }
10793     },
10794
10795     /**
10796      * Returns the currently selected field value or empty string if no value is set.
10797      * @return {String} value The selected value
10798      */
10799     getValue : function(){
10800         
10801         if(this.multiple){
10802             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10803         }
10804         
10805         if(this.valueField){
10806             return typeof this.value != 'undefined' ? this.value : '';
10807         }else{
10808             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10809         }
10810     },
10811
10812     /**
10813      * Clears any text/value currently set in the field
10814      */
10815     clearValue : function(){
10816         if(this.hiddenField){
10817             this.hiddenField.dom.value = '';
10818         }
10819         this.value = '';
10820         this.setRawValue('');
10821         this.lastSelectionText = '';
10822         
10823     },
10824
10825     /**
10826      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
10827      * will be displayed in the field.  If the value does not match the data value of an existing item,
10828      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10829      * Otherwise the field will be blank (although the value will still be set).
10830      * @param {String} value The value to match
10831      */
10832     setValue : function(v){
10833         if(this.multiple){
10834             this.syncValue();
10835             return;
10836         }
10837         
10838         var text = v;
10839         if(this.valueField){
10840             var r = this.findRecord(this.valueField, v);
10841             if(r){
10842                 text = r.data[this.displayField];
10843             }else if(this.valueNotFoundText !== undefined){
10844                 text = this.valueNotFoundText;
10845             }
10846         }
10847         this.lastSelectionText = text;
10848         if(this.hiddenField){
10849             this.hiddenField.dom.value = v;
10850         }
10851         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10852         this.value = v;
10853     },
10854     /**
10855      * @property {Object} the last set data for the element
10856      */
10857     
10858     lastData : false,
10859     /**
10860      * Sets the value of the field based on a object which is related to the record format for the store.
10861      * @param {Object} value the value to set as. or false on reset?
10862      */
10863     setFromData : function(o){
10864         
10865         if(this.multiple){
10866             this.addItem(o);
10867             return;
10868         }
10869             
10870         var dv = ''; // display value
10871         var vv = ''; // value value..
10872         this.lastData = o;
10873         if (this.displayField) {
10874             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10875         } else {
10876             // this is an error condition!!!
10877             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
10878         }
10879         
10880         if(this.valueField){
10881             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10882         }
10883         
10884         if(this.hiddenField){
10885             this.hiddenField.dom.value = vv;
10886             
10887             this.lastSelectionText = dv;
10888             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10889             this.value = vv;
10890             return;
10891         }
10892         // no hidden field.. - we store the value in 'value', but still display
10893         // display field!!!!
10894         this.lastSelectionText = dv;
10895         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10896         this.value = vv;
10897         
10898         
10899     },
10900     // private
10901     reset : function(){
10902         // overridden so that last data is reset..
10903         this.setValue(this.originalValue);
10904         this.clearInvalid();
10905         this.lastData = false;
10906         if (this.view) {
10907             this.view.clearSelections();
10908         }
10909     },
10910     // private
10911     findRecord : function(prop, value){
10912         var record;
10913         if(this.store.getCount() > 0){
10914             this.store.each(function(r){
10915                 if(r.data[prop] == value){
10916                     record = r;
10917                     return false;
10918                 }
10919                 return true;
10920             });
10921         }
10922         return record;
10923     },
10924     
10925     getName: function()
10926     {
10927         // returns hidden if it's set..
10928         if (!this.rendered) {return ''};
10929         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
10930         
10931     },
10932     // private
10933     onViewMove : function(e, t){
10934         this.inKeyMode = false;
10935     },
10936
10937     // private
10938     onViewOver : function(e, t){
10939         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10940             return;
10941         }
10942         var item = this.view.findItemFromChild(t);
10943         
10944         if(item){
10945             var index = this.view.indexOf(item);
10946             this.select(index, false);
10947         }
10948     },
10949
10950     // private
10951     onViewClick : function(view, doFocus, el, e)
10952     {
10953         var index = this.view.getSelectedIndexes()[0];
10954         
10955         var r = this.store.getAt(index);
10956         
10957         if(this.tickable){
10958             
10959             if(e.getTarget().nodeName.toLowerCase() != 'input'){
10960                 return;
10961             }
10962             
10963             var rm = false;
10964             var _this = this;
10965             
10966             Roo.each(this.tickItems, function(v,k){
10967                 
10968                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10969                     _this.tickItems.splice(k, 1);
10970                     rm = true;
10971                     return;
10972                 }
10973             })
10974             
10975             if(rm){
10976                 return;
10977             }
10978             
10979             this.tickItems.push(r.data);
10980             return;
10981         }
10982         
10983         if(r){
10984             this.onSelect(r, index);
10985         }
10986         if(doFocus !== false && !this.blockFocus){
10987             this.inputEl().focus();
10988         }
10989     },
10990
10991     // private
10992     restrictHeight : function(){
10993         //this.innerList.dom.style.height = '';
10994         //var inner = this.innerList.dom;
10995         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10996         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10997         //this.list.beginUpdate();
10998         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10999         this.list.alignTo(this.inputEl(), this.listAlign);
11000         //this.list.endUpdate();
11001     },
11002
11003     // private
11004     onEmptyResults : function(){
11005         this.collapse();
11006     },
11007
11008     /**
11009      * Returns true if the dropdown list is expanded, else false.
11010      */
11011     isExpanded : function(){
11012         return this.list.isVisible();
11013     },
11014
11015     /**
11016      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11017      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11018      * @param {String} value The data value of the item to select
11019      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11020      * selected item if it is not currently in view (defaults to true)
11021      * @return {Boolean} True if the value matched an item in the list, else false
11022      */
11023     selectByValue : function(v, scrollIntoView){
11024         if(v !== undefined && v !== null){
11025             var r = this.findRecord(this.valueField || this.displayField, v);
11026             if(r){
11027                 this.select(this.store.indexOf(r), scrollIntoView);
11028                 return true;
11029             }
11030         }
11031         return false;
11032     },
11033
11034     /**
11035      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11036      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11037      * @param {Number} index The zero-based index of the list item to select
11038      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11039      * selected item if it is not currently in view (defaults to true)
11040      */
11041     select : function(index, scrollIntoView){
11042         this.selectedIndex = index;
11043         this.view.select(index);
11044         if(scrollIntoView !== false){
11045             var el = this.view.getNode(index);
11046             if(el){
11047                 //this.innerList.scrollChildIntoView(el, false);
11048                 
11049             }
11050         }
11051     },
11052
11053     // private
11054     selectNext : function(){
11055         var ct = this.store.getCount();
11056         if(ct > 0){
11057             if(this.selectedIndex == -1){
11058                 this.select(0);
11059             }else if(this.selectedIndex < ct-1){
11060                 this.select(this.selectedIndex+1);
11061             }
11062         }
11063     },
11064
11065     // private
11066     selectPrev : function(){
11067         var ct = this.store.getCount();
11068         if(ct > 0){
11069             if(this.selectedIndex == -1){
11070                 this.select(0);
11071             }else if(this.selectedIndex != 0){
11072                 this.select(this.selectedIndex-1);
11073             }
11074         }
11075     },
11076
11077     // private
11078     onKeyUp : function(e){
11079         if(this.editable !== false && !e.isSpecialKey()){
11080             this.lastKey = e.getKey();
11081             this.dqTask.delay(this.queryDelay);
11082         }
11083     },
11084
11085     // private
11086     validateBlur : function(){
11087         return !this.list || !this.list.isVisible();   
11088     },
11089
11090     // private
11091     initQuery : function(){
11092         this.doQuery(this.getRawValue());
11093     },
11094
11095     // private
11096     doForce : function(){
11097         if(this.inputEl().dom.value.length > 0){
11098             this.inputEl().dom.value =
11099                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11100              
11101         }
11102     },
11103
11104     /**
11105      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11106      * query allowing the query action to be canceled if needed.
11107      * @param {String} query The SQL query to execute
11108      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11109      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11110      * saved in the current store (defaults to false)
11111      */
11112     doQuery : function(q, forceAll){
11113         
11114         if(q === undefined || q === null){
11115             q = '';
11116         }
11117         var qe = {
11118             query: q,
11119             forceAll: forceAll,
11120             combo: this,
11121             cancel:false
11122         };
11123         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11124             return false;
11125         }
11126         q = qe.query;
11127         
11128         forceAll = qe.forceAll;
11129         if(forceAll === true || (q.length >= this.minChars)){
11130             
11131             this.hasQuery = true;
11132             
11133             if(this.lastQuery != q || this.alwaysQuery){
11134                 this.lastQuery = q;
11135                 if(this.mode == 'local'){
11136                     this.selectedIndex = -1;
11137                     if(forceAll){
11138                         this.store.clearFilter();
11139                     }else{
11140                         this.store.filter(this.displayField, q);
11141                     }
11142                     this.onLoad();
11143                 }else{
11144                     this.store.baseParams[this.queryParam] = q;
11145                     
11146                     var options = {params : this.getParams(q)};
11147                     
11148                     if(this.loadNext){
11149                         options.add = true;
11150                         options.params.start = this.page * this.pageSize;
11151                     }
11152                     
11153                     this.store.load(options);
11154                     /*
11155                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11156                      *  we should expand the list on onLoad
11157                      *  so command out it
11158                      */
11159 //                    this.expand();
11160                 }
11161             }else{
11162                 this.selectedIndex = -1;
11163                 this.onLoad();   
11164             }
11165         }
11166         
11167         this.loadNext = false;
11168     },
11169
11170     // private
11171     getParams : function(q){
11172         var p = {};
11173         //p[this.queryParam] = q;
11174         
11175         if(this.pageSize){
11176             p.start = 0;
11177             p.limit = this.pageSize;
11178         }
11179         return p;
11180     },
11181
11182     /**
11183      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11184      */
11185     collapse : function(){
11186         if(!this.isExpanded()){
11187             return;
11188         }
11189         
11190         this.list.hide();
11191         
11192         if(this.tickable){
11193             this.okBtn.hide();
11194             this.cancelBtn.hide();
11195             this.trigger.show();
11196         }
11197         
11198         Roo.get(document).un('mousedown', this.collapseIf, this);
11199         Roo.get(document).un('mousewheel', this.collapseIf, this);
11200         if (!this.editable) {
11201             Roo.get(document).un('keydown', this.listKeyPress, this);
11202         }
11203         this.fireEvent('collapse', this);
11204     },
11205
11206     // private
11207     collapseIf : function(e){
11208         var in_combo  = e.within(this.el);
11209         var in_list =  e.within(this.list);
11210         
11211         if (in_combo || in_list) {
11212             //e.stopPropagation();
11213             return;
11214         }
11215         
11216         if(this.tickable){
11217             this.onTickableFooterButtonClick(e, false, false);
11218         }
11219
11220         this.collapse();
11221         
11222     },
11223
11224     /**
11225      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11226      */
11227     expand : function(){
11228        
11229         if(this.isExpanded() || !this.hasFocus){
11230             return;
11231         }
11232          Roo.log('expand');
11233         this.list.alignTo(this.inputEl(), this.listAlign);
11234         this.list.show();
11235         
11236         if(this.tickable){
11237             
11238             this.tickItems = Roo.apply([], this.item);
11239             
11240             this.okBtn.show();
11241             this.cancelBtn.show();
11242             this.trigger.hide();
11243             
11244         }
11245         
11246         Roo.get(document).on('mousedown', this.collapseIf, this);
11247         Roo.get(document).on('mousewheel', this.collapseIf, this);
11248         if (!this.editable) {
11249             Roo.get(document).on('keydown', this.listKeyPress, this);
11250         }
11251         
11252         this.fireEvent('expand', this);
11253     },
11254
11255     // private
11256     // Implements the default empty TriggerField.onTriggerClick function
11257     onTriggerClick : function()
11258     {
11259         Roo.log('trigger click');
11260         
11261         if(this.disabled){
11262             return;
11263         }
11264         
11265         if(this.tickable){
11266             this.onTickableTriggerClick();
11267             return;
11268         }
11269         
11270         this.page = 0;
11271         this.loadNext = false;
11272         
11273         if(this.isExpanded()){
11274             this.collapse();
11275             if (!this.blockFocus) {
11276                 this.inputEl().focus();
11277             }
11278             
11279         }else {
11280             this.hasFocus = true;
11281             if(this.triggerAction == 'all') {
11282                 this.doQuery(this.allQuery, true);
11283             } else {
11284                 this.doQuery(this.getRawValue());
11285             }
11286             if (!this.blockFocus) {
11287                 this.inputEl().focus();
11288             }
11289         }
11290     },
11291     
11292     onTickableTriggerClick : function()
11293     {
11294         this.page = 0;
11295         this.loadNext = false;
11296         this.hasFocus = true;
11297         
11298         if(this.triggerAction == 'all') {
11299             this.doQuery(this.allQuery, true);
11300         } else {
11301             this.doQuery(this.getRawValue());
11302         }
11303     },
11304     
11305     listKeyPress : function(e)
11306     {
11307         //Roo.log('listkeypress');
11308         // scroll to first matching element based on key pres..
11309         if (e.isSpecialKey()) {
11310             return false;
11311         }
11312         var k = String.fromCharCode(e.getKey()).toUpperCase();
11313         //Roo.log(k);
11314         var match  = false;
11315         var csel = this.view.getSelectedNodes();
11316         var cselitem = false;
11317         if (csel.length) {
11318             var ix = this.view.indexOf(csel[0]);
11319             cselitem  = this.store.getAt(ix);
11320             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11321                 cselitem = false;
11322             }
11323             
11324         }
11325         
11326         this.store.each(function(v) { 
11327             if (cselitem) {
11328                 // start at existing selection.
11329                 if (cselitem.id == v.id) {
11330                     cselitem = false;
11331                 }
11332                 return true;
11333             }
11334                 
11335             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11336                 match = this.store.indexOf(v);
11337                 return false;
11338             }
11339             return true;
11340         }, this);
11341         
11342         if (match === false) {
11343             return true; // no more action?
11344         }
11345         // scroll to?
11346         this.view.select(match);
11347         var sn = Roo.get(this.view.getSelectedNodes()[0])
11348         //sn.scrollIntoView(sn.dom.parentNode, false);
11349     },
11350     
11351     onViewScroll : function(e, t){
11352         
11353         if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11354             return;
11355         }
11356         
11357         this.hasQuery = true;
11358         
11359         this.loading = this.list.select('.loading', true).first();
11360         
11361         if(this.loading === null){
11362             this.list.createChild({
11363                 tag: 'div',
11364                 cls: 'loading select2-more-results select2-active',
11365                 html: 'Loading more results...'
11366             })
11367             
11368             this.loading = this.list.select('.loading', true).first();
11369             
11370             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11371             
11372             this.loading.hide();
11373         }
11374         
11375         this.loading.show();
11376         
11377         var _combo = this;
11378         
11379         this.page++;
11380         this.loadNext = true;
11381         
11382         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11383         
11384         return;
11385     },
11386     
11387     addItem : function(o)
11388     {   
11389         var dv = ''; // display value
11390         
11391         if (this.displayField) {
11392             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11393         } else {
11394             // this is an error condition!!!
11395             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11396         }
11397         
11398         if(!dv.length){
11399             return;
11400         }
11401         
11402         var choice = this.choices.createChild({
11403             tag: 'li',
11404             cls: 'select2-search-choice',
11405             cn: [
11406                 {
11407                     tag: 'div',
11408                     html: dv
11409                 },
11410                 {
11411                     tag: 'a',
11412                     href: '#',
11413                     cls: 'select2-search-choice-close',
11414                     tabindex: '-1'
11415                 }
11416             ]
11417             
11418         }, this.searchField);
11419         
11420         var close = choice.select('a.select2-search-choice-close', true).first()
11421         
11422         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11423         
11424         this.item.push(o);
11425         
11426         this.lastData = o;
11427         
11428         this.syncValue();
11429         
11430         this.inputEl().dom.value = '';
11431         
11432     },
11433     
11434     onRemoveItem : function(e, _self, o)
11435     {
11436         e.preventDefault();
11437         var index = this.item.indexOf(o.data) * 1;
11438         
11439         if( index < 0){
11440             Roo.log('not this item?!');
11441             return;
11442         }
11443         
11444         this.item.splice(index, 1);
11445         o.item.remove();
11446         
11447         this.syncValue();
11448         
11449         this.fireEvent('remove', this, e);
11450         
11451     },
11452     
11453     syncValue : function()
11454     {
11455         if(!this.item.length){
11456             this.clearValue();
11457             return;
11458         }
11459             
11460         var value = [];
11461         var _this = this;
11462         Roo.each(this.item, function(i){
11463             if(_this.valueField){
11464                 value.push(i[_this.valueField]);
11465                 return;
11466             }
11467
11468             value.push(i);
11469         });
11470
11471         this.value = value.join(',');
11472
11473         if(this.hiddenField){
11474             this.hiddenField.dom.value = this.value;
11475         }
11476     },
11477     
11478     clearItem : function()
11479     {
11480         if(!this.multiple){
11481             return;
11482         }
11483         
11484         this.item = [];
11485         
11486         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11487            c.remove();
11488         });
11489         
11490         this.syncValue();
11491     },
11492     
11493     inputEl: function ()
11494     {
11495         if(this.tickable){
11496             return this.searchField;
11497         }
11498         return this.el.select('input.form-control',true).first();
11499     },
11500     
11501     
11502     onTickableFooterButtonClick : function(e, btn, el)
11503     {
11504         e.preventDefault();
11505         
11506         if(btn && btn.name == 'cancel'){
11507             this.tickItems = Roo.apply([], this.item);
11508             this.collapse();
11509             return;
11510         }
11511         
11512         this.clearItem();
11513         
11514         var _this = this;
11515         
11516         Roo.each(this.tickItems, function(o){
11517             _this.addItem(o);
11518         });
11519         
11520         this.collapse();
11521         
11522     }
11523     
11524     
11525
11526     /** 
11527     * @cfg {Boolean} grow 
11528     * @hide 
11529     */
11530     /** 
11531     * @cfg {Number} growMin 
11532     * @hide 
11533     */
11534     /** 
11535     * @cfg {Number} growMax 
11536     * @hide 
11537     */
11538     /**
11539      * @hide
11540      * @method autoSize
11541      */
11542 });
11543 /*
11544  * Based on:
11545  * Ext JS Library 1.1.1
11546  * Copyright(c) 2006-2007, Ext JS, LLC.
11547  *
11548  * Originally Released Under LGPL - original licence link has changed is not relivant.
11549  *
11550  * Fork - LGPL
11551  * <script type="text/javascript">
11552  */
11553
11554 /**
11555  * @class Roo.View
11556  * @extends Roo.util.Observable
11557  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
11558  * This class also supports single and multi selection modes. <br>
11559  * Create a data model bound view:
11560  <pre><code>
11561  var store = new Roo.data.Store(...);
11562
11563  var view = new Roo.View({
11564     el : "my-element",
11565     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
11566  
11567     singleSelect: true,
11568     selectedClass: "ydataview-selected",
11569     store: store
11570  });
11571
11572  // listen for node click?
11573  view.on("click", function(vw, index, node, e){
11574  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11575  });
11576
11577  // load XML data
11578  dataModel.load("foobar.xml");
11579  </code></pre>
11580  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11581  * <br><br>
11582  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11583  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11584  * 
11585  * Note: old style constructor is still suported (container, template, config)
11586  * 
11587  * @constructor
11588  * Create a new View
11589  * @param {Object} config The config object
11590  * 
11591  */
11592 Roo.View = function(config, depreciated_tpl, depreciated_config){
11593     
11594     this.parent = false;
11595     
11596     if (typeof(depreciated_tpl) == 'undefined') {
11597         // new way.. - universal constructor.
11598         Roo.apply(this, config);
11599         this.el  = Roo.get(this.el);
11600     } else {
11601         // old format..
11602         this.el  = Roo.get(config);
11603         this.tpl = depreciated_tpl;
11604         Roo.apply(this, depreciated_config);
11605     }
11606     this.wrapEl  = this.el.wrap().wrap();
11607     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11608     
11609     
11610     if(typeof(this.tpl) == "string"){
11611         this.tpl = new Roo.Template(this.tpl);
11612     } else {
11613         // support xtype ctors..
11614         this.tpl = new Roo.factory(this.tpl, Roo);
11615     }
11616     
11617     
11618     this.tpl.compile();
11619     
11620     /** @private */
11621     this.addEvents({
11622         /**
11623          * @event beforeclick
11624          * Fires before a click is processed. Returns false to cancel the default action.
11625          * @param {Roo.View} this
11626          * @param {Number} index The index of the target node
11627          * @param {HTMLElement} node The target node
11628          * @param {Roo.EventObject} e The raw event object
11629          */
11630             "beforeclick" : true,
11631         /**
11632          * @event click
11633          * Fires when a template node is clicked.
11634          * @param {Roo.View} this
11635          * @param {Number} index The index of the target node
11636          * @param {HTMLElement} node The target node
11637          * @param {Roo.EventObject} e The raw event object
11638          */
11639             "click" : true,
11640         /**
11641          * @event dblclick
11642          * Fires when a template node is double clicked.
11643          * @param {Roo.View} this
11644          * @param {Number} index The index of the target node
11645          * @param {HTMLElement} node The target node
11646          * @param {Roo.EventObject} e The raw event object
11647          */
11648             "dblclick" : true,
11649         /**
11650          * @event contextmenu
11651          * Fires when a template node is right clicked.
11652          * @param {Roo.View} this
11653          * @param {Number} index The index of the target node
11654          * @param {HTMLElement} node The target node
11655          * @param {Roo.EventObject} e The raw event object
11656          */
11657             "contextmenu" : true,
11658         /**
11659          * @event selectionchange
11660          * Fires when the selected nodes change.
11661          * @param {Roo.View} this
11662          * @param {Array} selections Array of the selected nodes
11663          */
11664             "selectionchange" : true,
11665     
11666         /**
11667          * @event beforeselect
11668          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11669          * @param {Roo.View} this
11670          * @param {HTMLElement} node The node to be selected
11671          * @param {Array} selections Array of currently selected nodes
11672          */
11673             "beforeselect" : true,
11674         /**
11675          * @event preparedata
11676          * Fires on every row to render, to allow you to change the data.
11677          * @param {Roo.View} this
11678          * @param {Object} data to be rendered (change this)
11679          */
11680           "preparedata" : true
11681           
11682           
11683         });
11684
11685
11686
11687     this.el.on({
11688         "click": this.onClick,
11689         "dblclick": this.onDblClick,
11690         "contextmenu": this.onContextMenu,
11691         scope:this
11692     });
11693
11694     this.selections = [];
11695     this.nodes = [];
11696     this.cmp = new Roo.CompositeElementLite([]);
11697     if(this.store){
11698         this.store = Roo.factory(this.store, Roo.data);
11699         this.setStore(this.store, true);
11700     }
11701     
11702     if ( this.footer && this.footer.xtype) {
11703            
11704          var fctr = this.wrapEl.appendChild(document.createElement("div"));
11705         
11706         this.footer.dataSource = this.store
11707         this.footer.container = fctr;
11708         this.footer = Roo.factory(this.footer, Roo);
11709         fctr.insertFirst(this.el);
11710         
11711         // this is a bit insane - as the paging toolbar seems to detach the el..
11712 //        dom.parentNode.parentNode.parentNode
11713          // they get detached?
11714     }
11715     
11716     
11717     Roo.View.superclass.constructor.call(this);
11718     
11719     
11720 };
11721
11722 Roo.extend(Roo.View, Roo.util.Observable, {
11723     
11724      /**
11725      * @cfg {Roo.data.Store} store Data store to load data from.
11726      */
11727     store : false,
11728     
11729     /**
11730      * @cfg {String|Roo.Element} el The container element.
11731      */
11732     el : '',
11733     
11734     /**
11735      * @cfg {String|Roo.Template} tpl The template used by this View 
11736      */
11737     tpl : false,
11738     /**
11739      * @cfg {String} dataName the named area of the template to use as the data area
11740      *                          Works with domtemplates roo-name="name"
11741      */
11742     dataName: false,
11743     /**
11744      * @cfg {String} selectedClass The css class to add to selected nodes
11745      */
11746     selectedClass : "x-view-selected",
11747      /**
11748      * @cfg {String} emptyText The empty text to show when nothing is loaded.
11749      */
11750     emptyText : "",
11751     
11752     /**
11753      * @cfg {String} text to display on mask (default Loading)
11754      */
11755     mask : false,
11756     /**
11757      * @cfg {Boolean} multiSelect Allow multiple selection
11758      */
11759     multiSelect : false,
11760     /**
11761      * @cfg {Boolean} singleSelect Allow single selection
11762      */
11763     singleSelect:  false,
11764     
11765     /**
11766      * @cfg {Boolean} toggleSelect - selecting 
11767      */
11768     toggleSelect : false,
11769     
11770     /**
11771      * @cfg {Boolean} tickable - selecting 
11772      */
11773     tickable : false,
11774     
11775     /**
11776      * Returns the element this view is bound to.
11777      * @return {Roo.Element}
11778      */
11779     getEl : function(){
11780         return this.wrapEl;
11781     },
11782     
11783     
11784
11785     /**
11786      * Refreshes the view. - called by datachanged on the store. - do not call directly.
11787      */
11788     refresh : function(){
11789         Roo.log('refresh');
11790         var t = this.tpl;
11791         
11792         // if we are using something like 'domtemplate', then
11793         // the what gets used is:
11794         // t.applySubtemplate(NAME, data, wrapping data..)
11795         // the outer template then get' applied with
11796         //     the store 'extra data'
11797         // and the body get's added to the
11798         //      roo-name="data" node?
11799         //      <span class='roo-tpl-{name}'></span> ?????
11800         
11801         
11802         
11803         this.clearSelections();
11804         this.el.update("");
11805         var html = [];
11806         var records = this.store.getRange();
11807         if(records.length < 1) {
11808             
11809             // is this valid??  = should it render a template??
11810             
11811             this.el.update(this.emptyText);
11812             return;
11813         }
11814         var el = this.el;
11815         if (this.dataName) {
11816             this.el.update(t.apply(this.store.meta)); //????
11817             el = this.el.child('.roo-tpl-' + this.dataName);
11818         }
11819         
11820         for(var i = 0, len = records.length; i < len; i++){
11821             var data = this.prepareData(records[i].data, i, records[i]);
11822             this.fireEvent("preparedata", this, data, i, records[i]);
11823             
11824             var d = Roo.apply({}, data);
11825             
11826             if(this.tickable){
11827                 Roo.apply(d, {'roo-id' : Roo.id()});
11828                 
11829                 var _this = this;
11830             
11831                 Roo.each(this.parent.item, function(item){
11832                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11833                         return;
11834                     }
11835                     Roo.apply(d, {'roo-data-checked' : 'checked'});
11836                 });
11837             }
11838             
11839             html[html.length] = Roo.util.Format.trim(
11840                 this.dataName ?
11841                     t.applySubtemplate(this.dataName, d, this.store.meta) :
11842                     t.apply(d)
11843             );
11844         }
11845         
11846         
11847         
11848         el.update(html.join(""));
11849         this.nodes = el.dom.childNodes;
11850         this.updateIndexes(0);
11851     },
11852     
11853
11854     /**
11855      * Function to override to reformat the data that is sent to
11856      * the template for each node.
11857      * DEPRICATED - use the preparedata event handler.
11858      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11859      * a JSON object for an UpdateManager bound view).
11860      */
11861     prepareData : function(data, index, record)
11862     {
11863         this.fireEvent("preparedata", this, data, index, record);
11864         return data;
11865     },
11866
11867     onUpdate : function(ds, record){
11868          Roo.log('on update');   
11869         this.clearSelections();
11870         var index = this.store.indexOf(record);
11871         var n = this.nodes[index];
11872         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11873         n.parentNode.removeChild(n);
11874         this.updateIndexes(index, index);
11875     },
11876
11877     
11878     
11879 // --------- FIXME     
11880     onAdd : function(ds, records, index)
11881     {
11882         Roo.log(['on Add', ds, records, index] );        
11883         this.clearSelections();
11884         if(this.nodes.length == 0){
11885             this.refresh();
11886             return;
11887         }
11888         var n = this.nodes[index];
11889         for(var i = 0, len = records.length; i < len; i++){
11890             var d = this.prepareData(records[i].data, i, records[i]);
11891             if(n){
11892                 this.tpl.insertBefore(n, d);
11893             }else{
11894                 
11895                 this.tpl.append(this.el, d);
11896             }
11897         }
11898         this.updateIndexes(index);
11899     },
11900
11901     onRemove : function(ds, record, index){
11902         Roo.log('onRemove');
11903         this.clearSelections();
11904         var el = this.dataName  ?
11905             this.el.child('.roo-tpl-' + this.dataName) :
11906             this.el; 
11907         
11908         el.dom.removeChild(this.nodes[index]);
11909         this.updateIndexes(index);
11910     },
11911
11912     /**
11913      * Refresh an individual node.
11914      * @param {Number} index
11915      */
11916     refreshNode : function(index){
11917         this.onUpdate(this.store, this.store.getAt(index));
11918     },
11919
11920     updateIndexes : function(startIndex, endIndex){
11921         var ns = this.nodes;
11922         startIndex = startIndex || 0;
11923         endIndex = endIndex || ns.length - 1;
11924         for(var i = startIndex; i <= endIndex; i++){
11925             ns[i].nodeIndex = i;
11926         }
11927     },
11928
11929     /**
11930      * Changes the data store this view uses and refresh the view.
11931      * @param {Store} store
11932      */
11933     setStore : function(store, initial){
11934         if(!initial && this.store){
11935             this.store.un("datachanged", this.refresh);
11936             this.store.un("add", this.onAdd);
11937             this.store.un("remove", this.onRemove);
11938             this.store.un("update", this.onUpdate);
11939             this.store.un("clear", this.refresh);
11940             this.store.un("beforeload", this.onBeforeLoad);
11941             this.store.un("load", this.onLoad);
11942             this.store.un("loadexception", this.onLoad);
11943         }
11944         if(store){
11945           
11946             store.on("datachanged", this.refresh, this);
11947             store.on("add", this.onAdd, this);
11948             store.on("remove", this.onRemove, this);
11949             store.on("update", this.onUpdate, this);
11950             store.on("clear", this.refresh, this);
11951             store.on("beforeload", this.onBeforeLoad, this);
11952             store.on("load", this.onLoad, this);
11953             store.on("loadexception", this.onLoad, this);
11954         }
11955         
11956         if(store){
11957             this.refresh();
11958         }
11959     },
11960     /**
11961      * onbeforeLoad - masks the loading area.
11962      *
11963      */
11964     onBeforeLoad : function(store,opts)
11965     {
11966          Roo.log('onBeforeLoad');   
11967         if (!opts.add) {
11968             this.el.update("");
11969         }
11970         this.el.mask(this.mask ? this.mask : "Loading" ); 
11971     },
11972     onLoad : function ()
11973     {
11974         this.el.unmask();
11975     },
11976     
11977
11978     /**
11979      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11980      * @param {HTMLElement} node
11981      * @return {HTMLElement} The template node
11982      */
11983     findItemFromChild : function(node){
11984         var el = this.dataName  ?
11985             this.el.child('.roo-tpl-' + this.dataName,true) :
11986             this.el.dom; 
11987         
11988         if(!node || node.parentNode == el){
11989                     return node;
11990             }
11991             var p = node.parentNode;
11992             while(p && p != el){
11993             if(p.parentNode == el){
11994                 return p;
11995             }
11996             p = p.parentNode;
11997         }
11998             return null;
11999     },
12000
12001     /** @ignore */
12002     onClick : function(e){
12003         var item = this.findItemFromChild(e.getTarget());
12004         if(item){
12005             var index = this.indexOf(item);
12006             if(this.onItemClick(item, index, e) !== false){
12007                 this.fireEvent("click", this, index, item, e);
12008             }
12009         }else{
12010             this.clearSelections();
12011         }
12012     },
12013
12014     /** @ignore */
12015     onContextMenu : function(e){
12016         var item = this.findItemFromChild(e.getTarget());
12017         if(item){
12018             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12019         }
12020     },
12021
12022     /** @ignore */
12023     onDblClick : function(e){
12024         var item = this.findItemFromChild(e.getTarget());
12025         if(item){
12026             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12027         }
12028     },
12029
12030     onItemClick : function(item, index, e)
12031     {
12032         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12033             return false;
12034         }
12035         if (this.toggleSelect) {
12036             var m = this.isSelected(item) ? 'unselect' : 'select';
12037             Roo.log(m);
12038             var _t = this;
12039             _t[m](item, true, false);
12040             return true;
12041         }
12042         if(this.multiSelect || this.singleSelect){
12043             if(this.multiSelect && e.shiftKey && this.lastSelection){
12044                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12045             }else{
12046                 this.select(item, this.multiSelect && e.ctrlKey);
12047                 this.lastSelection = item;
12048             }
12049             
12050             if(!this.tickable){
12051                 e.preventDefault();
12052             }
12053             
12054         }
12055         return true;
12056     },
12057
12058     /**
12059      * Get the number of selected nodes.
12060      * @return {Number}
12061      */
12062     getSelectionCount : function(){
12063         return this.selections.length;
12064     },
12065
12066     /**
12067      * Get the currently selected nodes.
12068      * @return {Array} An array of HTMLElements
12069      */
12070     getSelectedNodes : function(){
12071         return this.selections;
12072     },
12073
12074     /**
12075      * Get the indexes of the selected nodes.
12076      * @return {Array}
12077      */
12078     getSelectedIndexes : function(){
12079         var indexes = [], s = this.selections;
12080         for(var i = 0, len = s.length; i < len; i++){
12081             indexes.push(s[i].nodeIndex);
12082         }
12083         return indexes;
12084     },
12085
12086     /**
12087      * Clear all selections
12088      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12089      */
12090     clearSelections : function(suppressEvent){
12091         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12092             this.cmp.elements = this.selections;
12093             this.cmp.removeClass(this.selectedClass);
12094             this.selections = [];
12095             if(!suppressEvent){
12096                 this.fireEvent("selectionchange", this, this.selections);
12097             }
12098         }
12099     },
12100
12101     /**
12102      * Returns true if the passed node is selected
12103      * @param {HTMLElement/Number} node The node or node index
12104      * @return {Boolean}
12105      */
12106     isSelected : function(node){
12107         var s = this.selections;
12108         if(s.length < 1){
12109             return false;
12110         }
12111         node = this.getNode(node);
12112         return s.indexOf(node) !== -1;
12113     },
12114
12115     /**
12116      * Selects nodes.
12117      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12118      * @param {Boolean} keepExisting (optional) true to keep existing selections
12119      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12120      */
12121     select : function(nodeInfo, keepExisting, suppressEvent){
12122         if(nodeInfo instanceof Array){
12123             if(!keepExisting){
12124                 this.clearSelections(true);
12125             }
12126             for(var i = 0, len = nodeInfo.length; i < len; i++){
12127                 this.select(nodeInfo[i], true, true);
12128             }
12129             return;
12130         } 
12131         var node = this.getNode(nodeInfo);
12132         if(!node || this.isSelected(node)){
12133             return; // already selected.
12134         }
12135         if(!keepExisting){
12136             this.clearSelections(true);
12137         }
12138         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12139             Roo.fly(node).addClass(this.selectedClass);
12140             this.selections.push(node);
12141             if(!suppressEvent){
12142                 this.fireEvent("selectionchange", this, this.selections);
12143             }
12144         }
12145         
12146         
12147     },
12148       /**
12149      * Unselects nodes.
12150      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12151      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12152      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12153      */
12154     unselect : function(nodeInfo, keepExisting, suppressEvent)
12155     {
12156         if(nodeInfo instanceof Array){
12157             Roo.each(this.selections, function(s) {
12158                 this.unselect(s, nodeInfo);
12159             }, this);
12160             return;
12161         }
12162         var node = this.getNode(nodeInfo);
12163         if(!node || !this.isSelected(node)){
12164             Roo.log("not selected");
12165             return; // not selected.
12166         }
12167         // fireevent???
12168         var ns = [];
12169         Roo.each(this.selections, function(s) {
12170             if (s == node ) {
12171                 Roo.fly(node).removeClass(this.selectedClass);
12172
12173                 return;
12174             }
12175             ns.push(s);
12176         },this);
12177         
12178         this.selections= ns;
12179         this.fireEvent("selectionchange", this, this.selections);
12180     },
12181
12182     /**
12183      * Gets a template node.
12184      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12185      * @return {HTMLElement} The node or null if it wasn't found
12186      */
12187     getNode : function(nodeInfo){
12188         if(typeof nodeInfo == "string"){
12189             return document.getElementById(nodeInfo);
12190         }else if(typeof nodeInfo == "number"){
12191             return this.nodes[nodeInfo];
12192         }
12193         return nodeInfo;
12194     },
12195
12196     /**
12197      * Gets a range template nodes.
12198      * @param {Number} startIndex
12199      * @param {Number} endIndex
12200      * @return {Array} An array of nodes
12201      */
12202     getNodes : function(start, end){
12203         var ns = this.nodes;
12204         start = start || 0;
12205         end = typeof end == "undefined" ? ns.length - 1 : end;
12206         var nodes = [];
12207         if(start <= end){
12208             for(var i = start; i <= end; i++){
12209                 nodes.push(ns[i]);
12210             }
12211         } else{
12212             for(var i = start; i >= end; i--){
12213                 nodes.push(ns[i]);
12214             }
12215         }
12216         return nodes;
12217     },
12218
12219     /**
12220      * Finds the index of the passed node
12221      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12222      * @return {Number} The index of the node or -1
12223      */
12224     indexOf : function(node){
12225         node = this.getNode(node);
12226         if(typeof node.nodeIndex == "number"){
12227             return node.nodeIndex;
12228         }
12229         var ns = this.nodes;
12230         for(var i = 0, len = ns.length; i < len; i++){
12231             if(ns[i] == node){
12232                 return i;
12233             }
12234         }
12235         return -1;
12236     }
12237 });
12238 /*
12239  * - LGPL
12240  *
12241  * based on jquery fullcalendar
12242  * 
12243  */
12244
12245 Roo.bootstrap = Roo.bootstrap || {};
12246 /**
12247  * @class Roo.bootstrap.Calendar
12248  * @extends Roo.bootstrap.Component
12249  * Bootstrap Calendar class
12250  * @cfg {Boolean} loadMask (true|false) default false
12251  * @cfg {Object} header generate the user specific header of the calendar, default false
12252
12253  * @constructor
12254  * Create a new Container
12255  * @param {Object} config The config object
12256  */
12257
12258
12259
12260 Roo.bootstrap.Calendar = function(config){
12261     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12262      this.addEvents({
12263         /**
12264              * @event select
12265              * Fires when a date is selected
12266              * @param {DatePicker} this
12267              * @param {Date} date The selected date
12268              */
12269         'select': true,
12270         /**
12271              * @event monthchange
12272              * Fires when the displayed month changes 
12273              * @param {DatePicker} this
12274              * @param {Date} date The selected month
12275              */
12276         'monthchange': true,
12277         /**
12278              * @event evententer
12279              * Fires when mouse over an event
12280              * @param {Calendar} this
12281              * @param {event} Event
12282              */
12283         'evententer': true,
12284         /**
12285              * @event eventleave
12286              * Fires when the mouse leaves an
12287              * @param {Calendar} this
12288              * @param {event}
12289              */
12290         'eventleave': true,
12291         /**
12292              * @event eventclick
12293              * Fires when the mouse click an
12294              * @param {Calendar} this
12295              * @param {event}
12296              */
12297         'eventclick': true
12298         
12299     });
12300
12301 };
12302
12303 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
12304     
12305      /**
12306      * @cfg {Number} startDay
12307      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12308      */
12309     startDay : 0,
12310     
12311     loadMask : false,
12312     
12313     header : false,
12314       
12315     getAutoCreate : function(){
12316         
12317         
12318         var fc_button = function(name, corner, style, content ) {
12319             return Roo.apply({},{
12320                 tag : 'span',
12321                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
12322                          (corner.length ?
12323                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12324                             ''
12325                         ),
12326                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12327                 unselectable: 'on'
12328             });
12329         };
12330         
12331         var header = {};
12332         
12333         if(!this.header){
12334             header = {
12335                 tag : 'table',
12336                 cls : 'fc-header',
12337                 style : 'width:100%',
12338                 cn : [
12339                     {
12340                         tag: 'tr',
12341                         cn : [
12342                             {
12343                                 tag : 'td',
12344                                 cls : 'fc-header-left',
12345                                 cn : [
12346                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
12347                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
12348                                     { tag: 'span', cls: 'fc-header-space' },
12349                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
12350
12351
12352                                 ]
12353                             },
12354
12355                             {
12356                                 tag : 'td',
12357                                 cls : 'fc-header-center',
12358                                 cn : [
12359                                     {
12360                                         tag: 'span',
12361                                         cls: 'fc-header-title',
12362                                         cn : {
12363                                             tag: 'H2',
12364                                             html : 'month / year'
12365                                         }
12366                                     }
12367
12368                                 ]
12369                             },
12370                             {
12371                                 tag : 'td',
12372                                 cls : 'fc-header-right',
12373                                 cn : [
12374                               /*      fc_button('month', 'left', '', 'month' ),
12375                                     fc_button('week', '', '', 'week' ),
12376                                     fc_button('day', 'right', '', 'day' )
12377                                 */    
12378
12379                                 ]
12380                             }
12381
12382                         ]
12383                     }
12384                 ]
12385             };
12386         }
12387         
12388         header = this.header;
12389         
12390        
12391         var cal_heads = function() {
12392             var ret = [];
12393             // fixme - handle this.
12394             
12395             for (var i =0; i < Date.dayNames.length; i++) {
12396                 var d = Date.dayNames[i];
12397                 ret.push({
12398                     tag: 'th',
12399                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12400                     html : d.substring(0,3)
12401                 });
12402                 
12403             }
12404             ret[0].cls += ' fc-first';
12405             ret[6].cls += ' fc-last';
12406             return ret;
12407         };
12408         var cal_cell = function(n) {
12409             return  {
12410                 tag: 'td',
12411                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12412                 cn : [
12413                     {
12414                         cn : [
12415                             {
12416                                 cls: 'fc-day-number',
12417                                 html: 'D'
12418                             },
12419                             {
12420                                 cls: 'fc-day-content',
12421                              
12422                                 cn : [
12423                                      {
12424                                         style: 'position: relative;' // height: 17px;
12425                                     }
12426                                 ]
12427                             }
12428                             
12429                             
12430                         ]
12431                     }
12432                 ]
12433                 
12434             }
12435         };
12436         var cal_rows = function() {
12437             
12438             var ret = []
12439             for (var r = 0; r < 6; r++) {
12440                 var row= {
12441                     tag : 'tr',
12442                     cls : 'fc-week',
12443                     cn : []
12444                 };
12445                 
12446                 for (var i =0; i < Date.dayNames.length; i++) {
12447                     var d = Date.dayNames[i];
12448                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12449
12450                 }
12451                 row.cn[0].cls+=' fc-first';
12452                 row.cn[0].cn[0].style = 'min-height:90px';
12453                 row.cn[6].cls+=' fc-last';
12454                 ret.push(row);
12455                 
12456             }
12457             ret[0].cls += ' fc-first';
12458             ret[4].cls += ' fc-prev-last';
12459             ret[5].cls += ' fc-last';
12460             return ret;
12461             
12462         };
12463         
12464         var cal_table = {
12465             tag: 'table',
12466             cls: 'fc-border-separate',
12467             style : 'width:100%',
12468             cellspacing  : 0,
12469             cn : [
12470                 { 
12471                     tag: 'thead',
12472                     cn : [
12473                         { 
12474                             tag: 'tr',
12475                             cls : 'fc-first fc-last',
12476                             cn : cal_heads()
12477                         }
12478                     ]
12479                 },
12480                 { 
12481                     tag: 'tbody',
12482                     cn : cal_rows()
12483                 }
12484                   
12485             ]
12486         };
12487          
12488          var cfg = {
12489             cls : 'fc fc-ltr',
12490             cn : [
12491                 header,
12492                 {
12493                     cls : 'fc-content',
12494                     style : "position: relative;",
12495                     cn : [
12496                         {
12497                             cls : 'fc-view fc-view-month fc-grid',
12498                             style : 'position: relative',
12499                             unselectable : 'on',
12500                             cn : [
12501                                 {
12502                                     cls : 'fc-event-container',
12503                                     style : 'position:absolute;z-index:8;top:0;left:0;'
12504                                 },
12505                                 cal_table
12506                             ]
12507                         }
12508                     ]
12509     
12510                 }
12511            ] 
12512             
12513         };
12514         
12515          
12516         
12517         return cfg;
12518     },
12519     
12520     
12521     initEvents : function()
12522     {
12523         if(!this.store){
12524             throw "can not find store for calendar";
12525         }
12526         
12527         var mark = {
12528             tag: "div",
12529             cls:"x-dlg-mask",
12530             style: "text-align:center",
12531             cn: [
12532                 {
12533                     tag: "div",
12534                     style: "background-color:white;width:50%;margin:250 auto",
12535                     cn: [
12536                         {
12537                             tag: "img",
12538                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
12539                         },
12540                         {
12541                             tag: "span",
12542                             html: "Loading"
12543                         }
12544                         
12545                     ]
12546                 }
12547             ]
12548         }
12549         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12550         
12551         var size = this.el.select('.fc-content', true).first().getSize();
12552         this.maskEl.setSize(size.width, size.height);
12553         this.maskEl.enableDisplayMode("block");
12554         if(!this.loadMask){
12555             this.maskEl.hide();
12556         }
12557         
12558         this.store = Roo.factory(this.store, Roo.data);
12559         this.store.on('load', this.onLoad, this);
12560         this.store.on('beforeload', this.onBeforeLoad, this);
12561         
12562         this.resize();
12563         
12564         this.cells = this.el.select('.fc-day',true);
12565         //Roo.log(this.cells);
12566         this.textNodes = this.el.query('.fc-day-number');
12567         this.cells.addClassOnOver('fc-state-hover');
12568         
12569         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12570         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12571         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12572         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12573         
12574         this.on('monthchange', this.onMonthChange, this);
12575         
12576         this.update(new Date().clearTime());
12577     },
12578     
12579     resize : function() {
12580         var sz  = this.el.getSize();
12581         
12582         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12583         this.el.select('.fc-day-content div',true).setHeight(34);
12584     },
12585     
12586     
12587     // private
12588     showPrevMonth : function(e){
12589         this.update(this.activeDate.add("mo", -1));
12590     },
12591     showToday : function(e){
12592         this.update(new Date().clearTime());
12593     },
12594     // private
12595     showNextMonth : function(e){
12596         this.update(this.activeDate.add("mo", 1));
12597     },
12598
12599     // private
12600     showPrevYear : function(){
12601         this.update(this.activeDate.add("y", -1));
12602     },
12603
12604     // private
12605     showNextYear : function(){
12606         this.update(this.activeDate.add("y", 1));
12607     },
12608
12609     
12610    // private
12611     update : function(date)
12612     {
12613         var vd = this.activeDate;
12614         this.activeDate = date;
12615 //        if(vd && this.el){
12616 //            var t = date.getTime();
12617 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12618 //                Roo.log('using add remove');
12619 //                
12620 //                this.fireEvent('monthchange', this, date);
12621 //                
12622 //                this.cells.removeClass("fc-state-highlight");
12623 //                this.cells.each(function(c){
12624 //                   if(c.dateValue == t){
12625 //                       c.addClass("fc-state-highlight");
12626 //                       setTimeout(function(){
12627 //                            try{c.dom.firstChild.focus();}catch(e){}
12628 //                       }, 50);
12629 //                       return false;
12630 //                   }
12631 //                   return true;
12632 //                });
12633 //                return;
12634 //            }
12635 //        }
12636         
12637         var days = date.getDaysInMonth();
12638         
12639         var firstOfMonth = date.getFirstDateOfMonth();
12640         var startingPos = firstOfMonth.getDay()-this.startDay;
12641         
12642         if(startingPos < this.startDay){
12643             startingPos += 7;
12644         }
12645         
12646         var pm = date.add(Date.MONTH, -1);
12647         var prevStart = pm.getDaysInMonth()-startingPos;
12648 //        
12649         this.cells = this.el.select('.fc-day',true);
12650         this.textNodes = this.el.query('.fc-day-number');
12651         this.cells.addClassOnOver('fc-state-hover');
12652         
12653         var cells = this.cells.elements;
12654         var textEls = this.textNodes;
12655         
12656         Roo.each(cells, function(cell){
12657             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12658         });
12659         
12660         days += startingPos;
12661
12662         // convert everything to numbers so it's fast
12663         var day = 86400000;
12664         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12665         //Roo.log(d);
12666         //Roo.log(pm);
12667         //Roo.log(prevStart);
12668         
12669         var today = new Date().clearTime().getTime();
12670         var sel = date.clearTime().getTime();
12671         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12672         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12673         var ddMatch = this.disabledDatesRE;
12674         var ddText = this.disabledDatesText;
12675         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12676         var ddaysText = this.disabledDaysText;
12677         var format = this.format;
12678         
12679         var setCellClass = function(cal, cell){
12680             cell.row = 0;
12681             cell.events = [];
12682             cell.more = [];
12683             //Roo.log('set Cell Class');
12684             cell.title = "";
12685             var t = d.getTime();
12686             
12687             //Roo.log(d);
12688             
12689             cell.dateValue = t;
12690             if(t == today){
12691                 cell.className += " fc-today";
12692                 cell.className += " fc-state-highlight";
12693                 cell.title = cal.todayText;
12694             }
12695             if(t == sel){
12696                 // disable highlight in other month..
12697                 //cell.className += " fc-state-highlight";
12698                 
12699             }
12700             // disabling
12701             if(t < min) {
12702                 cell.className = " fc-state-disabled";
12703                 cell.title = cal.minText;
12704                 return;
12705             }
12706             if(t > max) {
12707                 cell.className = " fc-state-disabled";
12708                 cell.title = cal.maxText;
12709                 return;
12710             }
12711             if(ddays){
12712                 if(ddays.indexOf(d.getDay()) != -1){
12713                     cell.title = ddaysText;
12714                     cell.className = " fc-state-disabled";
12715                 }
12716             }
12717             if(ddMatch && format){
12718                 var fvalue = d.dateFormat(format);
12719                 if(ddMatch.test(fvalue)){
12720                     cell.title = ddText.replace("%0", fvalue);
12721                     cell.className = " fc-state-disabled";
12722                 }
12723             }
12724             
12725             if (!cell.initialClassName) {
12726                 cell.initialClassName = cell.dom.className;
12727             }
12728             
12729             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
12730         };
12731
12732         var i = 0;
12733         
12734         for(; i < startingPos; i++) {
12735             textEls[i].innerHTML = (++prevStart);
12736             d.setDate(d.getDate()+1);
12737             
12738             cells[i].className = "fc-past fc-other-month";
12739             setCellClass(this, cells[i]);
12740         }
12741         
12742         var intDay = 0;
12743         
12744         for(; i < days; i++){
12745             intDay = i - startingPos + 1;
12746             textEls[i].innerHTML = (intDay);
12747             d.setDate(d.getDate()+1);
12748             
12749             cells[i].className = ''; // "x-date-active";
12750             setCellClass(this, cells[i]);
12751         }
12752         var extraDays = 0;
12753         
12754         for(; i < 42; i++) {
12755             textEls[i].innerHTML = (++extraDays);
12756             d.setDate(d.getDate()+1);
12757             
12758             cells[i].className = "fc-future fc-other-month";
12759             setCellClass(this, cells[i]);
12760         }
12761         
12762         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12763         
12764         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12765         
12766         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12767         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12768         
12769         if(totalRows != 6){
12770             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12771             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12772         }
12773         
12774         this.fireEvent('monthchange', this, date);
12775         
12776         
12777         /*
12778         if(!this.internalRender){
12779             var main = this.el.dom.firstChild;
12780             var w = main.offsetWidth;
12781             this.el.setWidth(w + this.el.getBorderWidth("lr"));
12782             Roo.fly(main).setWidth(w);
12783             this.internalRender = true;
12784             // opera does not respect the auto grow header center column
12785             // then, after it gets a width opera refuses to recalculate
12786             // without a second pass
12787             if(Roo.isOpera && !this.secondPass){
12788                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12789                 this.secondPass = true;
12790                 this.update.defer(10, this, [date]);
12791             }
12792         }
12793         */
12794         
12795     },
12796     
12797     findCell : function(dt) {
12798         dt = dt.clearTime().getTime();
12799         var ret = false;
12800         this.cells.each(function(c){
12801             //Roo.log("check " +c.dateValue + '?=' + dt);
12802             if(c.dateValue == dt){
12803                 ret = c;
12804                 return false;
12805             }
12806             return true;
12807         });
12808         
12809         return ret;
12810     },
12811     
12812     findCells : function(ev) {
12813         var s = ev.start.clone().clearTime().getTime();
12814        // Roo.log(s);
12815         var e= ev.end.clone().clearTime().getTime();
12816        // Roo.log(e);
12817         var ret = [];
12818         this.cells.each(function(c){
12819              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12820             
12821             if(c.dateValue > e){
12822                 return ;
12823             }
12824             if(c.dateValue < s){
12825                 return ;
12826             }
12827             ret.push(c);
12828         });
12829         
12830         return ret;    
12831     },
12832     
12833 //    findBestRow: function(cells)
12834 //    {
12835 //        var ret = 0;
12836 //        
12837 //        for (var i =0 ; i < cells.length;i++) {
12838 //            ret  = Math.max(cells[i].rows || 0,ret);
12839 //        }
12840 //        return ret;
12841 //        
12842 //    },
12843     
12844     
12845     addItem : function(ev)
12846     {
12847         // look for vertical location slot in
12848         var cells = this.findCells(ev);
12849         
12850 //        ev.row = this.findBestRow(cells);
12851         
12852         // work out the location.
12853         
12854         var crow = false;
12855         var rows = [];
12856         for(var i =0; i < cells.length; i++) {
12857             
12858             cells[i].row = cells[0].row;
12859             
12860             if(i == 0){
12861                 cells[i].row = cells[i].row + 1;
12862             }
12863             
12864             if (!crow) {
12865                 crow = {
12866                     start : cells[i],
12867                     end :  cells[i]
12868                 };
12869                 continue;
12870             }
12871             if (crow.start.getY() == cells[i].getY()) {
12872                 // on same row.
12873                 crow.end = cells[i];
12874                 continue;
12875             }
12876             // different row.
12877             rows.push(crow);
12878             crow = {
12879                 start: cells[i],
12880                 end : cells[i]
12881             };
12882             
12883         }
12884         
12885         rows.push(crow);
12886         ev.els = [];
12887         ev.rows = rows;
12888         ev.cells = cells;
12889         
12890         cells[0].events.push(ev);
12891         
12892         this.calevents.push(ev);
12893     },
12894     
12895     clearEvents: function() {
12896         
12897         if(!this.calevents){
12898             return;
12899         }
12900         
12901         Roo.each(this.cells.elements, function(c){
12902             c.row = 0;
12903             c.events = [];
12904             c.more = [];
12905         });
12906         
12907         Roo.each(this.calevents, function(e) {
12908             Roo.each(e.els, function(el) {
12909                 el.un('mouseenter' ,this.onEventEnter, this);
12910                 el.un('mouseleave' ,this.onEventLeave, this);
12911                 el.remove();
12912             },this);
12913         },this);
12914         
12915         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12916             e.remove();
12917         });
12918         
12919     },
12920     
12921     renderEvents: function()
12922     {   
12923         var _this = this;
12924         
12925         this.cells.each(function(c) {
12926             
12927             if(c.row < 5){
12928                 return;
12929             }
12930             
12931             var ev = c.events;
12932             
12933             var r = 4;
12934             if(c.row != c.events.length){
12935                 r = 4 - (4 - (c.row - c.events.length));
12936             }
12937             
12938             c.events = ev.slice(0, r);
12939             c.more = ev.slice(r);
12940             
12941             if(c.more.length && c.more.length == 1){
12942                 c.events.push(c.more.pop());
12943             }
12944             
12945             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12946             
12947         });
12948             
12949         this.cells.each(function(c) {
12950             
12951             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12952             
12953             
12954             for (var e = 0; e < c.events.length; e++){
12955                 var ev = c.events[e];
12956                 var rows = ev.rows;
12957                 
12958                 for(var i = 0; i < rows.length; i++) {
12959                 
12960                     // how many rows should it span..
12961
12962                     var  cfg = {
12963                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12964                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12965
12966                         unselectable : "on",
12967                         cn : [
12968                             {
12969                                 cls: 'fc-event-inner',
12970                                 cn : [
12971     //                                {
12972     //                                  tag:'span',
12973     //                                  cls: 'fc-event-time',
12974     //                                  html : cells.length > 1 ? '' : ev.time
12975     //                                },
12976                                     {
12977                                       tag:'span',
12978                                       cls: 'fc-event-title',
12979                                       html : String.format('{0}', ev.title)
12980                                     }
12981
12982
12983                                 ]
12984                             },
12985                             {
12986                                 cls: 'ui-resizable-handle ui-resizable-e',
12987                                 html : '&nbsp;&nbsp;&nbsp'
12988                             }
12989
12990                         ]
12991                     };
12992
12993                     if (i == 0) {
12994                         cfg.cls += ' fc-event-start';
12995                     }
12996                     if ((i+1) == rows.length) {
12997                         cfg.cls += ' fc-event-end';
12998                     }
12999
13000                     var ctr = _this.el.select('.fc-event-container',true).first();
13001                     var cg = ctr.createChild(cfg);
13002
13003                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13004                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13005
13006                     var r = (c.more.length) ? 1 : 0;
13007                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13008                     cg.setWidth(ebox.right - sbox.x -2);
13009
13010                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13011                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13012                     cg.on('click', _this.onEventClick, _this, ev);
13013
13014                     ev.els.push(cg);
13015                     
13016                 }
13017                 
13018             }
13019             
13020             
13021             if(c.more.length){
13022                 var  cfg = {
13023                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13024                     style : 'position: absolute',
13025                     unselectable : "on",
13026                     cn : [
13027                         {
13028                             cls: 'fc-event-inner',
13029                             cn : [
13030                                 {
13031                                   tag:'span',
13032                                   cls: 'fc-event-title',
13033                                   html : 'More'
13034                                 }
13035
13036
13037                             ]
13038                         },
13039                         {
13040                             cls: 'ui-resizable-handle ui-resizable-e',
13041                             html : '&nbsp;&nbsp;&nbsp'
13042                         }
13043
13044                     ]
13045                 };
13046
13047                 var ctr = _this.el.select('.fc-event-container',true).first();
13048                 var cg = ctr.createChild(cfg);
13049
13050                 var sbox = c.select('.fc-day-content',true).first().getBox();
13051                 var ebox = c.select('.fc-day-content',true).first().getBox();
13052                 //Roo.log(cg);
13053                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13054                 cg.setWidth(ebox.right - sbox.x -2);
13055
13056                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13057                 
13058             }
13059             
13060         });
13061         
13062         
13063         
13064     },
13065     
13066     onEventEnter: function (e, el,event,d) {
13067         this.fireEvent('evententer', this, el, event);
13068     },
13069     
13070     onEventLeave: function (e, el,event,d) {
13071         this.fireEvent('eventleave', this, el, event);
13072     },
13073     
13074     onEventClick: function (e, el,event,d) {
13075         this.fireEvent('eventclick', this, el, event);
13076     },
13077     
13078     onMonthChange: function () {
13079         this.store.load();
13080     },
13081     
13082     onMoreEventClick: function(e, el, more)
13083     {
13084         var _this = this;
13085         
13086         this.calpopover.placement = 'right';
13087         this.calpopover.setTitle('More');
13088         
13089         this.calpopover.setContent('');
13090         
13091         var ctr = this.calpopover.el.select('.popover-content', true).first();
13092         
13093         Roo.each(more, function(m){
13094             var cfg = {
13095                 cls : 'fc-event-hori fc-event-draggable',
13096                 html : m.title
13097             }
13098             var cg = ctr.createChild(cfg);
13099             
13100             cg.on('click', _this.onEventClick, _this, m);
13101         });
13102         
13103         this.calpopover.show(el);
13104         
13105         
13106     },
13107     
13108     onLoad: function () 
13109     {   
13110         this.calevents = [];
13111         var cal = this;
13112         
13113         if(this.store.getCount() > 0){
13114             this.store.data.each(function(d){
13115                cal.addItem({
13116                     id : d.data.id,
13117                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13118                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13119                     time : d.data.start_time,
13120                     title : d.data.title,
13121                     description : d.data.description,
13122                     venue : d.data.venue
13123                 });
13124             });
13125         }
13126         
13127         this.renderEvents();
13128         
13129         if(this.calevents.length && this.loadMask){
13130             this.maskEl.hide();
13131         }
13132     },
13133     
13134     onBeforeLoad: function()
13135     {
13136         this.clearEvents();
13137         if(this.loadMask){
13138             this.maskEl.show();
13139         }
13140     }
13141 });
13142
13143  
13144  /*
13145  * - LGPL
13146  *
13147  * element
13148  * 
13149  */
13150
13151 /**
13152  * @class Roo.bootstrap.Popover
13153  * @extends Roo.bootstrap.Component
13154  * Bootstrap Popover class
13155  * @cfg {String} html contents of the popover   (or false to use children..)
13156  * @cfg {String} title of popover (or false to hide)
13157  * @cfg {String} placement how it is placed
13158  * @cfg {String} trigger click || hover (or false to trigger manually)
13159  * @cfg {String} over what (parent or false to trigger manually.)
13160  * 
13161  * @constructor
13162  * Create a new Popover
13163  * @param {Object} config The config object
13164  */
13165
13166 Roo.bootstrap.Popover = function(config){
13167     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13168 };
13169
13170 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13171     
13172     title: 'Fill in a title',
13173     html: false,
13174     
13175     placement : 'right',
13176     trigger : 'hover', // hover
13177     
13178     over: 'parent',
13179     
13180     can_build_overlaid : false,
13181     
13182     getChildContainer : function()
13183     {
13184         return this.el.select('.popover-content',true).first();
13185     },
13186     
13187     getAutoCreate : function(){
13188          Roo.log('make popover?');
13189         var cfg = {
13190            cls : 'popover roo-dynamic',
13191            style: 'display:block',
13192            cn : [
13193                 {
13194                     cls : 'arrow'
13195                 },
13196                 {
13197                     cls : 'popover-inner',
13198                     cn : [
13199                         {
13200                             tag: 'h3',
13201                             cls: 'popover-title',
13202                             html : this.title
13203                         },
13204                         {
13205                             cls : 'popover-content',
13206                             html : this.html
13207                         }
13208                     ]
13209                     
13210                 }
13211            ]
13212         };
13213         
13214         return cfg;
13215     },
13216     setTitle: function(str)
13217     {
13218         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13219     },
13220     setContent: function(str)
13221     {
13222         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13223     },
13224     // as it get's added to the bottom of the page.
13225     onRender : function(ct, position)
13226     {
13227         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13228         if(!this.el){
13229             var cfg = Roo.apply({},  this.getAutoCreate());
13230             cfg.id = Roo.id();
13231             
13232             if (this.cls) {
13233                 cfg.cls += ' ' + this.cls;
13234             }
13235             if (this.style) {
13236                 cfg.style = this.style;
13237             }
13238             Roo.log("adding to ")
13239             this.el = Roo.get(document.body).createChild(cfg, position);
13240             Roo.log(this.el);
13241         }
13242         this.initEvents();
13243     },
13244     
13245     initEvents : function()
13246     {
13247         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13248         this.el.enableDisplayMode('block');
13249         this.el.hide();
13250         if (this.over === false) {
13251             return; 
13252         }
13253         if (this.triggers === false) {
13254             return;
13255         }
13256         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13257         var triggers = this.trigger ? this.trigger.split(' ') : [];
13258         Roo.each(triggers, function(trigger) {
13259         
13260             if (trigger == 'click') {
13261                 on_el.on('click', this.toggle, this);
13262             } else if (trigger != 'manual') {
13263                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
13264                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13265       
13266                 on_el.on(eventIn  ,this.enter, this);
13267                 on_el.on(eventOut, this.leave, this);
13268             }
13269         }, this);
13270         
13271     },
13272     
13273     
13274     // private
13275     timeout : null,
13276     hoverState : null,
13277     
13278     toggle : function () {
13279         this.hoverState == 'in' ? this.leave() : this.enter();
13280     },
13281     
13282     enter : function () {
13283        
13284     
13285         clearTimeout(this.timeout);
13286     
13287         this.hoverState = 'in'
13288     
13289         if (!this.delay || !this.delay.show) {
13290             this.show();
13291             return 
13292         }
13293         var _t = this;
13294         this.timeout = setTimeout(function () {
13295             if (_t.hoverState == 'in') {
13296                 _t.show();
13297             }
13298         }, this.delay.show)
13299     },
13300     leave : function() {
13301         clearTimeout(this.timeout);
13302     
13303         this.hoverState = 'out'
13304     
13305         if (!this.delay || !this.delay.hide) {
13306             this.hide();
13307             return 
13308         }
13309         var _t = this;
13310         this.timeout = setTimeout(function () {
13311             if (_t.hoverState == 'out') {
13312                 _t.hide();
13313             }
13314         }, this.delay.hide)
13315     },
13316     
13317     show : function (on_el)
13318     {
13319         if (!on_el) {
13320             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13321         }
13322         // set content.
13323         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13324         if (this.html !== false) {
13325             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13326         }
13327         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13328         if (!this.title.length) {
13329             this.el.select('.popover-title',true).hide();
13330         }
13331         
13332         var placement = typeof this.placement == 'function' ?
13333             this.placement.call(this, this.el, on_el) :
13334             this.placement;
13335             
13336         var autoToken = /\s?auto?\s?/i;
13337         var autoPlace = autoToken.test(placement);
13338         if (autoPlace) {
13339             placement = placement.replace(autoToken, '') || 'top';
13340         }
13341         
13342         //this.el.detach()
13343         //this.el.setXY([0,0]);
13344         this.el.show();
13345         this.el.dom.style.display='block';
13346         this.el.addClass(placement);
13347         
13348         //this.el.appendTo(on_el);
13349         
13350         var p = this.getPosition();
13351         var box = this.el.getBox();
13352         
13353         if (autoPlace) {
13354             // fixme..
13355         }
13356         var align = Roo.bootstrap.Popover.alignment[placement]
13357         this.el.alignTo(on_el, align[0],align[1]);
13358         //var arrow = this.el.select('.arrow',true).first();
13359         //arrow.set(align[2], 
13360         
13361         this.el.addClass('in');
13362         this.hoverState = null;
13363         
13364         if (this.el.hasClass('fade')) {
13365             // fade it?
13366         }
13367         
13368     },
13369     hide : function()
13370     {
13371         this.el.setXY([0,0]);
13372         this.el.removeClass('in');
13373         this.el.hide();
13374         
13375     }
13376     
13377 });
13378
13379 Roo.bootstrap.Popover.alignment = {
13380     'left' : ['r-l', [-10,0], 'right'],
13381     'right' : ['l-r', [10,0], 'left'],
13382     'bottom' : ['t-b', [0,10], 'top'],
13383     'top' : [ 'b-t', [0,-10], 'bottom']
13384 };
13385
13386  /*
13387  * - LGPL
13388  *
13389  * Progress
13390  * 
13391  */
13392
13393 /**
13394  * @class Roo.bootstrap.Progress
13395  * @extends Roo.bootstrap.Component
13396  * Bootstrap Progress class
13397  * @cfg {Boolean} striped striped of the progress bar
13398  * @cfg {Boolean} active animated of the progress bar
13399  * 
13400  * 
13401  * @constructor
13402  * Create a new Progress
13403  * @param {Object} config The config object
13404  */
13405
13406 Roo.bootstrap.Progress = function(config){
13407     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13408 };
13409
13410 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
13411     
13412     striped : false,
13413     active: false,
13414     
13415     getAutoCreate : function(){
13416         var cfg = {
13417             tag: 'div',
13418             cls: 'progress'
13419         };
13420         
13421         
13422         if(this.striped){
13423             cfg.cls += ' progress-striped';
13424         }
13425       
13426         if(this.active){
13427             cfg.cls += ' active';
13428         }
13429         
13430         
13431         return cfg;
13432     }
13433    
13434 });
13435
13436  
13437
13438  /*
13439  * - LGPL
13440  *
13441  * ProgressBar
13442  * 
13443  */
13444
13445 /**
13446  * @class Roo.bootstrap.ProgressBar
13447  * @extends Roo.bootstrap.Component
13448  * Bootstrap ProgressBar class
13449  * @cfg {Number} aria_valuenow aria-value now
13450  * @cfg {Number} aria_valuemin aria-value min
13451  * @cfg {Number} aria_valuemax aria-value max
13452  * @cfg {String} label label for the progress bar
13453  * @cfg {String} panel (success | info | warning | danger )
13454  * @cfg {String} role role of the progress bar
13455  * @cfg {String} sr_only text
13456  * 
13457  * 
13458  * @constructor
13459  * Create a new ProgressBar
13460  * @param {Object} config The config object
13461  */
13462
13463 Roo.bootstrap.ProgressBar = function(config){
13464     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13465 };
13466
13467 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
13468     
13469     aria_valuenow : 0,
13470     aria_valuemin : 0,
13471     aria_valuemax : 100,
13472     label : false,
13473     panel : false,
13474     role : false,
13475     sr_only: false,
13476     
13477     getAutoCreate : function()
13478     {
13479         
13480         var cfg = {
13481             tag: 'div',
13482             cls: 'progress-bar',
13483             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13484         };
13485         
13486         if(this.sr_only){
13487             cfg.cn = {
13488                 tag: 'span',
13489                 cls: 'sr-only',
13490                 html: this.sr_only
13491             }
13492         }
13493         
13494         if(this.role){
13495             cfg.role = this.role;
13496         }
13497         
13498         if(this.aria_valuenow){
13499             cfg['aria-valuenow'] = this.aria_valuenow;
13500         }
13501         
13502         if(this.aria_valuemin){
13503             cfg['aria-valuemin'] = this.aria_valuemin;
13504         }
13505         
13506         if(this.aria_valuemax){
13507             cfg['aria-valuemax'] = this.aria_valuemax;
13508         }
13509         
13510         if(this.label && !this.sr_only){
13511             cfg.html = this.label;
13512         }
13513         
13514         if(this.panel){
13515             cfg.cls += ' progress-bar-' + this.panel;
13516         }
13517         
13518         return cfg;
13519     },
13520     
13521     update : function(aria_valuenow)
13522     {
13523         this.aria_valuenow = aria_valuenow;
13524         
13525         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13526     }
13527    
13528 });
13529
13530  
13531
13532  /*
13533  * - LGPL
13534  *
13535  * TabPanel
13536  * 
13537  */
13538
13539 /**
13540  * @class Roo.bootstrap.TabPanel
13541  * @extends Roo.bootstrap.Component
13542  * Bootstrap TabPanel class
13543  * @cfg {Boolean} active panel active
13544  * @cfg {String} html panel content
13545  * @cfg {String} tabId tab relate id
13546  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13547  * 
13548  * 
13549  * @constructor
13550  * Create a new TabPanel
13551  * @param {Object} config The config object
13552  */
13553
13554 Roo.bootstrap.TabPanel = function(config){
13555     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13556      this.addEvents({
13557         /**
13558              * @event changed
13559              * Fires when the active status changes
13560              * @param {Roo.bootstrap.TabPanel} this
13561              * @param {Boolean} state the new state
13562             
13563          */
13564         'changed': true
13565      });
13566 };
13567
13568 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
13569     
13570     active: false,
13571     html: false,
13572     tabId: false,
13573     navId : false,
13574     
13575     getAutoCreate : function(){
13576         var cfg = {
13577             tag: 'div',
13578             cls: 'tab-pane',
13579             html: this.html || ''
13580         };
13581         
13582         if(this.active){
13583             cfg.cls += ' active';
13584         }
13585         
13586         if(this.tabId){
13587             cfg.tabId = this.tabId;
13588         }
13589         
13590         return cfg;
13591     },
13592     onRender : function(ct, position)
13593     {
13594        // Roo.log("Call onRender: " + this.xtype);
13595         
13596         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13597         
13598         if (this.navId && this.tabId) {
13599             var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13600             if (!item) {
13601                 Roo.log("could not find navID:"  + this.navId + ", tabId: " + this.tabId);
13602             } else {
13603                 item.on('changed', function(item, state) {
13604                     this.setActive(state);
13605                 }, this);
13606             }
13607         }
13608         
13609     },
13610     setActive: function(state)
13611     {
13612         Roo.log("panel - set active " + this.tabId + "=" + state);
13613         
13614         this.active = state;
13615         if (!state) {
13616             this.el.removeClass('active');
13617             
13618         } else  if (!this.el.hasClass('active')) {
13619             this.el.addClass('active');
13620         }
13621         this.fireEvent('changed', this, state);
13622     }
13623     
13624     
13625 });
13626  
13627
13628  
13629
13630  /*
13631  * - LGPL
13632  *
13633  * DateField
13634  * 
13635  */
13636
13637 /**
13638  * @class Roo.bootstrap.DateField
13639  * @extends Roo.bootstrap.Input
13640  * Bootstrap DateField class
13641  * @cfg {Number} weekStart default 0
13642  * @cfg {Number} weekStart default 0
13643  * @cfg {Number} viewMode default empty, (months|years)
13644  * @cfg {Number} minViewMode default empty, (months|years)
13645  * @cfg {Number} startDate default -Infinity
13646  * @cfg {Number} endDate default Infinity
13647  * @cfg {Boolean} todayHighlight default false
13648  * @cfg {Boolean} todayBtn default false
13649  * @cfg {Boolean} calendarWeeks default false
13650  * @cfg {Object} daysOfWeekDisabled default empty
13651  * 
13652  * @cfg {Boolean} keyboardNavigation default true
13653  * @cfg {String} language default en
13654  * 
13655  * @constructor
13656  * Create a new DateField
13657  * @param {Object} config The config object
13658  */
13659
13660 Roo.bootstrap.DateField = function(config){
13661     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13662      this.addEvents({
13663             /**
13664              * @event show
13665              * Fires when this field show.
13666              * @param {Roo.bootstrap.DateField} this
13667              * @param {Mixed} date The date value
13668              */
13669             show : true,
13670             /**
13671              * @event show
13672              * Fires when this field hide.
13673              * @param {Roo.bootstrap.DateField} this
13674              * @param {Mixed} date The date value
13675              */
13676             hide : true,
13677             /**
13678              * @event select
13679              * Fires when select a date.
13680              * @param {Roo.bootstrap.DateField} this
13681              * @param {Mixed} date The date value
13682              */
13683             select : true
13684         });
13685 };
13686
13687 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
13688     
13689     /**
13690      * @cfg {String} format
13691      * The default date format string which can be overriden for localization support.  The format must be
13692      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13693      */
13694     format : "m/d/y",
13695     /**
13696      * @cfg {String} altFormats
13697      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13698      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13699      */
13700     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13701     
13702     weekStart : 0,
13703     
13704     viewMode : '',
13705     
13706     minViewMode : '',
13707     
13708     todayHighlight : false,
13709     
13710     todayBtn: false,
13711     
13712     language: 'en',
13713     
13714     keyboardNavigation: true,
13715     
13716     calendarWeeks: false,
13717     
13718     startDate: -Infinity,
13719     
13720     endDate: Infinity,
13721     
13722     daysOfWeekDisabled: [],
13723     
13724     _events: [],
13725     
13726     UTCDate: function()
13727     {
13728         return new Date(Date.UTC.apply(Date, arguments));
13729     },
13730     
13731     UTCToday: function()
13732     {
13733         var today = new Date();
13734         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13735     },
13736     
13737     getDate: function() {
13738             var d = this.getUTCDate();
13739             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13740     },
13741     
13742     getUTCDate: function() {
13743             return this.date;
13744     },
13745     
13746     setDate: function(d) {
13747             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13748     },
13749     
13750     setUTCDate: function(d) {
13751             this.date = d;
13752             this.setValue(this.formatDate(this.date));
13753     },
13754         
13755     onRender: function(ct, position)
13756     {
13757         
13758         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13759         
13760         this.language = this.language || 'en';
13761         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13762         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13763         
13764         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13765         this.format = this.format || 'm/d/y';
13766         this.isInline = false;
13767         this.isInput = true;
13768         this.component = this.el.select('.add-on', true).first() || false;
13769         this.component = (this.component && this.component.length === 0) ? false : this.component;
13770         this.hasInput = this.component && this.inputEL().length;
13771         
13772         if (typeof(this.minViewMode === 'string')) {
13773             switch (this.minViewMode) {
13774                 case 'months':
13775                     this.minViewMode = 1;
13776                     break;
13777                 case 'years':
13778                     this.minViewMode = 2;
13779                     break;
13780                 default:
13781                     this.minViewMode = 0;
13782                     break;
13783             }
13784         }
13785         
13786         if (typeof(this.viewMode === 'string')) {
13787             switch (this.viewMode) {
13788                 case 'months':
13789                     this.viewMode = 1;
13790                     break;
13791                 case 'years':
13792                     this.viewMode = 2;
13793                     break;
13794                 default:
13795                     this.viewMode = 0;
13796                     break;
13797             }
13798         }
13799                 
13800         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13801         
13802         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13803         
13804         this.picker().on('mousedown', this.onMousedown, this);
13805         this.picker().on('click', this.onClick, this);
13806         
13807         this.picker().addClass('datepicker-dropdown');
13808         
13809         this.startViewMode = this.viewMode;
13810         
13811         
13812         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13813             if(!this.calendarWeeks){
13814                 v.remove();
13815                 return;
13816             };
13817             
13818             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13819             v.attr('colspan', function(i, val){
13820                 return parseInt(val) + 1;
13821             });
13822         })
13823                         
13824         
13825         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13826         
13827         this.setStartDate(this.startDate);
13828         this.setEndDate(this.endDate);
13829         
13830         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13831         
13832         this.fillDow();
13833         this.fillMonths();
13834         this.update();
13835         this.showMode();
13836         
13837         if(this.isInline) {
13838             this.show();
13839         }
13840     },
13841     
13842     picker : function()
13843     {
13844         return this.el.select('.datepicker', true).first();
13845     },
13846     
13847     fillDow: function()
13848     {
13849         var dowCnt = this.weekStart;
13850         
13851         var dow = {
13852             tag: 'tr',
13853             cn: [
13854                 
13855             ]
13856         };
13857         
13858         if(this.calendarWeeks){
13859             dow.cn.push({
13860                 tag: 'th',
13861                 cls: 'cw',
13862                 html: '&nbsp;'
13863             })
13864         }
13865         
13866         while (dowCnt < this.weekStart + 7) {
13867             dow.cn.push({
13868                 tag: 'th',
13869                 cls: 'dow',
13870                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13871             });
13872         }
13873         
13874         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13875     },
13876     
13877     fillMonths: function()
13878     {    
13879         var i = 0
13880         var months = this.picker().select('>.datepicker-months td', true).first();
13881         
13882         months.dom.innerHTML = '';
13883         
13884         while (i < 12) {
13885             var month = {
13886                 tag: 'span',
13887                 cls: 'month',
13888                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13889             }
13890             
13891             months.createChild(month);
13892         }
13893         
13894     },
13895     
13896     update: function()
13897     {
13898         
13899         this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13900         
13901         if (this.date < this.startDate) {
13902             this.viewDate = new Date(this.startDate);
13903         } else if (this.date > this.endDate) {
13904             this.viewDate = new Date(this.endDate);
13905         } else {
13906             this.viewDate = new Date(this.date);
13907         }
13908         
13909         this.fill();
13910     },
13911     
13912     fill: function() 
13913     {
13914         var d = new Date(this.viewDate),
13915                 year = d.getUTCFullYear(),
13916                 month = d.getUTCMonth(),
13917                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13918                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13919                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13920                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13921                 currentDate = this.date && this.date.valueOf(),
13922                 today = this.UTCToday();
13923         
13924         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13925         
13926 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13927         
13928 //        this.picker.select('>tfoot th.today').
13929 //                                              .text(dates[this.language].today)
13930 //                                              .toggle(this.todayBtn !== false);
13931     
13932         this.updateNavArrows();
13933         this.fillMonths();
13934                                                 
13935         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13936         
13937         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13938          
13939         prevMonth.setUTCDate(day);
13940         
13941         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13942         
13943         var nextMonth = new Date(prevMonth);
13944         
13945         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13946         
13947         nextMonth = nextMonth.valueOf();
13948         
13949         var fillMonths = false;
13950         
13951         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13952         
13953         while(prevMonth.valueOf() < nextMonth) {
13954             var clsName = '';
13955             
13956             if (prevMonth.getUTCDay() === this.weekStart) {
13957                 if(fillMonths){
13958                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13959                 }
13960                     
13961                 fillMonths = {
13962                     tag: 'tr',
13963                     cn: []
13964                 };
13965                 
13966                 if(this.calendarWeeks){
13967                     // ISO 8601: First week contains first thursday.
13968                     // ISO also states week starts on Monday, but we can be more abstract here.
13969                     var
13970                     // Start of current week: based on weekstart/current date
13971                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13972                     // Thursday of this week
13973                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13974                     // First Thursday of year, year from thursday
13975                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13976                     // Calendar week: ms between thursdays, div ms per day, div 7 days
13977                     calWeek =  (th - yth) / 864e5 / 7 + 1;
13978                     
13979                     fillMonths.cn.push({
13980                         tag: 'td',
13981                         cls: 'cw',
13982                         html: calWeek
13983                     });
13984                 }
13985             }
13986             
13987             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13988                 clsName += ' old';
13989             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13990                 clsName += ' new';
13991             }
13992             if (this.todayHighlight &&
13993                 prevMonth.getUTCFullYear() == today.getFullYear() &&
13994                 prevMonth.getUTCMonth() == today.getMonth() &&
13995                 prevMonth.getUTCDate() == today.getDate()) {
13996                 clsName += ' today';
13997             }
13998             
13999             if (currentDate && prevMonth.valueOf() === currentDate) {
14000                 clsName += ' active';
14001             }
14002             
14003             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14004                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14005                     clsName += ' disabled';
14006             }
14007             
14008             fillMonths.cn.push({
14009                 tag: 'td',
14010                 cls: 'day ' + clsName,
14011                 html: prevMonth.getDate()
14012             })
14013             
14014             prevMonth.setDate(prevMonth.getDate()+1);
14015         }
14016           
14017         var currentYear = this.date && this.date.getUTCFullYear();
14018         var currentMonth = this.date && this.date.getUTCMonth();
14019         
14020         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14021         
14022         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14023             v.removeClass('active');
14024             
14025             if(currentYear === year && k === currentMonth){
14026                 v.addClass('active');
14027             }
14028             
14029             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14030                 v.addClass('disabled');
14031             }
14032             
14033         });
14034         
14035         
14036         year = parseInt(year/10, 10) * 10;
14037         
14038         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14039         
14040         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14041         
14042         year -= 1;
14043         for (var i = -1; i < 11; i++) {
14044             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14045                 tag: 'span',
14046                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14047                 html: year
14048             })
14049             
14050             year += 1;
14051         }
14052     },
14053     
14054     showMode: function(dir) 
14055     {
14056         if (dir) {
14057             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14058         }
14059         Roo.each(this.picker().select('>div',true).elements, function(v){
14060             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14061             v.hide();
14062         });
14063         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14064     },
14065     
14066     place: function()
14067     {
14068         if(this.isInline) return;
14069         
14070         this.picker().removeClass(['bottom', 'top']);
14071         
14072         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14073             /*
14074              * place to the top of element!
14075              *
14076              */
14077             
14078             this.picker().addClass('top');
14079             this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14080             
14081             return;
14082         }
14083         
14084         this.picker().addClass('bottom');
14085         
14086         this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14087     },
14088     
14089     parseDate : function(value)
14090     {
14091         if(!value || value instanceof Date){
14092             return value;
14093         }
14094         var v = Date.parseDate(value, this.format);
14095         if (!v && this.useIso) {
14096             v = Date.parseDate(value, 'Y-m-d');
14097         }
14098         if(!v && this.altFormats){
14099             if(!this.altFormatsArray){
14100                 this.altFormatsArray = this.altFormats.split("|");
14101             }
14102             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14103                 v = Date.parseDate(value, this.altFormatsArray[i]);
14104             }
14105         }
14106         return v;
14107     },
14108     
14109     formatDate : function(date, fmt)
14110     {
14111         return (!date || !(date instanceof Date)) ?
14112         date : date.dateFormat(fmt || this.format);
14113     },
14114     
14115     onFocus : function()
14116     {
14117         Roo.bootstrap.DateField.superclass.onFocus.call(this);
14118         this.show();
14119     },
14120     
14121     onBlur : function()
14122     {
14123         Roo.bootstrap.DateField.superclass.onBlur.call(this);
14124         
14125         var d = this.inputEl().getValue();
14126         
14127         if(d && d.length){
14128             this.setValue(d);
14129         }
14130                 
14131         this.hide();
14132     },
14133     
14134     show : function()
14135     {
14136         this.picker().show();
14137         this.update();
14138         this.place();
14139         
14140         this.fireEvent('show', this, this.date);
14141     },
14142     
14143     hide : function()
14144     {
14145         if(this.isInline) return;
14146         this.picker().hide();
14147         this.viewMode = this.startViewMode;
14148         this.showMode();
14149         
14150         this.fireEvent('hide', this, this.date);
14151         
14152     },
14153     
14154     onMousedown: function(e)
14155     {
14156         e.stopPropagation();
14157         e.preventDefault();
14158     },
14159     
14160     keyup: function(e)
14161     {
14162         Roo.bootstrap.DateField.superclass.keyup.call(this);
14163         this.update();
14164     },
14165
14166     setValue: function(v)
14167     {
14168         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14169         
14170         var d = new Date(v);
14171         
14172         if(isNaN(d.getTime())){
14173             return;
14174         }
14175         
14176         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14177
14178         this.update();
14179
14180         this.fireEvent('select', this, this.date);
14181         
14182     },
14183     
14184     getValue: function()
14185     {
14186         return this.formatDate(this.date);
14187     },
14188     
14189     fireKey: function(e)
14190     {
14191         if (!this.picker().isVisible()){
14192             if (e.keyCode == 27) // allow escape to hide and re-show picker
14193                 this.show();
14194             return;
14195         }
14196         var dateChanged = false,
14197         dir, day, month,
14198         newDate, newViewDate;
14199         
14200         switch(e.keyCode){
14201             case 27: // escape
14202                 this.hide();
14203                 e.preventDefault();
14204                 break;
14205             case 37: // left
14206             case 39: // right
14207                 if (!this.keyboardNavigation) break;
14208                 dir = e.keyCode == 37 ? -1 : 1;
14209                 
14210                 if (e.ctrlKey){
14211                     newDate = this.moveYear(this.date, dir);
14212                     newViewDate = this.moveYear(this.viewDate, dir);
14213                 } else if (e.shiftKey){
14214                     newDate = this.moveMonth(this.date, dir);
14215                     newViewDate = this.moveMonth(this.viewDate, dir);
14216                 } else {
14217                     newDate = new Date(this.date);
14218                     newDate.setUTCDate(this.date.getUTCDate() + dir);
14219                     newViewDate = new Date(this.viewDate);
14220                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14221                 }
14222                 if (this.dateWithinRange(newDate)){
14223                     this.date = newDate;
14224                     this.viewDate = newViewDate;
14225                     this.setValue(this.formatDate(this.date));
14226 //                    this.update();
14227                     e.preventDefault();
14228                     dateChanged = true;
14229                 }
14230                 break;
14231             case 38: // up
14232             case 40: // down
14233                 if (!this.keyboardNavigation) break;
14234                 dir = e.keyCode == 38 ? -1 : 1;
14235                 if (e.ctrlKey){
14236                     newDate = this.moveYear(this.date, dir);
14237                     newViewDate = this.moveYear(this.viewDate, dir);
14238                 } else if (e.shiftKey){
14239                     newDate = this.moveMonth(this.date, dir);
14240                     newViewDate = this.moveMonth(this.viewDate, dir);
14241                 } else {
14242                     newDate = new Date(this.date);
14243                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14244                     newViewDate = new Date(this.viewDate);
14245                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14246                 }
14247                 if (this.dateWithinRange(newDate)){
14248                     this.date = newDate;
14249                     this.viewDate = newViewDate;
14250                     this.setValue(this.formatDate(this.date));
14251 //                    this.update();
14252                     e.preventDefault();
14253                     dateChanged = true;
14254                 }
14255                 break;
14256             case 13: // enter
14257                 this.setValue(this.formatDate(this.date));
14258                 this.hide();
14259                 e.preventDefault();
14260                 break;
14261             case 9: // tab
14262                 this.setValue(this.formatDate(this.date));
14263                 this.hide();
14264                 break;
14265                 
14266         }
14267     },
14268     
14269     
14270     onClick: function(e) 
14271     {
14272         e.stopPropagation();
14273         e.preventDefault();
14274         
14275         var target = e.getTarget();
14276         
14277         if(target.nodeName.toLowerCase() === 'i'){
14278             target = Roo.get(target).dom.parentNode;
14279         }
14280         
14281         var nodeName = target.nodeName;
14282         var className = target.className;
14283         var html = target.innerHTML;
14284         
14285         switch(nodeName.toLowerCase()) {
14286             case 'th':
14287                 switch(className) {
14288                     case 'switch':
14289                         this.showMode(1);
14290                         break;
14291                     case 'prev':
14292                     case 'next':
14293                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14294                         switch(this.viewMode){
14295                                 case 0:
14296                                         this.viewDate = this.moveMonth(this.viewDate, dir);
14297                                         break;
14298                                 case 1:
14299                                 case 2:
14300                                         this.viewDate = this.moveYear(this.viewDate, dir);
14301                                         break;
14302                         }
14303                         this.fill();
14304                         break;
14305                     case 'today':
14306                         var date = new Date();
14307                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14308 //                        this.fill()
14309                         this.setValue(this.formatDate(this.date));
14310                         
14311                         this.hide();
14312                         break;
14313                 }
14314                 break;
14315             case 'span':
14316                 if (className.indexOf('disabled') === -1) {
14317                     this.viewDate.setUTCDate(1);
14318                     if (className.indexOf('month') !== -1) {
14319                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14320                     } else {
14321                         var year = parseInt(html, 10) || 0;
14322                         this.viewDate.setUTCFullYear(year);
14323                         
14324                     }
14325                     this.showMode(-1);
14326                     this.fill();
14327                 }
14328                 break;
14329                 
14330             case 'td':
14331                 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14332                     var day = parseInt(html, 10) || 1;
14333                     var year = this.viewDate.getUTCFullYear(),
14334                         month = this.viewDate.getUTCMonth();
14335
14336                     if (className.indexOf('old') !== -1) {
14337                         if(month === 0 ){
14338                             month = 11;
14339                             year -= 1;
14340                         }else{
14341                             month -= 1;
14342                         }
14343                     } else if (className.indexOf('new') !== -1) {
14344                         if (month == 11) {
14345                             month = 0;
14346                             year += 1;
14347                         } else {
14348                             month += 1;
14349                         }
14350                     }
14351                     this.date = this.UTCDate(year, month, day,0,0,0,0);
14352                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14353 //                    this.fill();
14354                     this.setValue(this.formatDate(this.date));
14355                     this.hide();
14356                 }
14357                 break;
14358         }
14359     },
14360     
14361     setStartDate: function(startDate)
14362     {
14363         this.startDate = startDate || -Infinity;
14364         if (this.startDate !== -Infinity) {
14365             this.startDate = this.parseDate(this.startDate);
14366         }
14367         this.update();
14368         this.updateNavArrows();
14369     },
14370
14371     setEndDate: function(endDate)
14372     {
14373         this.endDate = endDate || Infinity;
14374         if (this.endDate !== Infinity) {
14375             this.endDate = this.parseDate(this.endDate);
14376         }
14377         this.update();
14378         this.updateNavArrows();
14379     },
14380     
14381     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14382     {
14383         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14384         if (typeof(this.daysOfWeekDisabled) !== 'object') {
14385             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14386         }
14387         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14388             return parseInt(d, 10);
14389         });
14390         this.update();
14391         this.updateNavArrows();
14392     },
14393     
14394     updateNavArrows: function() 
14395     {
14396         var d = new Date(this.viewDate),
14397         year = d.getUTCFullYear(),
14398         month = d.getUTCMonth();
14399         
14400         Roo.each(this.picker().select('.prev', true).elements, function(v){
14401             v.show();
14402             switch (this.viewMode) {
14403                 case 0:
14404
14405                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14406                         v.hide();
14407                     }
14408                     break;
14409                 case 1:
14410                 case 2:
14411                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14412                         v.hide();
14413                     }
14414                     break;
14415             }
14416         });
14417         
14418         Roo.each(this.picker().select('.next', true).elements, function(v){
14419             v.show();
14420             switch (this.viewMode) {
14421                 case 0:
14422
14423                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14424                         v.hide();
14425                     }
14426                     break;
14427                 case 1:
14428                 case 2:
14429                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14430                         v.hide();
14431                     }
14432                     break;
14433             }
14434         })
14435     },
14436     
14437     moveMonth: function(date, dir)
14438     {
14439         if (!dir) return date;
14440         var new_date = new Date(date.valueOf()),
14441         day = new_date.getUTCDate(),
14442         month = new_date.getUTCMonth(),
14443         mag = Math.abs(dir),
14444         new_month, test;
14445         dir = dir > 0 ? 1 : -1;
14446         if (mag == 1){
14447             test = dir == -1
14448             // If going back one month, make sure month is not current month
14449             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14450             ? function(){
14451                 return new_date.getUTCMonth() == month;
14452             }
14453             // If going forward one month, make sure month is as expected
14454             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14455             : function(){
14456                 return new_date.getUTCMonth() != new_month;
14457             };
14458             new_month = month + dir;
14459             new_date.setUTCMonth(new_month);
14460             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14461             if (new_month < 0 || new_month > 11)
14462                 new_month = (new_month + 12) % 12;
14463         } else {
14464             // For magnitudes >1, move one month at a time...
14465             for (var i=0; i<mag; i++)
14466                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14467                 new_date = this.moveMonth(new_date, dir);
14468             // ...then reset the day, keeping it in the new month
14469             new_month = new_date.getUTCMonth();
14470             new_date.setUTCDate(day);
14471             test = function(){
14472                 return new_month != new_date.getUTCMonth();
14473             };
14474         }
14475         // Common date-resetting loop -- if date is beyond end of month, make it
14476         // end of month
14477         while (test()){
14478             new_date.setUTCDate(--day);
14479             new_date.setUTCMonth(new_month);
14480         }
14481         return new_date;
14482     },
14483
14484     moveYear: function(date, dir)
14485     {
14486         return this.moveMonth(date, dir*12);
14487     },
14488
14489     dateWithinRange: function(date)
14490     {
14491         return date >= this.startDate && date <= this.endDate;
14492     },
14493
14494     
14495     remove: function() 
14496     {
14497         this.picker().remove();
14498     }
14499    
14500 });
14501
14502 Roo.apply(Roo.bootstrap.DateField,  {
14503     
14504     head : {
14505         tag: 'thead',
14506         cn: [
14507         {
14508             tag: 'tr',
14509             cn: [
14510             {
14511                 tag: 'th',
14512                 cls: 'prev',
14513                 html: '<i class="fa fa-arrow-left"/>'
14514             },
14515             {
14516                 tag: 'th',
14517                 cls: 'switch',
14518                 colspan: '5'
14519             },
14520             {
14521                 tag: 'th',
14522                 cls: 'next',
14523                 html: '<i class="fa fa-arrow-right"/>'
14524             }
14525
14526             ]
14527         }
14528         ]
14529     },
14530     
14531     content : {
14532         tag: 'tbody',
14533         cn: [
14534         {
14535             tag: 'tr',
14536             cn: [
14537             {
14538                 tag: 'td',
14539                 colspan: '7'
14540             }
14541             ]
14542         }
14543         ]
14544     },
14545     
14546     footer : {
14547         tag: 'tfoot',
14548         cn: [
14549         {
14550             tag: 'tr',
14551             cn: [
14552             {
14553                 tag: 'th',
14554                 colspan: '7',
14555                 cls: 'today'
14556             }
14557                     
14558             ]
14559         }
14560         ]
14561     },
14562     
14563     dates:{
14564         en: {
14565             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14566             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14567             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14568             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14569             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14570             today: "Today"
14571         }
14572     },
14573     
14574     modes: [
14575     {
14576         clsName: 'days',
14577         navFnc: 'Month',
14578         navStep: 1
14579     },
14580     {
14581         clsName: 'months',
14582         navFnc: 'FullYear',
14583         navStep: 1
14584     },
14585     {
14586         clsName: 'years',
14587         navFnc: 'FullYear',
14588         navStep: 10
14589     }]
14590 });
14591
14592 Roo.apply(Roo.bootstrap.DateField,  {
14593   
14594     template : {
14595         tag: 'div',
14596         cls: 'datepicker dropdown-menu',
14597         cn: [
14598         {
14599             tag: 'div',
14600             cls: 'datepicker-days',
14601             cn: [
14602             {
14603                 tag: 'table',
14604                 cls: 'table-condensed',
14605                 cn:[
14606                 Roo.bootstrap.DateField.head,
14607                 {
14608                     tag: 'tbody'
14609                 },
14610                 Roo.bootstrap.DateField.footer
14611                 ]
14612             }
14613             ]
14614         },
14615         {
14616             tag: 'div',
14617             cls: 'datepicker-months',
14618             cn: [
14619             {
14620                 tag: 'table',
14621                 cls: 'table-condensed',
14622                 cn:[
14623                 Roo.bootstrap.DateField.head,
14624                 Roo.bootstrap.DateField.content,
14625                 Roo.bootstrap.DateField.footer
14626                 ]
14627             }
14628             ]
14629         },
14630         {
14631             tag: 'div',
14632             cls: 'datepicker-years',
14633             cn: [
14634             {
14635                 tag: 'table',
14636                 cls: 'table-condensed',
14637                 cn:[
14638                 Roo.bootstrap.DateField.head,
14639                 Roo.bootstrap.DateField.content,
14640                 Roo.bootstrap.DateField.footer
14641                 ]
14642             }
14643             ]
14644         }
14645         ]
14646     }
14647 });
14648
14649  
14650
14651  /*
14652  * - LGPL
14653  *
14654  * TimeField
14655  * 
14656  */
14657
14658 /**
14659  * @class Roo.bootstrap.TimeField
14660  * @extends Roo.bootstrap.Input
14661  * Bootstrap DateField class
14662  * 
14663  * 
14664  * @constructor
14665  * Create a new TimeField
14666  * @param {Object} config The config object
14667  */
14668
14669 Roo.bootstrap.TimeField = function(config){
14670     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14671     this.addEvents({
14672             /**
14673              * @event show
14674              * Fires when this field show.
14675              * @param {Roo.bootstrap.DateField} this
14676              * @param {Mixed} date The date value
14677              */
14678             show : true,
14679             /**
14680              * @event show
14681              * Fires when this field hide.
14682              * @param {Roo.bootstrap.DateField} this
14683              * @param {Mixed} date The date value
14684              */
14685             hide : true,
14686             /**
14687              * @event select
14688              * Fires when select a date.
14689              * @param {Roo.bootstrap.DateField} this
14690              * @param {Mixed} date The date value
14691              */
14692             select : true
14693         });
14694 };
14695
14696 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
14697     
14698     /**
14699      * @cfg {String} format
14700      * The default time format string which can be overriden for localization support.  The format must be
14701      * valid according to {@link Date#parseDate} (defaults to 'H:i').
14702      */
14703     format : "H:i",
14704        
14705     onRender: function(ct, position)
14706     {
14707         
14708         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14709                 
14710         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14711         
14712         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14713         
14714         this.pop = this.picker().select('>.datepicker-time',true).first();
14715         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block' 
14716         
14717         this.picker().on('mousedown', this.onMousedown, this);
14718         this.picker().on('click', this.onClick, this);
14719         
14720         this.picker().addClass('datepicker-dropdown');
14721     
14722         this.fillTime();
14723         this.update();
14724             
14725         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14726         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14727         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14728         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14729         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14730         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14731
14732     },
14733     
14734     fireKey: function(e){
14735         if (!this.picker().isVisible()){
14736             if (e.keyCode == 27) // allow escape to hide and re-show picker
14737                 this.show();
14738             return;
14739         }
14740
14741         e.preventDefault();
14742         
14743         switch(e.keyCode){
14744             case 27: // escape
14745                 this.hide();
14746                 break;
14747             case 37: // left
14748             case 39: // right
14749                 this.onTogglePeriod();
14750                 break;
14751             case 38: // up
14752                 this.onIncrementMinutes();
14753                 break;
14754             case 40: // down
14755                 this.onDecrementMinutes();
14756                 break;
14757             case 13: // enter
14758             case 9: // tab
14759                 this.setTime();
14760                 break;
14761         }
14762     },
14763     
14764     onClick: function(e) {
14765         e.stopPropagation();
14766         e.preventDefault();
14767     },
14768     
14769     picker : function()
14770     {
14771         return this.el.select('.datepicker', true).first();
14772     },
14773     
14774     fillTime: function()
14775     {    
14776         var time = this.pop.select('tbody', true).first();
14777         
14778         time.dom.innerHTML = '';
14779         
14780         time.createChild({
14781             tag: 'tr',
14782             cn: [
14783                 {
14784                     tag: 'td',
14785                     cn: [
14786                         {
14787                             tag: 'a',
14788                             href: '#',
14789                             cls: 'btn',
14790                             cn: [
14791                                 {
14792                                     tag: 'span',
14793                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
14794                                 }
14795                             ]
14796                         } 
14797                     ]
14798                 },
14799                 {
14800                     tag: 'td',
14801                     cls: 'separator'
14802                 },
14803                 {
14804                     tag: 'td',
14805                     cn: [
14806                         {
14807                             tag: 'a',
14808                             href: '#',
14809                             cls: 'btn',
14810                             cn: [
14811                                 {
14812                                     tag: 'span',
14813                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
14814                                 }
14815                             ]
14816                         }
14817                     ]
14818                 },
14819                 {
14820                     tag: 'td',
14821                     cls: 'separator'
14822                 }
14823             ]
14824         });
14825         
14826         time.createChild({
14827             tag: 'tr',
14828             cn: [
14829                 {
14830                     tag: 'td',
14831                     cn: [
14832                         {
14833                             tag: 'span',
14834                             cls: 'timepicker-hour',
14835                             html: '00'
14836                         }  
14837                     ]
14838                 },
14839                 {
14840                     tag: 'td',
14841                     cls: 'separator',
14842                     html: ':'
14843                 },
14844                 {
14845                     tag: 'td',
14846                     cn: [
14847                         {
14848                             tag: 'span',
14849                             cls: 'timepicker-minute',
14850                             html: '00'
14851                         }  
14852                     ]
14853                 },
14854                 {
14855                     tag: 'td',
14856                     cls: 'separator'
14857                 },
14858                 {
14859                     tag: 'td',
14860                     cn: [
14861                         {
14862                             tag: 'button',
14863                             type: 'button',
14864                             cls: 'btn btn-primary period',
14865                             html: 'AM'
14866                             
14867                         }
14868                     ]
14869                 }
14870             ]
14871         });
14872         
14873         time.createChild({
14874             tag: 'tr',
14875             cn: [
14876                 {
14877                     tag: 'td',
14878                     cn: [
14879                         {
14880                             tag: 'a',
14881                             href: '#',
14882                             cls: 'btn',
14883                             cn: [
14884                                 {
14885                                     tag: 'span',
14886                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
14887                                 }
14888                             ]
14889                         }
14890                     ]
14891                 },
14892                 {
14893                     tag: 'td',
14894                     cls: 'separator'
14895                 },
14896                 {
14897                     tag: 'td',
14898                     cn: [
14899                         {
14900                             tag: 'a',
14901                             href: '#',
14902                             cls: 'btn',
14903                             cn: [
14904                                 {
14905                                     tag: 'span',
14906                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
14907                                 }
14908                             ]
14909                         }
14910                     ]
14911                 },
14912                 {
14913                     tag: 'td',
14914                     cls: 'separator'
14915                 }
14916             ]
14917         });
14918         
14919     },
14920     
14921     update: function()
14922     {
14923         
14924         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14925         
14926         this.fill();
14927     },
14928     
14929     fill: function() 
14930     {
14931         var hours = this.time.getHours();
14932         var minutes = this.time.getMinutes();
14933         var period = 'AM';
14934         
14935         if(hours > 11){
14936             period = 'PM';
14937         }
14938         
14939         if(hours == 0){
14940             hours = 12;
14941         }
14942         
14943         
14944         if(hours > 12){
14945             hours = hours - 12;
14946         }
14947         
14948         if(hours < 10){
14949             hours = '0' + hours;
14950         }
14951         
14952         if(minutes < 10){
14953             minutes = '0' + minutes;
14954         }
14955         
14956         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14957         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14958         this.pop.select('button', true).first().dom.innerHTML = period;
14959         
14960     },
14961     
14962     place: function()
14963     {   
14964         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14965         
14966         var cls = ['bottom'];
14967         
14968         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14969             cls.pop();
14970             cls.push('top');
14971         }
14972         
14973         cls.push('right');
14974         
14975         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14976             cls.pop();
14977             cls.push('left');
14978         }
14979         
14980         this.picker().addClass(cls.join('-'));
14981         
14982         var _this = this;
14983         
14984         Roo.each(cls, function(c){
14985             if(c == 'bottom'){
14986                 _this.picker().setTop(_this.inputEl().getHeight());
14987                 return;
14988             }
14989             if(c == 'top'){
14990                 _this.picker().setTop(0 - _this.picker().getHeight());
14991                 return;
14992             }
14993             
14994             if(c == 'left'){
14995                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14996                 return;
14997             }
14998             if(c == 'right'){
14999                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15000                 return;
15001             }
15002         });
15003         
15004     },
15005   
15006     onFocus : function()
15007     {
15008         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15009         this.show();
15010     },
15011     
15012     onBlur : function()
15013     {
15014         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15015         this.hide();
15016     },
15017     
15018     show : function()
15019     {
15020         this.picker().show();
15021         this.pop.show();
15022         this.update();
15023         this.place();
15024         
15025         this.fireEvent('show', this, this.date);
15026     },
15027     
15028     hide : function()
15029     {
15030         this.picker().hide();
15031         this.pop.hide();
15032         
15033         this.fireEvent('hide', this, this.date);
15034     },
15035     
15036     setTime : function()
15037     {
15038         this.hide();
15039         this.setValue(this.time.format(this.format));
15040         
15041         this.fireEvent('select', this, this.date);
15042         
15043         
15044     },
15045     
15046     onMousedown: function(e){
15047         e.stopPropagation();
15048         e.preventDefault();
15049     },
15050     
15051     onIncrementHours: function()
15052     {
15053         Roo.log('onIncrementHours');
15054         this.time = this.time.add(Date.HOUR, 1);
15055         this.update();
15056         
15057     },
15058     
15059     onDecrementHours: function()
15060     {
15061         Roo.log('onDecrementHours');
15062         this.time = this.time.add(Date.HOUR, -1);
15063         this.update();
15064     },
15065     
15066     onIncrementMinutes: function()
15067     {
15068         Roo.log('onIncrementMinutes');
15069         this.time = this.time.add(Date.MINUTE, 1);
15070         this.update();
15071     },
15072     
15073     onDecrementMinutes: function()
15074     {
15075         Roo.log('onDecrementMinutes');
15076         this.time = this.time.add(Date.MINUTE, -1);
15077         this.update();
15078     },
15079     
15080     onTogglePeriod: function()
15081     {
15082         Roo.log('onTogglePeriod');
15083         this.time = this.time.add(Date.HOUR, 12);
15084         this.update();
15085     }
15086     
15087    
15088 });
15089
15090 Roo.apply(Roo.bootstrap.TimeField,  {
15091     
15092     content : {
15093         tag: 'tbody',
15094         cn: [
15095             {
15096                 tag: 'tr',
15097                 cn: [
15098                 {
15099                     tag: 'td',
15100                     colspan: '7'
15101                 }
15102                 ]
15103             }
15104         ]
15105     },
15106     
15107     footer : {
15108         tag: 'tfoot',
15109         cn: [
15110             {
15111                 tag: 'tr',
15112                 cn: [
15113                 {
15114                     tag: 'th',
15115                     colspan: '7',
15116                     cls: '',
15117                     cn: [
15118                         {
15119                             tag: 'button',
15120                             cls: 'btn btn-info ok',
15121                             html: 'OK'
15122                         }
15123                     ]
15124                 }
15125
15126                 ]
15127             }
15128         ]
15129     }
15130 });
15131
15132 Roo.apply(Roo.bootstrap.TimeField,  {
15133   
15134     template : {
15135         tag: 'div',
15136         cls: 'datepicker dropdown-menu',
15137         cn: [
15138             {
15139                 tag: 'div',
15140                 cls: 'datepicker-time',
15141                 cn: [
15142                 {
15143                     tag: 'table',
15144                     cls: 'table-condensed',
15145                     cn:[
15146                     Roo.bootstrap.TimeField.content,
15147                     Roo.bootstrap.TimeField.footer
15148                     ]
15149                 }
15150                 ]
15151             }
15152         ]
15153     }
15154 });
15155
15156  
15157
15158  /*
15159  * - LGPL
15160  *
15161  * CheckBox
15162  * 
15163  */
15164
15165 /**
15166  * @class Roo.bootstrap.CheckBox
15167  * @extends Roo.bootstrap.Input
15168  * Bootstrap CheckBox class
15169  * 
15170  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15171  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15172  * @cfg {String} boxLabel The text that appears beside the checkbox
15173  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15174  * @cfg {Boolean} checked initnal the element
15175  * 
15176  * 
15177  * @constructor
15178  * Create a new CheckBox
15179  * @param {Object} config The config object
15180  */
15181
15182 Roo.bootstrap.CheckBox = function(config){
15183     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15184    
15185         this.addEvents({
15186             /**
15187             * @event check
15188             * Fires when the element is checked or unchecked.
15189             * @param {Roo.bootstrap.CheckBox} this This input
15190             * @param {Boolean} checked The new checked value
15191             */
15192            check : true
15193         });
15194 };
15195
15196 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
15197     
15198     inputType: 'checkbox',
15199     inputValue: 1,
15200     valueOff: 0,
15201     boxLabel: false,
15202     checked: false,
15203     weight : false,
15204     
15205     getAutoCreate : function()
15206     {
15207         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15208         
15209         var id = Roo.id();
15210         
15211         var cfg = {};
15212         
15213         cfg.cls = 'form-group checkbox' //input-group
15214         
15215         
15216         
15217         
15218         var input =  {
15219             tag: 'input',
15220             id : id,
15221             type : this.inputType,
15222             value : (!this.checked) ? this.valueOff : this.inputValue,
15223             cls : 'roo-checkbox', //'form-box',
15224             placeholder : this.placeholder || ''
15225             
15226         };
15227         
15228         if (this.weight) { // Validity check?
15229             cfg.cls += " checkbox-" + this.weight;
15230         }
15231         
15232         if (this.disabled) {
15233             input.disabled=true;
15234         }
15235         
15236         if(this.checked){
15237             input.checked = this.checked;
15238         }
15239         
15240         if (this.name) {
15241             input.name = this.name;
15242         }
15243         
15244         if (this.size) {
15245             input.cls += ' input-' + this.size;
15246         }
15247         
15248         var settings=this;
15249         ['xs','sm','md','lg'].map(function(size){
15250             if (settings[size]) {
15251                 cfg.cls += ' col-' + size + '-' + settings[size];
15252             }
15253         });
15254         
15255        
15256         
15257         var inputblock = input;
15258         
15259         
15260         
15261         
15262         if (this.before || this.after) {
15263             
15264             inputblock = {
15265                 cls : 'input-group',
15266                 cn :  [] 
15267             };
15268             if (this.before) {
15269                 inputblock.cn.push({
15270                     tag :'span',
15271                     cls : 'input-group-addon',
15272                     html : this.before
15273                 });
15274             }
15275             inputblock.cn.push(input);
15276             if (this.after) {
15277                 inputblock.cn.push({
15278                     tag :'span',
15279                     cls : 'input-group-addon',
15280                     html : this.after
15281                 });
15282             }
15283             
15284         };
15285         
15286         if (align ==='left' && this.fieldLabel.length) {
15287                 Roo.log("left and has label");
15288                 cfg.cn = [
15289                     
15290                     {
15291                         tag: 'label',
15292                         'for' :  id,
15293                         cls : 'control-label col-md-' + this.labelWidth,
15294                         html : this.fieldLabel
15295                         
15296                     },
15297                     {
15298                         cls : "col-md-" + (12 - this.labelWidth), 
15299                         cn: [
15300                             inputblock
15301                         ]
15302                     }
15303                     
15304                 ];
15305         } else if ( this.fieldLabel.length) {
15306                 Roo.log(" label");
15307                 cfg.cn = [
15308                    
15309                     {
15310                         tag: this.boxLabel ? 'span' : 'label',
15311                         'for': id,
15312                         cls: 'control-label box-input-label',
15313                         //cls : 'input-group-addon',
15314                         html : this.fieldLabel
15315                         
15316                     },
15317                     
15318                     inputblock
15319                     
15320                 ];
15321
15322         } else {
15323             
15324                 Roo.log(" no label && no align");
15325                 cfg.cn = [  inputblock ] ;
15326                 
15327                 
15328         };
15329          if(this.boxLabel){
15330             cfg.cn.push( {
15331                 tag: 'label',
15332                 'for': id,
15333                 cls: 'box-label',
15334                 html: this.boxLabel
15335                 
15336             });
15337         }
15338         
15339         
15340        
15341         return cfg;
15342         
15343     },
15344     
15345     /**
15346      * return the real input element.
15347      */
15348     inputEl: function ()
15349     {
15350         return this.el.select('input.roo-checkbox',true).first();
15351     },
15352     
15353     label: function()
15354     {
15355         return this.el.select('label.control-label',true).first();
15356     },
15357     
15358     initEvents : function()
15359     {
15360 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15361         
15362         this.inputEl().on('click', this.onClick,  this);
15363         
15364     },
15365     
15366     onClick : function()
15367     {   
15368         this.setChecked(!this.checked);
15369     },
15370     
15371     setChecked : function(state,suppressEvent)
15372     {
15373         this.checked = state;
15374         
15375         this.inputEl().dom.checked = state;
15376         
15377         if(suppressEvent !== true){
15378             this.fireEvent('check', this, state);
15379         }
15380         
15381         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15382         
15383     },
15384     
15385     setValue : function(v,suppressEvent)
15386     {
15387         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15388     }
15389     
15390 });
15391
15392  
15393 /*
15394  * - LGPL
15395  *
15396  * Radio
15397  * 
15398  */
15399
15400 /**
15401  * @class Roo.bootstrap.Radio
15402  * @extends Roo.bootstrap.CheckBox
15403  * Bootstrap Radio class
15404
15405  * @constructor
15406  * Create a new Radio
15407  * @param {Object} config The config object
15408  */
15409
15410 Roo.bootstrap.Radio = function(config){
15411     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15412    
15413 };
15414
15415 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
15416     
15417     inputType: 'radio',
15418     inputValue: '',
15419     valueOff: '',
15420     
15421     getAutoCreate : function()
15422     {
15423         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15424         
15425         var id = Roo.id();
15426         
15427         var cfg = {};
15428         
15429         cfg.cls = 'form-group radio' //input-group
15430         
15431         var input =  {
15432             tag: 'input',
15433             id : id,
15434             type : this.inputType,
15435             value : (!this.checked) ? this.valueOff : this.inputValue,
15436             cls : 'roo-radio',
15437             placeholder : this.placeholder || ''
15438             
15439         };
15440           if (this.weight) { // Validity check?
15441             cfg.cls += " radio-" + this.weight;
15442         }
15443         if (this.disabled) {
15444             input.disabled=true;
15445         }
15446         
15447         if(this.checked){
15448             input.checked = this.checked;
15449         }
15450         
15451         if (this.name) {
15452             input.name = this.name;
15453         }
15454         
15455         if (this.size) {
15456             input.cls += ' input-' + this.size;
15457         }
15458         
15459         var settings=this;
15460         ['xs','sm','md','lg'].map(function(size){
15461             if (settings[size]) {
15462                 cfg.cls += ' col-' + size + '-' + settings[size];
15463             }
15464         });
15465         
15466         var inputblock = input;
15467         
15468         if (this.before || this.after) {
15469             
15470             inputblock = {
15471                 cls : 'input-group',
15472                 cn :  [] 
15473             };
15474             if (this.before) {
15475                 inputblock.cn.push({
15476                     tag :'span',
15477                     cls : 'input-group-addon',
15478                     html : this.before
15479                 });
15480             }
15481             inputblock.cn.push(input);
15482             if (this.after) {
15483                 inputblock.cn.push({
15484                     tag :'span',
15485                     cls : 'input-group-addon',
15486                     html : this.after
15487                 });
15488             }
15489             
15490         };
15491         
15492         if (align ==='left' && this.fieldLabel.length) {
15493                 Roo.log("left and has label");
15494                 cfg.cn = [
15495                     
15496                     {
15497                         tag: 'label',
15498                         'for' :  id,
15499                         cls : 'control-label col-md-' + this.labelWidth,
15500                         html : this.fieldLabel
15501                         
15502                     },
15503                     {
15504                         cls : "col-md-" + (12 - this.labelWidth), 
15505                         cn: [
15506                             inputblock
15507                         ]
15508                     }
15509                     
15510                 ];
15511         } else if ( this.fieldLabel.length) {
15512                 Roo.log(" label");
15513                  cfg.cn = [
15514                    
15515                     {
15516                         tag: 'label',
15517                         'for': id,
15518                         cls: 'control-label box-input-label',
15519                         //cls : 'input-group-addon',
15520                         html : this.fieldLabel
15521                         
15522                     },
15523                     
15524                     inputblock
15525                     
15526                 ];
15527
15528         } else {
15529             
15530                    Roo.log(" no label && no align");
15531                 cfg.cn = [
15532                     
15533                         inputblock
15534                     
15535                 ];
15536                 
15537                 
15538         };
15539         
15540         if(this.boxLabel){
15541             cfg.cn.push({
15542                 tag: 'label',
15543                 'for': id,
15544                 cls: 'box-label',
15545                 html: this.boxLabel
15546             })
15547         }
15548         
15549         return cfg;
15550         
15551     },
15552     inputEl: function ()
15553     {
15554         return this.el.select('input.roo-radio',true).first();
15555     },
15556     onClick : function()
15557     {   
15558         this.setChecked(true);
15559     },
15560     
15561     setChecked : function(state,suppressEvent)
15562     {
15563         if(state){
15564             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15565                 v.dom.checked = false;
15566             });
15567         }
15568         
15569         this.checked = state;
15570         this.inputEl().dom.checked = state;
15571         
15572         if(suppressEvent !== true){
15573             this.fireEvent('check', this, state);
15574         }
15575         
15576         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15577         
15578     },
15579     
15580     getGroupValue : function()
15581     {
15582         var value = ''
15583         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15584             if(v.dom.checked == true){
15585                 value = v.dom.value;
15586             }
15587         });
15588         
15589         return value;
15590     },
15591     
15592     /**
15593      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
15594      * @return {Mixed} value The field value
15595      */
15596     getValue : function(){
15597         return this.getGroupValue();
15598     }
15599     
15600 });
15601
15602  
15603 //<script type="text/javascript">
15604
15605 /*
15606  * Based  Ext JS Library 1.1.1
15607  * Copyright(c) 2006-2007, Ext JS, LLC.
15608  * LGPL
15609  *
15610  */
15611  
15612 /**
15613  * @class Roo.HtmlEditorCore
15614  * @extends Roo.Component
15615  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15616  *
15617  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15618  */
15619
15620 Roo.HtmlEditorCore = function(config){
15621     
15622     
15623     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15624     this.addEvents({
15625         /**
15626          * @event initialize
15627          * Fires when the editor is fully initialized (including the iframe)
15628          * @param {Roo.HtmlEditorCore} this
15629          */
15630         initialize: true,
15631         /**
15632          * @event activate
15633          * Fires when the editor is first receives the focus. Any insertion must wait
15634          * until after this event.
15635          * @param {Roo.HtmlEditorCore} this
15636          */
15637         activate: true,
15638          /**
15639          * @event beforesync
15640          * Fires before the textarea is updated with content from the editor iframe. Return false
15641          * to cancel the sync.
15642          * @param {Roo.HtmlEditorCore} this
15643          * @param {String} html
15644          */
15645         beforesync: true,
15646          /**
15647          * @event beforepush
15648          * Fires before the iframe editor is updated with content from the textarea. Return false
15649          * to cancel the push.
15650          * @param {Roo.HtmlEditorCore} this
15651          * @param {String} html
15652          */
15653         beforepush: true,
15654          /**
15655          * @event sync
15656          * Fires when the textarea is updated with content from the editor iframe.
15657          * @param {Roo.HtmlEditorCore} this
15658          * @param {String} html
15659          */
15660         sync: true,
15661          /**
15662          * @event push
15663          * Fires when the iframe editor is updated with content from the textarea.
15664          * @param {Roo.HtmlEditorCore} this
15665          * @param {String} html
15666          */
15667         push: true,
15668         
15669         /**
15670          * @event editorevent
15671          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15672          * @param {Roo.HtmlEditorCore} this
15673          */
15674         editorevent: true
15675     });
15676      
15677 };
15678
15679
15680 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
15681
15682
15683      /**
15684      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
15685      */
15686     
15687     owner : false,
15688     
15689      /**
15690      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
15691      *                        Roo.resizable.
15692      */
15693     resizable : false,
15694      /**
15695      * @cfg {Number} height (in pixels)
15696      */   
15697     height: 300,
15698    /**
15699      * @cfg {Number} width (in pixels)
15700      */   
15701     width: 500,
15702     
15703     /**
15704      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15705      * 
15706      */
15707     stylesheets: false,
15708     
15709     // id of frame..
15710     frameId: false,
15711     
15712     // private properties
15713     validationEvent : false,
15714     deferHeight: true,
15715     initialized : false,
15716     activated : false,
15717     sourceEditMode : false,
15718     onFocus : Roo.emptyFn,
15719     iframePad:3,
15720     hideMode:'offsets',
15721     
15722     clearUp: true,
15723     
15724      
15725     
15726
15727     /**
15728      * Protected method that will not generally be called directly. It
15729      * is called when the editor initializes the iframe with HTML contents. Override this method if you
15730      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15731      */
15732     getDocMarkup : function(){
15733         // body styles..
15734         var st = '';
15735         Roo.log(this.stylesheets);
15736         
15737         // inherit styels from page...?? 
15738         if (this.stylesheets === false) {
15739             
15740             Roo.get(document.head).select('style').each(function(node) {
15741                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15742             });
15743             
15744             Roo.get(document.head).select('link').each(function(node) { 
15745                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15746             });
15747             
15748         } else if (!this.stylesheets.length) {
15749                 // simple..
15750                 st = '<style type="text/css">' +
15751                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15752                    '</style>';
15753         } else {
15754             Roo.each(this.stylesheets, function(s) {
15755                 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15756             });
15757             
15758         }
15759         
15760         st +=  '<style type="text/css">' +
15761             'IMG { cursor: pointer } ' +
15762         '</style>';
15763
15764         
15765         return '<html><head>' + st  +
15766             //<style type="text/css">' +
15767             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15768             //'</style>' +
15769             ' </head><body class="roo-htmleditor-body"></body></html>';
15770     },
15771
15772     // private
15773     onRender : function(ct, position)
15774     {
15775         var _t = this;
15776         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15777         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15778         
15779         
15780         this.el.dom.style.border = '0 none';
15781         this.el.dom.setAttribute('tabIndex', -1);
15782         this.el.addClass('x-hidden hide');
15783         
15784         
15785         
15786         if(Roo.isIE){ // fix IE 1px bogus margin
15787             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15788         }
15789        
15790         
15791         this.frameId = Roo.id();
15792         
15793          
15794         
15795         var iframe = this.owner.wrap.createChild({
15796             tag: 'iframe',
15797             cls: 'form-control', // bootstrap..
15798             id: this.frameId,
15799             name: this.frameId,
15800             frameBorder : 'no',
15801             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
15802         }, this.el
15803         );
15804         
15805         
15806         this.iframe = iframe.dom;
15807
15808          this.assignDocWin();
15809         
15810         this.doc.designMode = 'on';
15811        
15812         this.doc.open();
15813         this.doc.write(this.getDocMarkup());
15814         this.doc.close();
15815
15816         
15817         var task = { // must defer to wait for browser to be ready
15818             run : function(){
15819                 //console.log("run task?" + this.doc.readyState);
15820                 this.assignDocWin();
15821                 if(this.doc.body || this.doc.readyState == 'complete'){
15822                     try {
15823                         this.doc.designMode="on";
15824                     } catch (e) {
15825                         return;
15826                     }
15827                     Roo.TaskMgr.stop(task);
15828                     this.initEditor.defer(10, this);
15829                 }
15830             },
15831             interval : 10,
15832             duration: 10000,
15833             scope: this
15834         };
15835         Roo.TaskMgr.start(task);
15836
15837         
15838          
15839     },
15840
15841     // private
15842     onResize : function(w, h)
15843     {
15844          Roo.log('resize: ' +w + ',' + h );
15845         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15846         if(!this.iframe){
15847             return;
15848         }
15849         if(typeof w == 'number'){
15850             
15851             this.iframe.style.width = w + 'px';
15852         }
15853         if(typeof h == 'number'){
15854             
15855             this.iframe.style.height = h + 'px';
15856             if(this.doc){
15857                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15858             }
15859         }
15860         
15861     },
15862
15863     /**
15864      * Toggles the editor between standard and source edit mode.
15865      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15866      */
15867     toggleSourceEdit : function(sourceEditMode){
15868         
15869         this.sourceEditMode = sourceEditMode === true;
15870         
15871         if(this.sourceEditMode){
15872  
15873             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
15874             
15875         }else{
15876             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15877             //this.iframe.className = '';
15878             this.deferFocus();
15879         }
15880         //this.setSize(this.owner.wrap.getSize());
15881         //this.fireEvent('editmodechange', this, this.sourceEditMode);
15882     },
15883
15884     
15885   
15886
15887     /**
15888      * Protected method that will not generally be called directly. If you need/want
15889      * custom HTML cleanup, this is the method you should override.
15890      * @param {String} html The HTML to be cleaned
15891      * return {String} The cleaned HTML
15892      */
15893     cleanHtml : function(html){
15894         html = String(html);
15895         if(html.length > 5){
15896             if(Roo.isSafari){ // strip safari nonsense
15897                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15898             }
15899         }
15900         if(html == '&nbsp;'){
15901             html = '';
15902         }
15903         return html;
15904     },
15905
15906     /**
15907      * HTML Editor -> Textarea
15908      * Protected method that will not generally be called directly. Syncs the contents
15909      * of the editor iframe with the textarea.
15910      */
15911     syncValue : function(){
15912         if(this.initialized){
15913             var bd = (this.doc.body || this.doc.documentElement);
15914             //this.cleanUpPaste(); -- this is done else where and causes havoc..
15915             var html = bd.innerHTML;
15916             if(Roo.isSafari){
15917                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15918                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15919                 if(m && m[1]){
15920                     html = '<div style="'+m[0]+'">' + html + '</div>';
15921                 }
15922             }
15923             html = this.cleanHtml(html);
15924             // fix up the special chars.. normaly like back quotes in word...
15925             // however we do not want to do this with chinese..
15926             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15927                 var cc = b.charCodeAt();
15928                 if (
15929                     (cc >= 0x4E00 && cc < 0xA000 ) ||
15930                     (cc >= 0x3400 && cc < 0x4E00 ) ||
15931                     (cc >= 0xf900 && cc < 0xfb00 )
15932                 ) {
15933                         return b;
15934                 }
15935                 return "&#"+cc+";" 
15936             });
15937             if(this.owner.fireEvent('beforesync', this, html) !== false){
15938                 this.el.dom.value = html;
15939                 this.owner.fireEvent('sync', this, html);
15940             }
15941         }
15942     },
15943
15944     /**
15945      * Protected method that will not generally be called directly. Pushes the value of the textarea
15946      * into the iframe editor.
15947      */
15948     pushValue : function(){
15949         if(this.initialized){
15950             var v = this.el.dom.value.trim();
15951             
15952 //            if(v.length < 1){
15953 //                v = '&#160;';
15954 //            }
15955             
15956             if(this.owner.fireEvent('beforepush', this, v) !== false){
15957                 var d = (this.doc.body || this.doc.documentElement);
15958                 d.innerHTML = v;
15959                 this.cleanUpPaste();
15960                 this.el.dom.value = d.innerHTML;
15961                 this.owner.fireEvent('push', this, v);
15962             }
15963         }
15964     },
15965
15966     // private
15967     deferFocus : function(){
15968         this.focus.defer(10, this);
15969     },
15970
15971     // doc'ed in Field
15972     focus : function(){
15973         if(this.win && !this.sourceEditMode){
15974             this.win.focus();
15975         }else{
15976             this.el.focus();
15977         }
15978     },
15979     
15980     assignDocWin: function()
15981     {
15982         var iframe = this.iframe;
15983         
15984          if(Roo.isIE){
15985             this.doc = iframe.contentWindow.document;
15986             this.win = iframe.contentWindow;
15987         } else {
15988             if (!Roo.get(this.frameId)) {
15989                 return;
15990             }
15991             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15992             this.win = Roo.get(this.frameId).dom.contentWindow;
15993         }
15994     },
15995     
15996     // private
15997     initEditor : function(){
15998         //console.log("INIT EDITOR");
15999         this.assignDocWin();
16000         
16001         
16002         
16003         this.doc.designMode="on";
16004         this.doc.open();
16005         this.doc.write(this.getDocMarkup());
16006         this.doc.close();
16007         
16008         var dbody = (this.doc.body || this.doc.documentElement);
16009         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16010         // this copies styles from the containing element into thsi one..
16011         // not sure why we need all of this..
16012         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16013         
16014         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16015         //ss['background-attachment'] = 'fixed'; // w3c
16016         dbody.bgProperties = 'fixed'; // ie
16017         //Roo.DomHelper.applyStyles(dbody, ss);
16018         Roo.EventManager.on(this.doc, {
16019             //'mousedown': this.onEditorEvent,
16020             'mouseup': this.onEditorEvent,
16021             'dblclick': this.onEditorEvent,
16022             'click': this.onEditorEvent,
16023             'keyup': this.onEditorEvent,
16024             buffer:100,
16025             scope: this
16026         });
16027         if(Roo.isGecko){
16028             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16029         }
16030         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16031             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16032         }
16033         this.initialized = true;
16034
16035         this.owner.fireEvent('initialize', this);
16036         this.pushValue();
16037     },
16038
16039     // private
16040     onDestroy : function(){
16041         
16042         
16043         
16044         if(this.rendered){
16045             
16046             //for (var i =0; i < this.toolbars.length;i++) {
16047             //    // fixme - ask toolbars for heights?
16048             //    this.toolbars[i].onDestroy();
16049            // }
16050             
16051             //this.wrap.dom.innerHTML = '';
16052             //this.wrap.remove();
16053         }
16054     },
16055
16056     // private
16057     onFirstFocus : function(){
16058         
16059         this.assignDocWin();
16060         
16061         
16062         this.activated = true;
16063          
16064     
16065         if(Roo.isGecko){ // prevent silly gecko errors
16066             this.win.focus();
16067             var s = this.win.getSelection();
16068             if(!s.focusNode || s.focusNode.nodeType != 3){
16069                 var r = s.getRangeAt(0);
16070                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16071                 r.collapse(true);
16072                 this.deferFocus();
16073             }
16074             try{
16075                 this.execCmd('useCSS', true);
16076                 this.execCmd('styleWithCSS', false);
16077             }catch(e){}
16078         }
16079         this.owner.fireEvent('activate', this);
16080     },
16081
16082     // private
16083     adjustFont: function(btn){
16084         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16085         //if(Roo.isSafari){ // safari
16086         //    adjust *= 2;
16087        // }
16088         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16089         if(Roo.isSafari){ // safari
16090             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16091             v =  (v < 10) ? 10 : v;
16092             v =  (v > 48) ? 48 : v;
16093             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16094             
16095         }
16096         
16097         
16098         v = Math.max(1, v+adjust);
16099         
16100         this.execCmd('FontSize', v  );
16101     },
16102
16103     onEditorEvent : function(e){
16104         this.owner.fireEvent('editorevent', this, e);
16105       //  this.updateToolbar();
16106         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16107     },
16108
16109     insertTag : function(tg)
16110     {
16111         // could be a bit smarter... -> wrap the current selected tRoo..
16112         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16113             
16114             range = this.createRange(this.getSelection());
16115             var wrappingNode = this.doc.createElement(tg.toLowerCase());
16116             wrappingNode.appendChild(range.extractContents());
16117             range.insertNode(wrappingNode);
16118
16119             return;
16120             
16121             
16122             
16123         }
16124         this.execCmd("formatblock",   tg);
16125         
16126     },
16127     
16128     insertText : function(txt)
16129     {
16130         
16131         
16132         var range = this.createRange();
16133         range.deleteContents();
16134                //alert(Sender.getAttribute('label'));
16135                
16136         range.insertNode(this.doc.createTextNode(txt));
16137     } ,
16138     
16139      
16140
16141     /**
16142      * Executes a Midas editor command on the editor document and performs necessary focus and
16143      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16144      * @param {String} cmd The Midas command
16145      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16146      */
16147     relayCmd : function(cmd, value){
16148         this.win.focus();
16149         this.execCmd(cmd, value);
16150         this.owner.fireEvent('editorevent', this);
16151         //this.updateToolbar();
16152         this.owner.deferFocus();
16153     },
16154
16155     /**
16156      * Executes a Midas editor command directly on the editor document.
16157      * For visual commands, you should use {@link #relayCmd} instead.
16158      * <b>This should only be called after the editor is initialized.</b>
16159      * @param {String} cmd The Midas command
16160      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16161      */
16162     execCmd : function(cmd, value){
16163         this.doc.execCommand(cmd, false, value === undefined ? null : value);
16164         this.syncValue();
16165     },
16166  
16167  
16168    
16169     /**
16170      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16171      * to insert tRoo.
16172      * @param {String} text | dom node.. 
16173      */
16174     insertAtCursor : function(text)
16175     {
16176         
16177         
16178         
16179         if(!this.activated){
16180             return;
16181         }
16182         /*
16183         if(Roo.isIE){
16184             this.win.focus();
16185             var r = this.doc.selection.createRange();
16186             if(r){
16187                 r.collapse(true);
16188                 r.pasteHTML(text);
16189                 this.syncValue();
16190                 this.deferFocus();
16191             
16192             }
16193             return;
16194         }
16195         */
16196         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16197             this.win.focus();
16198             
16199             
16200             // from jquery ui (MIT licenced)
16201             var range, node;
16202             var win = this.win;
16203             
16204             if (win.getSelection && win.getSelection().getRangeAt) {
16205                 range = win.getSelection().getRangeAt(0);
16206                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16207                 range.insertNode(node);
16208             } else if (win.document.selection && win.document.selection.createRange) {
16209                 // no firefox support
16210                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16211                 win.document.selection.createRange().pasteHTML(txt);
16212             } else {
16213                 // no firefox support
16214                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16215                 this.execCmd('InsertHTML', txt);
16216             } 
16217             
16218             this.syncValue();
16219             
16220             this.deferFocus();
16221         }
16222     },
16223  // private
16224     mozKeyPress : function(e){
16225         if(e.ctrlKey){
16226             var c = e.getCharCode(), cmd;
16227           
16228             if(c > 0){
16229                 c = String.fromCharCode(c).toLowerCase();
16230                 switch(c){
16231                     case 'b':
16232                         cmd = 'bold';
16233                         break;
16234                     case 'i':
16235                         cmd = 'italic';
16236                         break;
16237                     
16238                     case 'u':
16239                         cmd = 'underline';
16240                         break;
16241                     
16242                     case 'v':
16243                         this.cleanUpPaste.defer(100, this);
16244                         return;
16245                         
16246                 }
16247                 if(cmd){
16248                     this.win.focus();
16249                     this.execCmd(cmd);
16250                     this.deferFocus();
16251                     e.preventDefault();
16252                 }
16253                 
16254             }
16255         }
16256     },
16257
16258     // private
16259     fixKeys : function(){ // load time branching for fastest keydown performance
16260         if(Roo.isIE){
16261             return function(e){
16262                 var k = e.getKey(), r;
16263                 if(k == e.TAB){
16264                     e.stopEvent();
16265                     r = this.doc.selection.createRange();
16266                     if(r){
16267                         r.collapse(true);
16268                         r.pasteHTML('&#160;&#160;&#160;&#160;');
16269                         this.deferFocus();
16270                     }
16271                     return;
16272                 }
16273                 
16274                 if(k == e.ENTER){
16275                     r = this.doc.selection.createRange();
16276                     if(r){
16277                         var target = r.parentElement();
16278                         if(!target || target.tagName.toLowerCase() != 'li'){
16279                             e.stopEvent();
16280                             r.pasteHTML('<br />');
16281                             r.collapse(false);
16282                             r.select();
16283                         }
16284                     }
16285                 }
16286                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16287                     this.cleanUpPaste.defer(100, this);
16288                     return;
16289                 }
16290                 
16291                 
16292             };
16293         }else if(Roo.isOpera){
16294             return function(e){
16295                 var k = e.getKey();
16296                 if(k == e.TAB){
16297                     e.stopEvent();
16298                     this.win.focus();
16299                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
16300                     this.deferFocus();
16301                 }
16302                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16303                     this.cleanUpPaste.defer(100, this);
16304                     return;
16305                 }
16306                 
16307             };
16308         }else if(Roo.isSafari){
16309             return function(e){
16310                 var k = e.getKey();
16311                 
16312                 if(k == e.TAB){
16313                     e.stopEvent();
16314                     this.execCmd('InsertText','\t');
16315                     this.deferFocus();
16316                     return;
16317                 }
16318                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16319                     this.cleanUpPaste.defer(100, this);
16320                     return;
16321                 }
16322                 
16323              };
16324         }
16325     }(),
16326     
16327     getAllAncestors: function()
16328     {
16329         var p = this.getSelectedNode();
16330         var a = [];
16331         if (!p) {
16332             a.push(p); // push blank onto stack..
16333             p = this.getParentElement();
16334         }
16335         
16336         
16337         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16338             a.push(p);
16339             p = p.parentNode;
16340         }
16341         a.push(this.doc.body);
16342         return a;
16343     },
16344     lastSel : false,
16345     lastSelNode : false,
16346     
16347     
16348     getSelection : function() 
16349     {
16350         this.assignDocWin();
16351         return Roo.isIE ? this.doc.selection : this.win.getSelection();
16352     },
16353     
16354     getSelectedNode: function() 
16355     {
16356         // this may only work on Gecko!!!
16357         
16358         // should we cache this!!!!
16359         
16360         
16361         
16362          
16363         var range = this.createRange(this.getSelection()).cloneRange();
16364         
16365         if (Roo.isIE) {
16366             var parent = range.parentElement();
16367             while (true) {
16368                 var testRange = range.duplicate();
16369                 testRange.moveToElementText(parent);
16370                 if (testRange.inRange(range)) {
16371                     break;
16372                 }
16373                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16374                     break;
16375                 }
16376                 parent = parent.parentElement;
16377             }
16378             return parent;
16379         }
16380         
16381         // is ancestor a text element.
16382         var ac =  range.commonAncestorContainer;
16383         if (ac.nodeType == 3) {
16384             ac = ac.parentNode;
16385         }
16386         
16387         var ar = ac.childNodes;
16388          
16389         var nodes = [];
16390         var other_nodes = [];
16391         var has_other_nodes = false;
16392         for (var i=0;i<ar.length;i++) {
16393             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
16394                 continue;
16395             }
16396             // fullly contained node.
16397             
16398             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16399                 nodes.push(ar[i]);
16400                 continue;
16401             }
16402             
16403             // probably selected..
16404             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16405                 other_nodes.push(ar[i]);
16406                 continue;
16407             }
16408             // outer..
16409             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
16410                 continue;
16411             }
16412             
16413             
16414             has_other_nodes = true;
16415         }
16416         if (!nodes.length && other_nodes.length) {
16417             nodes= other_nodes;
16418         }
16419         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16420             return false;
16421         }
16422         
16423         return nodes[0];
16424     },
16425     createRange: function(sel)
16426     {
16427         // this has strange effects when using with 
16428         // top toolbar - not sure if it's a great idea.
16429         //this.editor.contentWindow.focus();
16430         if (typeof sel != "undefined") {
16431             try {
16432                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16433             } catch(e) {
16434                 return this.doc.createRange();
16435             }
16436         } else {
16437             return this.doc.createRange();
16438         }
16439     },
16440     getParentElement: function()
16441     {
16442         
16443         this.assignDocWin();
16444         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16445         
16446         var range = this.createRange(sel);
16447          
16448         try {
16449             var p = range.commonAncestorContainer;
16450             while (p.nodeType == 3) { // text node
16451                 p = p.parentNode;
16452             }
16453             return p;
16454         } catch (e) {
16455             return null;
16456         }
16457     
16458     },
16459     /***
16460      *
16461      * Range intersection.. the hard stuff...
16462      *  '-1' = before
16463      *  '0' = hits..
16464      *  '1' = after.
16465      *         [ -- selected range --- ]
16466      *   [fail]                        [fail]
16467      *
16468      *    basically..
16469      *      if end is before start or  hits it. fail.
16470      *      if start is after end or hits it fail.
16471      *
16472      *   if either hits (but other is outside. - then it's not 
16473      *   
16474      *    
16475      **/
16476     
16477     
16478     // @see http://www.thismuchiknow.co.uk/?p=64.
16479     rangeIntersectsNode : function(range, node)
16480     {
16481         var nodeRange = node.ownerDocument.createRange();
16482         try {
16483             nodeRange.selectNode(node);
16484         } catch (e) {
16485             nodeRange.selectNodeContents(node);
16486         }
16487     
16488         var rangeStartRange = range.cloneRange();
16489         rangeStartRange.collapse(true);
16490     
16491         var rangeEndRange = range.cloneRange();
16492         rangeEndRange.collapse(false);
16493     
16494         var nodeStartRange = nodeRange.cloneRange();
16495         nodeStartRange.collapse(true);
16496     
16497         var nodeEndRange = nodeRange.cloneRange();
16498         nodeEndRange.collapse(false);
16499     
16500         return rangeStartRange.compareBoundaryPoints(
16501                  Range.START_TO_START, nodeEndRange) == -1 &&
16502                rangeEndRange.compareBoundaryPoints(
16503                  Range.START_TO_START, nodeStartRange) == 1;
16504         
16505          
16506     },
16507     rangeCompareNode : function(range, node)
16508     {
16509         var nodeRange = node.ownerDocument.createRange();
16510         try {
16511             nodeRange.selectNode(node);
16512         } catch (e) {
16513             nodeRange.selectNodeContents(node);
16514         }
16515         
16516         
16517         range.collapse(true);
16518     
16519         nodeRange.collapse(true);
16520      
16521         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16522         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
16523          
16524         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16525         
16526         var nodeIsBefore   =  ss == 1;
16527         var nodeIsAfter    = ee == -1;
16528         
16529         if (nodeIsBefore && nodeIsAfter)
16530             return 0; // outer
16531         if (!nodeIsBefore && nodeIsAfter)
16532             return 1; //right trailed.
16533         
16534         if (nodeIsBefore && !nodeIsAfter)
16535             return 2;  // left trailed.
16536         // fully contined.
16537         return 3;
16538     },
16539
16540     // private? - in a new class?
16541     cleanUpPaste :  function()
16542     {
16543         // cleans up the whole document..
16544         Roo.log('cleanuppaste');
16545         
16546         this.cleanUpChildren(this.doc.body);
16547         var clean = this.cleanWordChars(this.doc.body.innerHTML);
16548         if (clean != this.doc.body.innerHTML) {
16549             this.doc.body.innerHTML = clean;
16550         }
16551         
16552     },
16553     
16554     cleanWordChars : function(input) {// change the chars to hex code
16555         var he = Roo.HtmlEditorCore;
16556         
16557         var output = input;
16558         Roo.each(he.swapCodes, function(sw) { 
16559             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16560             
16561             output = output.replace(swapper, sw[1]);
16562         });
16563         
16564         return output;
16565     },
16566     
16567     
16568     cleanUpChildren : function (n)
16569     {
16570         if (!n.childNodes.length) {
16571             return;
16572         }
16573         for (var i = n.childNodes.length-1; i > -1 ; i--) {
16574            this.cleanUpChild(n.childNodes[i]);
16575         }
16576     },
16577     
16578     
16579         
16580     
16581     cleanUpChild : function (node)
16582     {
16583         var ed = this;
16584         //console.log(node);
16585         if (node.nodeName == "#text") {
16586             // clean up silly Windows -- stuff?
16587             return; 
16588         }
16589         if (node.nodeName == "#comment") {
16590             node.parentNode.removeChild(node);
16591             // clean up silly Windows -- stuff?
16592             return; 
16593         }
16594         
16595         if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16596             // remove node.
16597             node.parentNode.removeChild(node);
16598             return;
16599             
16600         }
16601         
16602         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16603         
16604         // remove <a name=....> as rendering on yahoo mailer is borked with this.
16605         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16606         
16607         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16608         //    remove_keep_children = true;
16609         //}
16610         
16611         if (remove_keep_children) {
16612             this.cleanUpChildren(node);
16613             // inserts everything just before this node...
16614             while (node.childNodes.length) {
16615                 var cn = node.childNodes[0];
16616                 node.removeChild(cn);
16617                 node.parentNode.insertBefore(cn, node);
16618             }
16619             node.parentNode.removeChild(node);
16620             return;
16621         }
16622         
16623         if (!node.attributes || !node.attributes.length) {
16624             this.cleanUpChildren(node);
16625             return;
16626         }
16627         
16628         function cleanAttr(n,v)
16629         {
16630             
16631             if (v.match(/^\./) || v.match(/^\//)) {
16632                 return;
16633             }
16634             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16635                 return;
16636             }
16637             if (v.match(/^#/)) {
16638                 return;
16639             }
16640 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16641             node.removeAttribute(n);
16642             
16643         }
16644         
16645         function cleanStyle(n,v)
16646         {
16647             if (v.match(/expression/)) { //XSS?? should we even bother..
16648                 node.removeAttribute(n);
16649                 return;
16650             }
16651             var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16652             var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16653             
16654             
16655             var parts = v.split(/;/);
16656             var clean = [];
16657             
16658             Roo.each(parts, function(p) {
16659                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16660                 if (!p.length) {
16661                     return true;
16662                 }
16663                 var l = p.split(':').shift().replace(/\s+/g,'');
16664                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16665                 
16666                 if ( cblack.indexOf(l) > -1) {
16667 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16668                     //node.removeAttribute(n);
16669                     return true;
16670                 }
16671                 //Roo.log()
16672                 // only allow 'c whitelisted system attributes'
16673                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
16674 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16675                     //node.removeAttribute(n);
16676                     return true;
16677                 }
16678                 
16679                 
16680                  
16681                 
16682                 clean.push(p);
16683                 return true;
16684             });
16685             if (clean.length) { 
16686                 node.setAttribute(n, clean.join(';'));
16687             } else {
16688                 node.removeAttribute(n);
16689             }
16690             
16691         }
16692         
16693         
16694         for (var i = node.attributes.length-1; i > -1 ; i--) {
16695             var a = node.attributes[i];
16696             //console.log(a);
16697             
16698             if (a.name.toLowerCase().substr(0,2)=='on')  {
16699                 node.removeAttribute(a.name);
16700                 continue;
16701             }
16702             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16703                 node.removeAttribute(a.name);
16704                 continue;
16705             }
16706             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16707                 cleanAttr(a.name,a.value); // fixme..
16708                 continue;
16709             }
16710             if (a.name == 'style') {
16711                 cleanStyle(a.name,a.value);
16712                 continue;
16713             }
16714             /// clean up MS crap..
16715             // tecnically this should be a list of valid class'es..
16716             
16717             
16718             if (a.name == 'class') {
16719                 if (a.value.match(/^Mso/)) {
16720                     node.className = '';
16721                 }
16722                 
16723                 if (a.value.match(/body/)) {
16724                     node.className = '';
16725                 }
16726                 continue;
16727             }
16728             
16729             // style cleanup!?
16730             // class cleanup?
16731             
16732         }
16733         
16734         
16735         this.cleanUpChildren(node);
16736         
16737         
16738     },
16739     /**
16740      * Clean up MS wordisms...
16741      */
16742     cleanWord : function(node)
16743     {
16744         var _t = this;
16745         var cleanWordChildren = function()
16746         {
16747             if (!node.childNodes.length) {
16748                 return;
16749             }
16750             for (var i = node.childNodes.length-1; i > -1 ; i--) {
16751                _t.cleanWord(node.childNodes[i]);
16752             }
16753         }
16754         
16755         
16756         if (!node) {
16757             this.cleanWord(this.doc.body);
16758             return;
16759         }
16760         if (node.nodeName == "#text") {
16761             // clean up silly Windows -- stuff?
16762             return; 
16763         }
16764         if (node.nodeName == "#comment") {
16765             node.parentNode.removeChild(node);
16766             // clean up silly Windows -- stuff?
16767             return; 
16768         }
16769         
16770         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16771             node.parentNode.removeChild(node);
16772             return;
16773         }
16774         
16775         // remove - but keep children..
16776         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16777             while (node.childNodes.length) {
16778                 var cn = node.childNodes[0];
16779                 node.removeChild(cn);
16780                 node.parentNode.insertBefore(cn, node);
16781             }
16782             node.parentNode.removeChild(node);
16783             cleanWordChildren();
16784             return;
16785         }
16786         // clean styles
16787         if (node.className.length) {
16788             
16789             var cn = node.className.split(/\W+/);
16790             var cna = [];
16791             Roo.each(cn, function(cls) {
16792                 if (cls.match(/Mso[a-zA-Z]+/)) {
16793                     return;
16794                 }
16795                 cna.push(cls);
16796             });
16797             node.className = cna.length ? cna.join(' ') : '';
16798             if (!cna.length) {
16799                 node.removeAttribute("class");
16800             }
16801         }
16802         
16803         if (node.hasAttribute("lang")) {
16804             node.removeAttribute("lang");
16805         }
16806         
16807         if (node.hasAttribute("style")) {
16808             
16809             var styles = node.getAttribute("style").split(";");
16810             var nstyle = [];
16811             Roo.each(styles, function(s) {
16812                 if (!s.match(/:/)) {
16813                     return;
16814                 }
16815                 var kv = s.split(":");
16816                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16817                     return;
16818                 }
16819                 // what ever is left... we allow.
16820                 nstyle.push(s);
16821             });
16822             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16823             if (!nstyle.length) {
16824                 node.removeAttribute('style');
16825             }
16826         }
16827         
16828         cleanWordChildren();
16829         
16830         
16831     },
16832     domToHTML : function(currentElement, depth, nopadtext) {
16833         
16834             depth = depth || 0;
16835             nopadtext = nopadtext || false;
16836         
16837             if (!currentElement) {
16838                 return this.domToHTML(this.doc.body);
16839             }
16840             
16841             //Roo.log(currentElement);
16842             var j;
16843             var allText = false;
16844             var nodeName = currentElement.nodeName;
16845             var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16846             
16847             if  (nodeName == '#text') {
16848                 return currentElement.nodeValue;
16849             }
16850             
16851             
16852             var ret = '';
16853             if (nodeName != 'BODY') {
16854                  
16855                 var i = 0;
16856                 // Prints the node tagName, such as <A>, <IMG>, etc
16857                 if (tagName) {
16858                     var attr = [];
16859                     for(i = 0; i < currentElement.attributes.length;i++) {
16860                         // quoting?
16861                         var aname = currentElement.attributes.item(i).name;
16862                         if (!currentElement.attributes.item(i).value.length) {
16863                             continue;
16864                         }
16865                         attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16866                     }
16867                     
16868                     ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16869                 } 
16870                 else {
16871                     
16872                     // eack
16873                 }
16874             } else {
16875                 tagName = false;
16876             }
16877             if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16878                 return ret;
16879             }
16880             if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16881                 nopadtext = true;
16882             }
16883             
16884             
16885             // Traverse the tree
16886             i = 0;
16887             var currentElementChild = currentElement.childNodes.item(i);
16888             var allText = true;
16889             var innerHTML  = '';
16890             lastnode = '';
16891             while (currentElementChild) {
16892                 // Formatting code (indent the tree so it looks nice on the screen)
16893                 var nopad = nopadtext;
16894                 if (lastnode == 'SPAN') {
16895                     nopad  = true;
16896                 }
16897                 // text
16898                 if  (currentElementChild.nodeName == '#text') {
16899                     var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16900                     if (!nopad && toadd.length > 80) {
16901                         innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
16902                     }
16903                     innerHTML  += toadd;
16904                     
16905                     i++;
16906                     currentElementChild = currentElement.childNodes.item(i);
16907                     lastNode = '';
16908                     continue;
16909                 }
16910                 allText = false;
16911                 
16912                 innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
16913                     
16914                 // Recursively traverse the tree structure of the child node
16915                 innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
16916                 lastnode = currentElementChild.nodeName;
16917                 i++;
16918                 currentElementChild=currentElement.childNodes.item(i);
16919             }
16920             
16921             ret += innerHTML;
16922             
16923             if (!allText) {
16924                     // The remaining code is mostly for formatting the tree
16925                 ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
16926             }
16927             
16928             
16929             if (tagName) {
16930                 ret+= "</"+tagName+">";
16931             }
16932             return ret;
16933             
16934         }
16935     
16936     // hide stuff that is not compatible
16937     /**
16938      * @event blur
16939      * @hide
16940      */
16941     /**
16942      * @event change
16943      * @hide
16944      */
16945     /**
16946      * @event focus
16947      * @hide
16948      */
16949     /**
16950      * @event specialkey
16951      * @hide
16952      */
16953     /**
16954      * @cfg {String} fieldClass @hide
16955      */
16956     /**
16957      * @cfg {String} focusClass @hide
16958      */
16959     /**
16960      * @cfg {String} autoCreate @hide
16961      */
16962     /**
16963      * @cfg {String} inputType @hide
16964      */
16965     /**
16966      * @cfg {String} invalidClass @hide
16967      */
16968     /**
16969      * @cfg {String} invalidText @hide
16970      */
16971     /**
16972      * @cfg {String} msgFx @hide
16973      */
16974     /**
16975      * @cfg {String} validateOnBlur @hide
16976      */
16977 });
16978
16979 Roo.HtmlEditorCore.white = [
16980         'area', 'br', 'img', 'input', 'hr', 'wbr',
16981         
16982        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
16983        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
16984        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
16985        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
16986        'table',   'ul',         'xmp', 
16987        
16988        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
16989       'thead',   'tr', 
16990      
16991       'dir', 'menu', 'ol', 'ul', 'dl',
16992        
16993       'embed',  'object'
16994 ];
16995
16996
16997 Roo.HtmlEditorCore.black = [
16998     //    'embed',  'object', // enable - backend responsiblity to clean thiese
16999         'applet', // 
17000         'base',   'basefont', 'bgsound', 'blink',  'body', 
17001         'frame',  'frameset', 'head',    'html',   'ilayer', 
17002         'iframe', 'layer',  'link',     'meta',    'object',   
17003         'script', 'style' ,'title',  'xml' // clean later..
17004 ];
17005 Roo.HtmlEditorCore.clean = [
17006     'script', 'style', 'title', 'xml'
17007 ];
17008 Roo.HtmlEditorCore.remove = [
17009     'font'
17010 ];
17011 // attributes..
17012
17013 Roo.HtmlEditorCore.ablack = [
17014     'on'
17015 ];
17016     
17017 Roo.HtmlEditorCore.aclean = [ 
17018     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
17019 ];
17020
17021 // protocols..
17022 Roo.HtmlEditorCore.pwhite= [
17023         'http',  'https',  'mailto'
17024 ];
17025
17026 // white listed style attributes.
17027 Roo.HtmlEditorCore.cwhite= [
17028       //  'text-align', /// default is to allow most things..
17029       
17030          
17031 //        'font-size'//??
17032 ];
17033
17034 // black listed style attributes.
17035 Roo.HtmlEditorCore.cblack= [
17036       //  'font-size' -- this can be set by the project 
17037 ];
17038
17039
17040 Roo.HtmlEditorCore.swapCodes   =[ 
17041     [    8211, "--" ], 
17042     [    8212, "--" ], 
17043     [    8216,  "'" ],  
17044     [    8217, "'" ],  
17045     [    8220, '"' ],  
17046     [    8221, '"' ],  
17047     [    8226, "*" ],  
17048     [    8230, "..." ]
17049 ]; 
17050
17051     /*
17052  * - LGPL
17053  *
17054  * HtmlEditor
17055  * 
17056  */
17057
17058 /**
17059  * @class Roo.bootstrap.HtmlEditor
17060  * @extends Roo.bootstrap.TextArea
17061  * Bootstrap HtmlEditor class
17062
17063  * @constructor
17064  * Create a new HtmlEditor
17065  * @param {Object} config The config object
17066  */
17067
17068 Roo.bootstrap.HtmlEditor = function(config){
17069     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17070     if (!this.toolbars) {
17071         this.toolbars = [];
17072     }
17073     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17074     this.addEvents({
17075             /**
17076              * @event initialize
17077              * Fires when the editor is fully initialized (including the iframe)
17078              * @param {HtmlEditor} this
17079              */
17080             initialize: true,
17081             /**
17082              * @event activate
17083              * Fires when the editor is first receives the focus. Any insertion must wait
17084              * until after this event.
17085              * @param {HtmlEditor} this
17086              */
17087             activate: true,
17088              /**
17089              * @event beforesync
17090              * Fires before the textarea is updated with content from the editor iframe. Return false
17091              * to cancel the sync.
17092              * @param {HtmlEditor} this
17093              * @param {String} html
17094              */
17095             beforesync: true,
17096              /**
17097              * @event beforepush
17098              * Fires before the iframe editor is updated with content from the textarea. Return false
17099              * to cancel the push.
17100              * @param {HtmlEditor} this
17101              * @param {String} html
17102              */
17103             beforepush: true,
17104              /**
17105              * @event sync
17106              * Fires when the textarea is updated with content from the editor iframe.
17107              * @param {HtmlEditor} this
17108              * @param {String} html
17109              */
17110             sync: true,
17111              /**
17112              * @event push
17113              * Fires when the iframe editor is updated with content from the textarea.
17114              * @param {HtmlEditor} this
17115              * @param {String} html
17116              */
17117             push: true,
17118              /**
17119              * @event editmodechange
17120              * Fires when the editor switches edit modes
17121              * @param {HtmlEditor} this
17122              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17123              */
17124             editmodechange: true,
17125             /**
17126              * @event editorevent
17127              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17128              * @param {HtmlEditor} this
17129              */
17130             editorevent: true,
17131             /**
17132              * @event firstfocus
17133              * Fires when on first focus - needed by toolbars..
17134              * @param {HtmlEditor} this
17135              */
17136             firstfocus: true,
17137             /**
17138              * @event autosave
17139              * Auto save the htmlEditor value as a file into Events
17140              * @param {HtmlEditor} this
17141              */
17142             autosave: true,
17143             /**
17144              * @event savedpreview
17145              * preview the saved version of htmlEditor
17146              * @param {HtmlEditor} this
17147              */
17148             savedpreview: true
17149         });
17150 };
17151
17152
17153 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
17154     
17155     
17156       /**
17157      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17158      */
17159     toolbars : false,
17160    
17161      /**
17162      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17163      *                        Roo.resizable.
17164      */
17165     resizable : false,
17166      /**
17167      * @cfg {Number} height (in pixels)
17168      */   
17169     height: 300,
17170    /**
17171      * @cfg {Number} width (in pixels)
17172      */   
17173     width: false,
17174     
17175     /**
17176      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17177      * 
17178      */
17179     stylesheets: false,
17180     
17181     // id of frame..
17182     frameId: false,
17183     
17184     // private properties
17185     validationEvent : false,
17186     deferHeight: true,
17187     initialized : false,
17188     activated : false,
17189     
17190     onFocus : Roo.emptyFn,
17191     iframePad:3,
17192     hideMode:'offsets',
17193     
17194     
17195     tbContainer : false,
17196     
17197     toolbarContainer :function() {
17198         return this.wrap.select('.x-html-editor-tb',true).first();
17199     },
17200
17201     /**
17202      * Protected method that will not generally be called directly. It
17203      * is called when the editor creates its toolbar. Override this method if you need to
17204      * add custom toolbar buttons.
17205      * @param {HtmlEditor} editor
17206      */
17207     createToolbar : function(){
17208         
17209         Roo.log("create toolbars");
17210         
17211         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17212         this.toolbars[0].render(this.toolbarContainer());
17213         
17214         return;
17215         
17216 //        if (!editor.toolbars || !editor.toolbars.length) {
17217 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17218 //        }
17219 //        
17220 //        for (var i =0 ; i < editor.toolbars.length;i++) {
17221 //            editor.toolbars[i] = Roo.factory(
17222 //                    typeof(editor.toolbars[i]) == 'string' ?
17223 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
17224 //                Roo.bootstrap.HtmlEditor);
17225 //            editor.toolbars[i].init(editor);
17226 //        }
17227     },
17228
17229      
17230     // private
17231     onRender : function(ct, position)
17232     {
17233        // Roo.log("Call onRender: " + this.xtype);
17234         var _t = this;
17235         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17236       
17237         this.wrap = this.inputEl().wrap({
17238             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17239         });
17240         
17241         this.editorcore.onRender(ct, position);
17242          
17243         if (this.resizable) {
17244             this.resizeEl = new Roo.Resizable(this.wrap, {
17245                 pinned : true,
17246                 wrap: true,
17247                 dynamic : true,
17248                 minHeight : this.height,
17249                 height: this.height,
17250                 handles : this.resizable,
17251                 width: this.width,
17252                 listeners : {
17253                     resize : function(r, w, h) {
17254                         _t.onResize(w,h); // -something
17255                     }
17256                 }
17257             });
17258             
17259         }
17260         this.createToolbar(this);
17261        
17262         
17263         if(!this.width && this.resizable){
17264             this.setSize(this.wrap.getSize());
17265         }
17266         if (this.resizeEl) {
17267             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17268             // should trigger onReize..
17269         }
17270         
17271     },
17272
17273     // private
17274     onResize : function(w, h)
17275     {
17276         Roo.log('resize: ' +w + ',' + h );
17277         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17278         var ew = false;
17279         var eh = false;
17280         
17281         if(this.inputEl() ){
17282             if(typeof w == 'number'){
17283                 var aw = w - this.wrap.getFrameWidth('lr');
17284                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17285                 ew = aw;
17286             }
17287             if(typeof h == 'number'){
17288                  var tbh = -11;  // fixme it needs to tool bar size!
17289                 for (var i =0; i < this.toolbars.length;i++) {
17290                     // fixme - ask toolbars for heights?
17291                     tbh += this.toolbars[i].el.getHeight();
17292                     //if (this.toolbars[i].footer) {
17293                     //    tbh += this.toolbars[i].footer.el.getHeight();
17294                     //}
17295                 }
17296               
17297                 
17298                 
17299                 
17300                 
17301                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17302                 ah -= 5; // knock a few pixes off for look..
17303                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17304                 var eh = ah;
17305             }
17306         }
17307         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17308         this.editorcore.onResize(ew,eh);
17309         
17310     },
17311
17312     /**
17313      * Toggles the editor between standard and source edit mode.
17314      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17315      */
17316     toggleSourceEdit : function(sourceEditMode)
17317     {
17318         this.editorcore.toggleSourceEdit(sourceEditMode);
17319         
17320         if(this.editorcore.sourceEditMode){
17321             Roo.log('editor - showing textarea');
17322             
17323 //            Roo.log('in');
17324 //            Roo.log(this.syncValue());
17325             this.syncValue();
17326             this.inputEl().removeClass(['hide', 'x-hidden']);
17327             this.inputEl().dom.removeAttribute('tabIndex');
17328             this.inputEl().focus();
17329         }else{
17330             Roo.log('editor - hiding textarea');
17331 //            Roo.log('out')
17332 //            Roo.log(this.pushValue()); 
17333             this.pushValue();
17334             
17335             this.inputEl().addClass(['hide', 'x-hidden']);
17336             this.inputEl().dom.setAttribute('tabIndex', -1);
17337             //this.deferFocus();
17338         }
17339          
17340         if(this.resizable){
17341             this.setSize(this.wrap.getSize());
17342         }
17343         
17344         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17345     },
17346  
17347     // private (for BoxComponent)
17348     adjustSize : Roo.BoxComponent.prototype.adjustSize,
17349
17350     // private (for BoxComponent)
17351     getResizeEl : function(){
17352         return this.wrap;
17353     },
17354
17355     // private (for BoxComponent)
17356     getPositionEl : function(){
17357         return this.wrap;
17358     },
17359
17360     // private
17361     initEvents : function(){
17362         this.originalValue = this.getValue();
17363     },
17364
17365 //    /**
17366 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17367 //     * @method
17368 //     */
17369 //    markInvalid : Roo.emptyFn,
17370 //    /**
17371 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17372 //     * @method
17373 //     */
17374 //    clearInvalid : Roo.emptyFn,
17375
17376     setValue : function(v){
17377         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17378         this.editorcore.pushValue();
17379     },
17380
17381      
17382     // private
17383     deferFocus : function(){
17384         this.focus.defer(10, this);
17385     },
17386
17387     // doc'ed in Field
17388     focus : function(){
17389         this.editorcore.focus();
17390         
17391     },
17392       
17393
17394     // private
17395     onDestroy : function(){
17396         
17397         
17398         
17399         if(this.rendered){
17400             
17401             for (var i =0; i < this.toolbars.length;i++) {
17402                 // fixme - ask toolbars for heights?
17403                 this.toolbars[i].onDestroy();
17404             }
17405             
17406             this.wrap.dom.innerHTML = '';
17407             this.wrap.remove();
17408         }
17409     },
17410
17411     // private
17412     onFirstFocus : function(){
17413         //Roo.log("onFirstFocus");
17414         this.editorcore.onFirstFocus();
17415          for (var i =0; i < this.toolbars.length;i++) {
17416             this.toolbars[i].onFirstFocus();
17417         }
17418         
17419     },
17420     
17421     // private
17422     syncValue : function()
17423     {   
17424         this.editorcore.syncValue();
17425     },
17426     
17427     pushValue : function()
17428     {   
17429         this.editorcore.pushValue();
17430     }
17431      
17432     
17433     // hide stuff that is not compatible
17434     /**
17435      * @event blur
17436      * @hide
17437      */
17438     /**
17439      * @event change
17440      * @hide
17441      */
17442     /**
17443      * @event focus
17444      * @hide
17445      */
17446     /**
17447      * @event specialkey
17448      * @hide
17449      */
17450     /**
17451      * @cfg {String} fieldClass @hide
17452      */
17453     /**
17454      * @cfg {String} focusClass @hide
17455      */
17456     /**
17457      * @cfg {String} autoCreate @hide
17458      */
17459     /**
17460      * @cfg {String} inputType @hide
17461      */
17462     /**
17463      * @cfg {String} invalidClass @hide
17464      */
17465     /**
17466      * @cfg {String} invalidText @hide
17467      */
17468     /**
17469      * @cfg {String} msgFx @hide
17470      */
17471     /**
17472      * @cfg {String} validateOnBlur @hide
17473      */
17474 });
17475  
17476     
17477    
17478    
17479    
17480       
17481 Roo.namespace('Roo.bootstrap.htmleditor');
17482 /**
17483  * @class Roo.bootstrap.HtmlEditorToolbar1
17484  * Basic Toolbar
17485  * 
17486  * Usage:
17487  *
17488  new Roo.bootstrap.HtmlEditor({
17489     ....
17490     toolbars : [
17491         new Roo.bootstrap.HtmlEditorToolbar1({
17492             disable : { fonts: 1 , format: 1, ..., ... , ...],
17493             btns : [ .... ]
17494         })
17495     }
17496      
17497  * 
17498  * @cfg {Object} disable List of elements to disable..
17499  * @cfg {Array} btns List of additional buttons.
17500  * 
17501  * 
17502  * NEEDS Extra CSS? 
17503  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17504  */
17505  
17506 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17507 {
17508     
17509     Roo.apply(this, config);
17510     
17511     // default disabled, based on 'good practice'..
17512     this.disable = this.disable || {};
17513     Roo.applyIf(this.disable, {
17514         fontSize : true,
17515         colors : true,
17516         specialElements : true
17517     });
17518     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17519     
17520     this.editor = config.editor;
17521     this.editorcore = config.editor.editorcore;
17522     
17523     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17524     
17525     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17526     // dont call parent... till later.
17527 }
17528 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
17529      
17530     bar : true,
17531     
17532     editor : false,
17533     editorcore : false,
17534     
17535     
17536     formats : [
17537         "p" ,  
17538         "h1","h2","h3","h4","h5","h6", 
17539         "pre", "code", 
17540         "abbr", "acronym", "address", "cite", "samp", "var",
17541         'div','span'
17542     ],
17543     
17544     onRender : function(ct, position)
17545     {
17546        // Roo.log("Call onRender: " + this.xtype);
17547         
17548        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17549        Roo.log(this.el);
17550        this.el.dom.style.marginBottom = '0';
17551        var _this = this;
17552        var editorcore = this.editorcore;
17553        var editor= this.editor;
17554        
17555        var children = [];
17556        var btn = function(id,cmd , toggle, handler){
17557        
17558             var  event = toggle ? 'toggle' : 'click';
17559        
17560             var a = {
17561                 size : 'sm',
17562                 xtype: 'Button',
17563                 xns: Roo.bootstrap,
17564                 glyphicon : id,
17565                 cmd : id || cmd,
17566                 enableToggle:toggle !== false,
17567                 //html : 'submit'
17568                 pressed : toggle ? false : null,
17569                 listeners : {}
17570             }
17571             a.listeners[toggle ? 'toggle' : 'click'] = function() {
17572                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
17573             }
17574             children.push(a);
17575             return a;
17576        }
17577         
17578         var style = {
17579                 xtype: 'Button',
17580                 size : 'sm',
17581                 xns: Roo.bootstrap,
17582                 glyphicon : 'font',
17583                 //html : 'submit'
17584                 menu : {
17585                     xtype: 'Menu',
17586                     xns: Roo.bootstrap,
17587                     items:  []
17588                 }
17589         };
17590         Roo.each(this.formats, function(f) {
17591             style.menu.items.push({
17592                 xtype :'MenuItem',
17593                 xns: Roo.bootstrap,
17594                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17595                 tagname : f,
17596                 listeners : {
17597                     click : function()
17598                     {
17599                         editorcore.insertTag(this.tagname);
17600                         editor.focus();
17601                     }
17602                 }
17603                 
17604             });
17605         });
17606          children.push(style);   
17607             
17608             
17609         btn('bold',false,true);
17610         btn('italic',false,true);
17611         btn('align-left', 'justifyleft',true);
17612         btn('align-center', 'justifycenter',true);
17613         btn('align-right' , 'justifyright',true);
17614         btn('link', false, false, function(btn) {
17615             //Roo.log("create link?");
17616             var url = prompt(this.createLinkText, this.defaultLinkValue);
17617             if(url && url != 'http:/'+'/'){
17618                 this.editorcore.relayCmd('createlink', url);
17619             }
17620         }),
17621         btn('list','insertunorderedlist',true);
17622         btn('pencil', false,true, function(btn){
17623                 Roo.log(this);
17624                 
17625                 this.toggleSourceEdit(btn.pressed);
17626         });
17627         /*
17628         var cog = {
17629                 xtype: 'Button',
17630                 size : 'sm',
17631                 xns: Roo.bootstrap,
17632                 glyphicon : 'cog',
17633                 //html : 'submit'
17634                 menu : {
17635                     xtype: 'Menu',
17636                     xns: Roo.bootstrap,
17637                     items:  []
17638                 }
17639         };
17640         
17641         cog.menu.items.push({
17642             xtype :'MenuItem',
17643             xns: Roo.bootstrap,
17644             html : Clean styles,
17645             tagname : f,
17646             listeners : {
17647                 click : function()
17648                 {
17649                     editorcore.insertTag(this.tagname);
17650                     editor.focus();
17651                 }
17652             }
17653             
17654         });
17655        */
17656         
17657          
17658        this.xtype = 'NavSimplebar';
17659         
17660         for(var i=0;i< children.length;i++) {
17661             
17662             this.buttons.add(this.addxtypeChild(children[i]));
17663             
17664         }
17665         
17666         editor.on('editorevent', this.updateToolbar, this);
17667     },
17668     onBtnClick : function(id)
17669     {
17670        this.editorcore.relayCmd(id);
17671        this.editorcore.focus();
17672     },
17673     
17674     /**
17675      * Protected method that will not generally be called directly. It triggers
17676      * a toolbar update by reading the markup state of the current selection in the editor.
17677      */
17678     updateToolbar: function(){
17679
17680         if(!this.editorcore.activated){
17681             this.editor.onFirstFocus(); // is this neeed?
17682             return;
17683         }
17684
17685         var btns = this.buttons; 
17686         var doc = this.editorcore.doc;
17687         btns.get('bold').setActive(doc.queryCommandState('bold'));
17688         btns.get('italic').setActive(doc.queryCommandState('italic'));
17689         //btns.get('underline').setActive(doc.queryCommandState('underline'));
17690         
17691         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17692         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17693         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17694         
17695         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17696         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17697          /*
17698         
17699         var ans = this.editorcore.getAllAncestors();
17700         if (this.formatCombo) {
17701             
17702             
17703             var store = this.formatCombo.store;
17704             this.formatCombo.setValue("");
17705             for (var i =0; i < ans.length;i++) {
17706                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17707                     // select it..
17708                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17709                     break;
17710                 }
17711             }
17712         }
17713         
17714         
17715         
17716         // hides menus... - so this cant be on a menu...
17717         Roo.bootstrap.MenuMgr.hideAll();
17718         */
17719         Roo.bootstrap.MenuMgr.hideAll();
17720         //this.editorsyncValue();
17721     },
17722     onFirstFocus: function() {
17723         this.buttons.each(function(item){
17724            item.enable();
17725         });
17726     },
17727     toggleSourceEdit : function(sourceEditMode){
17728         
17729           
17730         if(sourceEditMode){
17731             Roo.log("disabling buttons");
17732            this.buttons.each( function(item){
17733                 if(item.cmd != 'pencil'){
17734                     item.disable();
17735                 }
17736             });
17737           
17738         }else{
17739             Roo.log("enabling buttons");
17740             if(this.editorcore.initialized){
17741                 this.buttons.each( function(item){
17742                     item.enable();
17743                 });
17744             }
17745             
17746         }
17747         Roo.log("calling toggole on editor");
17748         // tell the editor that it's been pressed..
17749         this.editor.toggleSourceEdit(sourceEditMode);
17750        
17751     }
17752 });
17753
17754
17755
17756
17757
17758 /**
17759  * @class Roo.bootstrap.Table.AbstractSelectionModel
17760  * @extends Roo.util.Observable
17761  * Abstract base class for grid SelectionModels.  It provides the interface that should be
17762  * implemented by descendant classes.  This class should not be directly instantiated.
17763  * @constructor
17764  */
17765 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17766     this.locked = false;
17767     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17768 };
17769
17770
17771 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
17772     /** @ignore Called by the grid automatically. Do not call directly. */
17773     init : function(grid){
17774         this.grid = grid;
17775         this.initEvents();
17776     },
17777
17778     /**
17779      * Locks the selections.
17780      */
17781     lock : function(){
17782         this.locked = true;
17783     },
17784
17785     /**
17786      * Unlocks the selections.
17787      */
17788     unlock : function(){
17789         this.locked = false;
17790     },
17791
17792     /**
17793      * Returns true if the selections are locked.
17794      * @return {Boolean}
17795      */
17796     isLocked : function(){
17797         return this.locked;
17798     }
17799 });
17800 /**
17801  * @extends Roo.bootstrap.Table.AbstractSelectionModel
17802  * @class Roo.bootstrap.Table.RowSelectionModel
17803  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17804  * It supports multiple selections and keyboard selection/navigation. 
17805  * @constructor
17806  * @param {Object} config
17807  */
17808
17809 Roo.bootstrap.Table.RowSelectionModel = function(config){
17810     Roo.apply(this, config);
17811     this.selections = new Roo.util.MixedCollection(false, function(o){
17812         return o.id;
17813     });
17814
17815     this.last = false;
17816     this.lastActive = false;
17817
17818     this.addEvents({
17819         /**
17820              * @event selectionchange
17821              * Fires when the selection changes
17822              * @param {SelectionModel} this
17823              */
17824             "selectionchange" : true,
17825         /**
17826              * @event afterselectionchange
17827              * Fires after the selection changes (eg. by key press or clicking)
17828              * @param {SelectionModel} this
17829              */
17830             "afterselectionchange" : true,
17831         /**
17832              * @event beforerowselect
17833              * Fires when a row is selected being selected, return false to cancel.
17834              * @param {SelectionModel} this
17835              * @param {Number} rowIndex The selected index
17836              * @param {Boolean} keepExisting False if other selections will be cleared
17837              */
17838             "beforerowselect" : true,
17839         /**
17840              * @event rowselect
17841              * Fires when a row is selected.
17842              * @param {SelectionModel} this
17843              * @param {Number} rowIndex The selected index
17844              * @param {Roo.data.Record} r The record
17845              */
17846             "rowselect" : true,
17847         /**
17848              * @event rowdeselect
17849              * Fires when a row is deselected.
17850              * @param {SelectionModel} this
17851              * @param {Number} rowIndex The selected index
17852              */
17853         "rowdeselect" : true
17854     });
17855     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17856     this.locked = false;
17857 };
17858
17859 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
17860     /**
17861      * @cfg {Boolean} singleSelect
17862      * True to allow selection of only one row at a time (defaults to false)
17863      */
17864     singleSelect : false,
17865
17866     // private
17867     initEvents : function(){
17868
17869         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17870             this.grid.on("mousedown", this.handleMouseDown, this);
17871         }else{ // allow click to work like normal
17872             this.grid.on("rowclick", this.handleDragableRowClick, this);
17873         }
17874
17875         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17876             "up" : function(e){
17877                 if(!e.shiftKey){
17878                     this.selectPrevious(e.shiftKey);
17879                 }else if(this.last !== false && this.lastActive !== false){
17880                     var last = this.last;
17881                     this.selectRange(this.last,  this.lastActive-1);
17882                     this.grid.getView().focusRow(this.lastActive);
17883                     if(last !== false){
17884                         this.last = last;
17885                     }
17886                 }else{
17887                     this.selectFirstRow();
17888                 }
17889                 this.fireEvent("afterselectionchange", this);
17890             },
17891             "down" : function(e){
17892                 if(!e.shiftKey){
17893                     this.selectNext(e.shiftKey);
17894                 }else if(this.last !== false && this.lastActive !== false){
17895                     var last = this.last;
17896                     this.selectRange(this.last,  this.lastActive+1);
17897                     this.grid.getView().focusRow(this.lastActive);
17898                     if(last !== false){
17899                         this.last = last;
17900                     }
17901                 }else{
17902                     this.selectFirstRow();
17903                 }
17904                 this.fireEvent("afterselectionchange", this);
17905             },
17906             scope: this
17907         });
17908
17909         var view = this.grid.view;
17910         view.on("refresh", this.onRefresh, this);
17911         view.on("rowupdated", this.onRowUpdated, this);
17912         view.on("rowremoved", this.onRemove, this);
17913     },
17914
17915     // private
17916     onRefresh : function(){
17917         var ds = this.grid.dataSource, i, v = this.grid.view;
17918         var s = this.selections;
17919         s.each(function(r){
17920             if((i = ds.indexOfId(r.id)) != -1){
17921                 v.onRowSelect(i);
17922             }else{
17923                 s.remove(r);
17924             }
17925         });
17926     },
17927
17928     // private
17929     onRemove : function(v, index, r){
17930         this.selections.remove(r);
17931     },
17932
17933     // private
17934     onRowUpdated : function(v, index, r){
17935         if(this.isSelected(r)){
17936             v.onRowSelect(index);
17937         }
17938     },
17939
17940     /**
17941      * Select records.
17942      * @param {Array} records The records to select
17943      * @param {Boolean} keepExisting (optional) True to keep existing selections
17944      */
17945     selectRecords : function(records, keepExisting){
17946         if(!keepExisting){
17947             this.clearSelections();
17948         }
17949         var ds = this.grid.dataSource;
17950         for(var i = 0, len = records.length; i < len; i++){
17951             this.selectRow(ds.indexOf(records[i]), true);
17952         }
17953     },
17954
17955     /**
17956      * Gets the number of selected rows.
17957      * @return {Number}
17958      */
17959     getCount : function(){
17960         return this.selections.length;
17961     },
17962
17963     /**
17964      * Selects the first row in the grid.
17965      */
17966     selectFirstRow : function(){
17967         this.selectRow(0);
17968     },
17969
17970     /**
17971      * Select the last row.
17972      * @param {Boolean} keepExisting (optional) True to keep existing selections
17973      */
17974     selectLastRow : function(keepExisting){
17975         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17976     },
17977
17978     /**
17979      * Selects the row immediately following the last selected row.
17980      * @param {Boolean} keepExisting (optional) True to keep existing selections
17981      */
17982     selectNext : function(keepExisting){
17983         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17984             this.selectRow(this.last+1, keepExisting);
17985             this.grid.getView().focusRow(this.last);
17986         }
17987     },
17988
17989     /**
17990      * Selects the row that precedes the last selected row.
17991      * @param {Boolean} keepExisting (optional) True to keep existing selections
17992      */
17993     selectPrevious : function(keepExisting){
17994         if(this.last){
17995             this.selectRow(this.last-1, keepExisting);
17996             this.grid.getView().focusRow(this.last);
17997         }
17998     },
17999
18000     /**
18001      * Returns the selected records
18002      * @return {Array} Array of selected records
18003      */
18004     getSelections : function(){
18005         return [].concat(this.selections.items);
18006     },
18007
18008     /**
18009      * Returns the first selected record.
18010      * @return {Record}
18011      */
18012     getSelected : function(){
18013         return this.selections.itemAt(0);
18014     },
18015
18016
18017     /**
18018      * Clears all selections.
18019      */
18020     clearSelections : function(fast){
18021         if(this.locked) return;
18022         if(fast !== true){
18023             var ds = this.grid.dataSource;
18024             var s = this.selections;
18025             s.each(function(r){
18026                 this.deselectRow(ds.indexOfId(r.id));
18027             }, this);
18028             s.clear();
18029         }else{
18030             this.selections.clear();
18031         }
18032         this.last = false;
18033     },
18034
18035
18036     /**
18037      * Selects all rows.
18038      */
18039     selectAll : function(){
18040         if(this.locked) return;
18041         this.selections.clear();
18042         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18043             this.selectRow(i, true);
18044         }
18045     },
18046
18047     /**
18048      * Returns True if there is a selection.
18049      * @return {Boolean}
18050      */
18051     hasSelection : function(){
18052         return this.selections.length > 0;
18053     },
18054
18055     /**
18056      * Returns True if the specified row is selected.
18057      * @param {Number/Record} record The record or index of the record to check
18058      * @return {Boolean}
18059      */
18060     isSelected : function(index){
18061         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18062         return (r && this.selections.key(r.id) ? true : false);
18063     },
18064
18065     /**
18066      * Returns True if the specified record id is selected.
18067      * @param {String} id The id of record to check
18068      * @return {Boolean}
18069      */
18070     isIdSelected : function(id){
18071         return (this.selections.key(id) ? true : false);
18072     },
18073
18074     // private
18075     handleMouseDown : function(e, t){
18076         var view = this.grid.getView(), rowIndex;
18077         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18078             return;
18079         };
18080         if(e.shiftKey && this.last !== false){
18081             var last = this.last;
18082             this.selectRange(last, rowIndex, e.ctrlKey);
18083             this.last = last; // reset the last
18084             view.focusRow(rowIndex);
18085         }else{
18086             var isSelected = this.isSelected(rowIndex);
18087             if(e.button !== 0 && isSelected){
18088                 view.focusRow(rowIndex);
18089             }else if(e.ctrlKey && isSelected){
18090                 this.deselectRow(rowIndex);
18091             }else if(!isSelected){
18092                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18093                 view.focusRow(rowIndex);
18094             }
18095         }
18096         this.fireEvent("afterselectionchange", this);
18097     },
18098     // private
18099     handleDragableRowClick :  function(grid, rowIndex, e) 
18100     {
18101         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18102             this.selectRow(rowIndex, false);
18103             grid.view.focusRow(rowIndex);
18104              this.fireEvent("afterselectionchange", this);
18105         }
18106     },
18107     
18108     /**
18109      * Selects multiple rows.
18110      * @param {Array} rows Array of the indexes of the row to select
18111      * @param {Boolean} keepExisting (optional) True to keep existing selections
18112      */
18113     selectRows : function(rows, keepExisting){
18114         if(!keepExisting){
18115             this.clearSelections();
18116         }
18117         for(var i = 0, len = rows.length; i < len; i++){
18118             this.selectRow(rows[i], true);
18119         }
18120     },
18121
18122     /**
18123      * Selects a range of rows. All rows in between startRow and endRow are also selected.
18124      * @param {Number} startRow The index of the first row in the range
18125      * @param {Number} endRow The index of the last row in the range
18126      * @param {Boolean} keepExisting (optional) True to retain existing selections
18127      */
18128     selectRange : function(startRow, endRow, keepExisting){
18129         if(this.locked) return;
18130         if(!keepExisting){
18131             this.clearSelections();
18132         }
18133         if(startRow <= endRow){
18134             for(var i = startRow; i <= endRow; i++){
18135                 this.selectRow(i, true);
18136             }
18137         }else{
18138             for(var i = startRow; i >= endRow; i--){
18139                 this.selectRow(i, true);
18140             }
18141         }
18142     },
18143
18144     /**
18145      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18146      * @param {Number} startRow The index of the first row in the range
18147      * @param {Number} endRow The index of the last row in the range
18148      */
18149     deselectRange : function(startRow, endRow, preventViewNotify){
18150         if(this.locked) return;
18151         for(var i = startRow; i <= endRow; i++){
18152             this.deselectRow(i, preventViewNotify);
18153         }
18154     },
18155
18156     /**
18157      * Selects a row.
18158      * @param {Number} row The index of the row to select
18159      * @param {Boolean} keepExisting (optional) True to keep existing selections
18160      */
18161     selectRow : function(index, keepExisting, preventViewNotify){
18162         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18163         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18164             if(!keepExisting || this.singleSelect){
18165                 this.clearSelections();
18166             }
18167             var r = this.grid.dataSource.getAt(index);
18168             this.selections.add(r);
18169             this.last = this.lastActive = index;
18170             if(!preventViewNotify){
18171                 this.grid.getView().onRowSelect(index);
18172             }
18173             this.fireEvent("rowselect", this, index, r);
18174             this.fireEvent("selectionchange", this);
18175         }
18176     },
18177
18178     /**
18179      * Deselects a row.
18180      * @param {Number} row The index of the row to deselect
18181      */
18182     deselectRow : function(index, preventViewNotify){
18183         if(this.locked) return;
18184         if(this.last == index){
18185             this.last = false;
18186         }
18187         if(this.lastActive == index){
18188             this.lastActive = false;
18189         }
18190         var r = this.grid.dataSource.getAt(index);
18191         this.selections.remove(r);
18192         if(!preventViewNotify){
18193             this.grid.getView().onRowDeselect(index);
18194         }
18195         this.fireEvent("rowdeselect", this, index);
18196         this.fireEvent("selectionchange", this);
18197     },
18198
18199     // private
18200     restoreLast : function(){
18201         if(this._last){
18202             this.last = this._last;
18203         }
18204     },
18205
18206     // private
18207     acceptsNav : function(row, col, cm){
18208         return !cm.isHidden(col) && cm.isCellEditable(col, row);
18209     },
18210
18211     // private
18212     onEditorKey : function(field, e){
18213         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18214         if(k == e.TAB){
18215             e.stopEvent();
18216             ed.completeEdit();
18217             if(e.shiftKey){
18218                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18219             }else{
18220                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18221             }
18222         }else if(k == e.ENTER && !e.ctrlKey){
18223             e.stopEvent();
18224             ed.completeEdit();
18225             if(e.shiftKey){
18226                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18227             }else{
18228                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18229             }
18230         }else if(k == e.ESC){
18231             ed.cancelEdit();
18232         }
18233         if(newCell){
18234             g.startEditing(newCell[0], newCell[1]);
18235         }
18236     }
18237 });/*
18238  * Based on:
18239  * Ext JS Library 1.1.1
18240  * Copyright(c) 2006-2007, Ext JS, LLC.
18241  *
18242  * Originally Released Under LGPL - original licence link has changed is not relivant.
18243  *
18244  * Fork - LGPL
18245  * <script type="text/javascript">
18246  */
18247  
18248 /**
18249  * @class Roo.bootstrap.PagingToolbar
18250  * @extends Roo.Row
18251  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18252  * @constructor
18253  * Create a new PagingToolbar
18254  * @param {Object} config The config object
18255  */
18256 Roo.bootstrap.PagingToolbar = function(config)
18257 {
18258     // old args format still supported... - xtype is prefered..
18259         // created from xtype...
18260     var ds = config.dataSource;
18261     this.toolbarItems = [];
18262     if (config.items) {
18263         this.toolbarItems = config.items;
18264 //        config.items = [];
18265     }
18266     
18267     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18268     this.ds = ds;
18269     this.cursor = 0;
18270     if (ds) { 
18271         this.bind(ds);
18272     }
18273     
18274     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18275     
18276 };
18277
18278 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18279     /**
18280      * @cfg {Roo.data.Store} dataSource
18281      * The underlying data store providing the paged data
18282      */
18283     /**
18284      * @cfg {String/HTMLElement/Element} container
18285      * container The id or element that will contain the toolbar
18286      */
18287     /**
18288      * @cfg {Boolean} displayInfo
18289      * True to display the displayMsg (defaults to false)
18290      */
18291     /**
18292      * @cfg {Number} pageSize
18293      * The number of records to display per page (defaults to 20)
18294      */
18295     pageSize: 20,
18296     /**
18297      * @cfg {String} displayMsg
18298      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18299      */
18300     displayMsg : 'Displaying {0} - {1} of {2}',
18301     /**
18302      * @cfg {String} emptyMsg
18303      * The message to display when no records are found (defaults to "No data to display")
18304      */
18305     emptyMsg : 'No data to display',
18306     /**
18307      * Customizable piece of the default paging text (defaults to "Page")
18308      * @type String
18309      */
18310     beforePageText : "Page",
18311     /**
18312      * Customizable piece of the default paging text (defaults to "of %0")
18313      * @type String
18314      */
18315     afterPageText : "of {0}",
18316     /**
18317      * Customizable piece of the default paging text (defaults to "First Page")
18318      * @type String
18319      */
18320     firstText : "First Page",
18321     /**
18322      * Customizable piece of the default paging text (defaults to "Previous Page")
18323      * @type String
18324      */
18325     prevText : "Previous Page",
18326     /**
18327      * Customizable piece of the default paging text (defaults to "Next Page")
18328      * @type String
18329      */
18330     nextText : "Next Page",
18331     /**
18332      * Customizable piece of the default paging text (defaults to "Last Page")
18333      * @type String
18334      */
18335     lastText : "Last Page",
18336     /**
18337      * Customizable piece of the default paging text (defaults to "Refresh")
18338      * @type String
18339      */
18340     refreshText : "Refresh",
18341
18342     buttons : false,
18343     // private
18344     onRender : function(ct, position) 
18345     {
18346         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18347         this.navgroup.parentId = this.id;
18348         this.navgroup.onRender(this.el, null);
18349         // add the buttons to the navgroup
18350         
18351         if(this.displayInfo){
18352             Roo.log(this.el.select('ul.navbar-nav',true).first());
18353             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18354             this.displayEl = this.el.select('.x-paging-info', true).first();
18355 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18356 //            this.displayEl = navel.el.select('span',true).first();
18357         }
18358         
18359         var _this = this;
18360         
18361         if(this.buttons){
18362             Roo.each(_this.buttons, function(e){
18363                Roo.factory(e).onRender(_this.el, null);
18364             });
18365         }
18366             
18367         Roo.each(_this.toolbarItems, function(e) {
18368             _this.navgroup.addItem(e);
18369         });
18370         
18371         this.first = this.navgroup.addItem({
18372             tooltip: this.firstText,
18373             cls: "prev",
18374             icon : 'fa fa-backward',
18375             disabled: true,
18376             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18377         });
18378         
18379         this.prev =  this.navgroup.addItem({
18380             tooltip: this.prevText,
18381             cls: "prev",
18382             icon : 'fa fa-step-backward',
18383             disabled: true,
18384             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
18385         });
18386     //this.addSeparator();
18387         
18388         
18389         var field = this.navgroup.addItem( {
18390             tagtype : 'span',
18391             cls : 'x-paging-position',
18392             
18393             html : this.beforePageText  +
18394                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18395                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
18396          } ); //?? escaped?
18397         
18398         this.field = field.el.select('input', true).first();
18399         this.field.on("keydown", this.onPagingKeydown, this);
18400         this.field.on("focus", function(){this.dom.select();});
18401     
18402     
18403         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
18404         //this.field.setHeight(18);
18405         //this.addSeparator();
18406         this.next = this.navgroup.addItem({
18407             tooltip: this.nextText,
18408             cls: "next",
18409             html : ' <i class="fa fa-step-forward">',
18410             disabled: true,
18411             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
18412         });
18413         this.last = this.navgroup.addItem({
18414             tooltip: this.lastText,
18415             icon : 'fa fa-forward',
18416             cls: "next",
18417             disabled: true,
18418             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
18419         });
18420     //this.addSeparator();
18421         this.loading = this.navgroup.addItem({
18422             tooltip: this.refreshText,
18423             icon: 'fa fa-refresh',
18424             
18425             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18426         });
18427
18428     },
18429
18430     // private
18431     updateInfo : function(){
18432         if(this.displayEl){
18433             var count = this.ds.getCount();
18434             var msg = count == 0 ?
18435                 this.emptyMsg :
18436                 String.format(
18437                     this.displayMsg,
18438                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
18439                 );
18440             this.displayEl.update(msg);
18441         }
18442     },
18443
18444     // private
18445     onLoad : function(ds, r, o){
18446        this.cursor = o.params ? o.params.start : 0;
18447        var d = this.getPageData(),
18448             ap = d.activePage,
18449             ps = d.pages;
18450         
18451        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18452        this.field.dom.value = ap;
18453        this.first.setDisabled(ap == 1);
18454        this.prev.setDisabled(ap == 1);
18455        this.next.setDisabled(ap == ps);
18456        this.last.setDisabled(ap == ps);
18457        this.loading.enable();
18458        this.updateInfo();
18459     },
18460
18461     // private
18462     getPageData : function(){
18463         var total = this.ds.getTotalCount();
18464         return {
18465             total : total,
18466             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18467             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18468         };
18469     },
18470
18471     // private
18472     onLoadError : function(){
18473         this.loading.enable();
18474     },
18475
18476     // private
18477     onPagingKeydown : function(e){
18478         var k = e.getKey();
18479         var d = this.getPageData();
18480         if(k == e.RETURN){
18481             var v = this.field.dom.value, pageNum;
18482             if(!v || isNaN(pageNum = parseInt(v, 10))){
18483                 this.field.dom.value = d.activePage;
18484                 return;
18485             }
18486             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18487             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18488             e.stopEvent();
18489         }
18490         else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
18491         {
18492           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18493           this.field.dom.value = pageNum;
18494           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18495           e.stopEvent();
18496         }
18497         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18498         {
18499           var v = this.field.dom.value, pageNum; 
18500           var increment = (e.shiftKey) ? 10 : 1;
18501           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18502             increment *= -1;
18503           if(!v || isNaN(pageNum = parseInt(v, 10))) {
18504             this.field.dom.value = d.activePage;
18505             return;
18506           }
18507           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18508           {
18509             this.field.dom.value = parseInt(v, 10) + increment;
18510             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18511             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18512           }
18513           e.stopEvent();
18514         }
18515     },
18516
18517     // private
18518     beforeLoad : function(){
18519         if(this.loading){
18520             this.loading.disable();
18521         }
18522     },
18523
18524     // private
18525     onClick : function(which){
18526         var ds = this.ds;
18527         if (!ds) {
18528             return;
18529         }
18530         switch(which){
18531             case "first":
18532                 ds.load({params:{start: 0, limit: this.pageSize}});
18533             break;
18534             case "prev":
18535                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18536             break;
18537             case "next":
18538                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18539             break;
18540             case "last":
18541                 var total = ds.getTotalCount();
18542                 var extra = total % this.pageSize;
18543                 var lastStart = extra ? (total - extra) : total-this.pageSize;
18544                 ds.load({params:{start: lastStart, limit: this.pageSize}});
18545             break;
18546             case "refresh":
18547                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18548             break;
18549         }
18550     },
18551
18552     /**
18553      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18554      * @param {Roo.data.Store} store The data store to unbind
18555      */
18556     unbind : function(ds){
18557         ds.un("beforeload", this.beforeLoad, this);
18558         ds.un("load", this.onLoad, this);
18559         ds.un("loadexception", this.onLoadError, this);
18560         ds.un("remove", this.updateInfo, this);
18561         ds.un("add", this.updateInfo, this);
18562         this.ds = undefined;
18563     },
18564
18565     /**
18566      * Binds the paging toolbar to the specified {@link Roo.data.Store}
18567      * @param {Roo.data.Store} store The data store to bind
18568      */
18569     bind : function(ds){
18570         ds.on("beforeload", this.beforeLoad, this);
18571         ds.on("load", this.onLoad, this);
18572         ds.on("loadexception", this.onLoadError, this);
18573         ds.on("remove", this.updateInfo, this);
18574         ds.on("add", this.updateInfo, this);
18575         this.ds = ds;
18576     }
18577 });/*
18578  * - LGPL
18579  *
18580  * element
18581  * 
18582  */
18583
18584 /**
18585  * @class Roo.bootstrap.MessageBar
18586  * @extends Roo.bootstrap.Component
18587  * Bootstrap MessageBar class
18588  * @cfg {String} html contents of the MessageBar
18589  * @cfg {String} weight (info | success | warning | danger) default info
18590  * @cfg {String} beforeClass insert the bar before the given class
18591  * @cfg {Boolean} closable (true | false) default false
18592  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18593  * 
18594  * @constructor
18595  * Create a new Element
18596  * @param {Object} config The config object
18597  */
18598
18599 Roo.bootstrap.MessageBar = function(config){
18600     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18601 };
18602
18603 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
18604     
18605     html: '',
18606     weight: 'info',
18607     closable: false,
18608     fixed: false,
18609     beforeClass: 'bootstrap-sticky-wrap',
18610     
18611     getAutoCreate : function(){
18612         
18613         var cfg = {
18614             tag: 'div',
18615             cls: 'alert alert-dismissable alert-' + this.weight,
18616             cn: [
18617                 {
18618                     tag: 'span',
18619                     cls: 'message',
18620                     html: this.html || ''
18621                 }
18622             ]
18623         }
18624         
18625         if(this.fixed){
18626             cfg.cls += ' alert-messages-fixed';
18627         }
18628         
18629         if(this.closable){
18630             cfg.cn.push({
18631                 tag: 'button',
18632                 cls: 'close',
18633                 html: 'x'
18634             });
18635         }
18636         
18637         return cfg;
18638     },
18639     
18640     onRender : function(ct, position)
18641     {
18642         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18643         
18644         if(!this.el){
18645             var cfg = Roo.apply({},  this.getAutoCreate());
18646             cfg.id = Roo.id();
18647             
18648             if (this.cls) {
18649                 cfg.cls += ' ' + this.cls;
18650             }
18651             if (this.style) {
18652                 cfg.style = this.style;
18653             }
18654             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18655             
18656             this.el.setVisibilityMode(Roo.Element.DISPLAY);
18657         }
18658         
18659         this.el.select('>button.close').on('click', this.hide, this);
18660         
18661     },
18662     
18663     show : function()
18664     {
18665         if (!this.rendered) {
18666             this.render();
18667         }
18668         
18669         this.el.show();
18670         
18671         this.fireEvent('show', this);
18672         
18673     },
18674     
18675     hide : function()
18676     {
18677         if (!this.rendered) {
18678             this.render();
18679         }
18680         
18681         this.el.hide();
18682         
18683         this.fireEvent('hide', this);
18684     },
18685     
18686     update : function()
18687     {
18688 //        var e = this.el.dom.firstChild;
18689 //        
18690 //        if(this.closable){
18691 //            e = e.nextSibling;
18692 //        }
18693 //        
18694 //        e.data = this.html || '';
18695
18696         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18697     }
18698    
18699 });
18700
18701  
18702
18703      /*
18704  * - LGPL
18705  *
18706  * Graph
18707  * 
18708  */
18709
18710
18711 /**
18712  * @class Roo.bootstrap.Graph
18713  * @extends Roo.bootstrap.Component
18714  * Bootstrap Graph class
18715 > Prameters
18716  -sm {number} sm 4
18717  -md {number} md 5
18718  @cfg {String} graphtype  bar | vbar | pie
18719  @cfg {number} g_x coodinator | centre x (pie)
18720  @cfg {number} g_y coodinator | centre y (pie)
18721  @cfg {number} g_r radius (pie)
18722  @cfg {number} g_height height of the chart (respected by all elements in the set)
18723  @cfg {number} g_width width of the chart (respected by all elements in the set)
18724  @cfg {Object} title The title of the chart
18725     
18726  -{Array}  values
18727  -opts (object) options for the chart 
18728      o {
18729      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18730      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18731      o vgutter (number)
18732      o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
18733      o stacked (boolean) whether or not to tread values as in a stacked bar chart
18734      o to
18735      o stretch (boolean)
18736      o }
18737  -opts (object) options for the pie
18738      o{
18739      o cut
18740      o startAngle (number)
18741      o endAngle (number)
18742      } 
18743  *
18744  * @constructor
18745  * Create a new Input
18746  * @param {Object} config The config object
18747  */
18748
18749 Roo.bootstrap.Graph = function(config){
18750     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18751     
18752     this.addEvents({
18753         // img events
18754         /**
18755          * @event click
18756          * The img click event for the img.
18757          * @param {Roo.EventObject} e
18758          */
18759         "click" : true
18760     });
18761 };
18762
18763 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
18764     
18765     sm: 4,
18766     md: 5,
18767     graphtype: 'bar',
18768     g_height: 250,
18769     g_width: 400,
18770     g_x: 50,
18771     g_y: 50,
18772     g_r: 30,
18773     opts:{
18774         //g_colors: this.colors,
18775         g_type: 'soft',
18776         g_gutter: '20%'
18777
18778     },
18779     title : false,
18780
18781     getAutoCreate : function(){
18782         
18783         var cfg = {
18784             tag: 'div',
18785             html : null
18786         }
18787         
18788         
18789         return  cfg;
18790     },
18791
18792     onRender : function(ct,position){
18793         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18794         this.raphael = Raphael(this.el.dom);
18795         
18796                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18797                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18798                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18799                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18800                 /*
18801                 r.text(160, 10, "Single Series Chart").attr(txtattr);
18802                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18803                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18804                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18805                 
18806                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18807                 r.barchart(330, 10, 300, 220, data1);
18808                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18809                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18810                 */
18811                 
18812                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18813                 // r.barchart(30, 30, 560, 250,  xdata, {
18814                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18815                 //     axis : "0 0 1 1",
18816                 //     axisxlabels :  xdata
18817                 //     //yvalues : cols,
18818                    
18819                 // });
18820 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18821 //        
18822 //        this.load(null,xdata,{
18823 //                axis : "0 0 1 1",
18824 //                axisxlabels :  xdata
18825 //                });
18826
18827     },
18828
18829     load : function(graphtype,xdata,opts){
18830         this.raphael.clear();
18831         if(!graphtype) {
18832             graphtype = this.graphtype;
18833         }
18834         if(!opts){
18835             opts = this.opts;
18836         }
18837         var r = this.raphael,
18838             fin = function () {
18839                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18840             },
18841             fout = function () {
18842                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18843             },
18844             pfin = function() {
18845                 this.sector.stop();
18846                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18847
18848                 if (this.label) {
18849                     this.label[0].stop();
18850                     this.label[0].attr({ r: 7.5 });
18851                     this.label[1].attr({ "font-weight": 800 });
18852                 }
18853             },
18854             pfout = function() {
18855                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18856
18857                 if (this.label) {
18858                     this.label[0].animate({ r: 5 }, 500, "bounce");
18859                     this.label[1].attr({ "font-weight": 400 });
18860                 }
18861             };
18862
18863         switch(graphtype){
18864             case 'bar':
18865                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18866                 break;
18867             case 'hbar':
18868                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18869                 break;
18870             case 'pie':
18871 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
18872 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18873 //            
18874                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18875                 
18876                 break;
18877
18878         }
18879         
18880         if(this.title){
18881             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18882         }
18883         
18884     },
18885     
18886     setTitle: function(o)
18887     {
18888         this.title = o;
18889     },
18890     
18891     initEvents: function() {
18892         
18893         if(!this.href){
18894             this.el.on('click', this.onClick, this);
18895         }
18896     },
18897     
18898     onClick : function(e)
18899     {
18900         Roo.log('img onclick');
18901         this.fireEvent('click', this, e);
18902     }
18903    
18904 });
18905
18906  
18907 /*
18908  * - LGPL
18909  *
18910  * numberBox
18911  * 
18912  */
18913 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18914
18915 /**
18916  * @class Roo.bootstrap.dash.NumberBox
18917  * @extends Roo.bootstrap.Component
18918  * Bootstrap NumberBox class
18919  * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18920  * @cfg {String} headline Box headline
18921  * @cfg {String} content Box content
18922  * @cfg {String} icon Box icon
18923  * @cfg {String} footer Footer text
18924  * @cfg {String} fhref Footer href
18925  * 
18926  * @constructor
18927  * Create a new NumberBox
18928  * @param {Object} config The config object
18929  */
18930
18931
18932 Roo.bootstrap.dash.NumberBox = function(config){
18933     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18934     
18935 };
18936
18937 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
18938     
18939     bgcolor : 'aqua',
18940     headline : '',
18941     content : '',
18942     icon : '',
18943     footer : '',
18944     fhref : '',
18945     ficon : '',
18946     
18947     getAutoCreate : function(){
18948         
18949         var cfg = {
18950             tag : 'div',
18951             cls : 'small-box bg-' + this.bgcolor,
18952             cn : [
18953                 {
18954                     tag : 'div',
18955                     cls : 'inner',
18956                     cn :[
18957                         {
18958                             tag : 'h3',
18959                             cls : 'roo-headline',
18960                             html : this.headline
18961                         },
18962                         {
18963                             tag : 'p',
18964                             cls : 'roo-content',
18965                             html : this.content
18966                         }
18967                     ]
18968                 }
18969             ]
18970         }
18971         
18972         if(this.icon){
18973             cfg.cn.push({
18974                 tag : 'div',
18975                 cls : 'icon',
18976                 cn :[
18977                     {
18978                         tag : 'i',
18979                         cls : 'ion ' + this.icon
18980                     }
18981                 ]
18982             });
18983         }
18984         
18985         if(this.footer){
18986             var footer = {
18987                 tag : 'a',
18988                 cls : 'small-box-footer',
18989                 href : this.fhref || '#',
18990                 html : this.footer
18991             };
18992             
18993             cfg.cn.push(footer);
18994             
18995         }
18996         
18997         return  cfg;
18998     },
18999
19000     onRender : function(ct,position){
19001         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19002
19003
19004        
19005                 
19006     },
19007
19008     setHeadline: function (value)
19009     {
19010         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19011     },
19012     
19013     setFooter: function (value, href)
19014     {
19015         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19016         
19017         if(href){
19018             this.el.select('a.small-box-footer',true).first().attr('href', href);
19019         }
19020         
19021     },
19022
19023     setContent: function (value)
19024     {
19025         this.el.select('.roo-content',true).first().dom.innerHTML = value;
19026     },
19027
19028     initEvents: function() 
19029     {   
19030         
19031     }
19032     
19033 });
19034
19035  
19036 /*
19037  * - LGPL
19038  *
19039  * TabBox
19040  * 
19041  */
19042 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19043
19044 /**
19045  * @class Roo.bootstrap.dash.TabBox
19046  * @extends Roo.bootstrap.Component
19047  * Bootstrap TabBox class
19048  * @cfg {String} title Title of the TabBox
19049  * @cfg {String} icon Icon of the TabBox
19050  * 
19051  * @constructor
19052  * Create a new TabBox
19053  * @param {Object} config The config object
19054  */
19055
19056
19057 Roo.bootstrap.dash.TabBox = function(config){
19058     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19059     
19060 };
19061
19062 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
19063
19064     title : '',
19065     icon : false,
19066     
19067     getChildContainer : function()
19068     {
19069         return this.el.select('.tab-content', true).first();
19070     },
19071     
19072     getAutoCreate : function(){
19073         
19074         var header = {
19075             tag: 'li',
19076             cls: 'pull-left header',
19077             html: this.title,
19078             cn : []
19079         };
19080         
19081         if(this.icon){
19082             header.cn.push({
19083                 tag: 'i',
19084                 cls: 'fa ' + this.icon
19085             });
19086         }
19087         
19088         
19089         var cfg = {
19090             tag: 'div',
19091             cls: 'nav-tabs-custom',
19092             cn: [
19093                 {
19094                     tag: 'ul',
19095                     cls: 'nav nav-tabs pull-right',
19096                     cn: [
19097                         header
19098                     ]
19099                 },
19100                 {
19101                     tag: 'div',
19102                     cls: 'tab-content no-padding',
19103                     cn: []
19104                 }
19105             ]
19106         }
19107
19108         return  cfg;
19109     },
19110     
19111     setTitle : function(value)
19112     {
19113         this.el.select('.header', true).first().dom.innerHTML = value;
19114     }
19115     
19116 });
19117
19118  
19119 /*
19120  * - LGPL
19121  *
19122  * Tab pane
19123  * 
19124  */
19125 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19126 /**
19127  * @class Roo.bootstrap.TabPane
19128  * @extends Roo.bootstrap.Component
19129  * Bootstrap TabPane class
19130  * @cfg {Boolean} active (false | true) Default false
19131
19132  * 
19133  * @constructor
19134  * Create a new TabPane
19135  * @param {Object} config The config object
19136  */
19137
19138 Roo.bootstrap.dash.TabPane = function(config){
19139     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19140     
19141 };
19142
19143 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
19144     
19145     active : false,
19146 //    
19147 //    getBox : function()
19148 //    {
19149 //        return this.el.findParent('.nav-tabs-custom', false, true);
19150 //    },
19151     
19152     getAutoCreate : function() 
19153     {
19154         var cfg = {
19155             tag: 'div',
19156             cls: 'tab-pane'
19157         }
19158         
19159         if(this.active){
19160             cfg.cls += ' active';
19161         }
19162         
19163         return cfg;
19164     }
19165     
19166     
19167 });
19168
19169  
19170
19171
19172  /*
19173  * - LGPL
19174  *
19175  * menu
19176  * 
19177  */
19178 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19179
19180 /**
19181  * @class Roo.bootstrap.menu.Menu
19182  * @extends Roo.bootstrap.Component
19183  * Bootstrap Menu class - container for Menu
19184  * @cfg {String} html Text of the menu
19185  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19186  * @cfg {String} icon Font awesome icon
19187  * @cfg {String} pos Menu align to (top | bottom) default bottom
19188  * 
19189  * 
19190  * @constructor
19191  * Create a new Menu
19192  * @param {Object} config The config object
19193  */
19194
19195
19196 Roo.bootstrap.menu.Menu = function(config){
19197     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19198     
19199     this.addEvents({
19200         /**
19201          * @event beforeshow
19202          * Fires before this menu is displayed
19203          * @param {Roo.bootstrap.menu.Menu} this
19204          */
19205         beforeshow : true,
19206         /**
19207          * @event beforehide
19208          * Fires before this menu is hidden
19209          * @param {Roo.bootstrap.menu.Menu} this
19210          */
19211         beforehide : true,
19212         /**
19213          * @event show
19214          * Fires after this menu is displayed
19215          * @param {Roo.bootstrap.menu.Menu} this
19216          */
19217         show : true,
19218         /**
19219          * @event hide
19220          * Fires after this menu is hidden
19221          * @param {Roo.bootstrap.menu.Menu} this
19222          */
19223         hide : true,
19224         /**
19225          * @event click
19226          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19227          * @param {Roo.bootstrap.menu.Menu} this
19228          * @param {Roo.EventObject} e
19229          */
19230         click : true
19231     });
19232     
19233 };
19234
19235 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
19236     
19237     submenu : false,
19238     html : '',
19239     weight : 'default',
19240     icon : false,
19241     pos : 'bottom',
19242     
19243     
19244     getChildContainer : function() {
19245         if(this.isSubMenu){
19246             return this.el;
19247         }
19248         
19249         return this.el.select('ul.dropdown-menu', true).first();  
19250     },
19251     
19252     getAutoCreate : function()
19253     {
19254         var text = [
19255             {
19256                 tag : 'span',
19257                 cls : 'roo-menu-text',
19258                 html : this.html
19259             }
19260         ];
19261         
19262         if(this.icon){
19263             text.unshift({
19264                 tag : 'i',
19265                 cls : 'fa ' + this.icon
19266             })
19267         }
19268         
19269         
19270         var cfg = {
19271             tag : 'div',
19272             cls : 'btn-group',
19273             cn : [
19274                 {
19275                     tag : 'button',
19276                     cls : 'dropdown-button btn btn-' + this.weight,
19277                     cn : text
19278                 },
19279                 {
19280                     tag : 'button',
19281                     cls : 'dropdown-toggle btn btn-' + this.weight,
19282                     cn : [
19283                         {
19284                             tag : 'span',
19285                             cls : 'caret'
19286                         }
19287                     ]
19288                 },
19289                 {
19290                     tag : 'ul',
19291                     cls : 'dropdown-menu'
19292                 }
19293             ]
19294             
19295         };
19296         
19297         if(this.pos == 'top'){
19298             cfg.cls += ' dropup';
19299         }
19300         
19301         if(this.isSubMenu){
19302             cfg = {
19303                 tag : 'ul',
19304                 cls : 'dropdown-menu'
19305             }
19306         }
19307         
19308         return cfg;
19309     },
19310     
19311     onRender : function(ct, position)
19312     {
19313         this.isSubMenu = ct.hasClass('dropdown-submenu');
19314         
19315         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19316     },
19317     
19318     initEvents : function() 
19319     {
19320         if(this.isSubMenu){
19321             return;
19322         }
19323         
19324         this.hidden = true;
19325         
19326         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19327         this.triggerEl.on('click', this.onTriggerPress, this);
19328         
19329         this.buttonEl = this.el.select('button.dropdown-button', true).first();
19330         this.buttonEl.on('click', this.onClick, this);
19331         
19332     },
19333     
19334     list : function()
19335     {
19336         if(this.isSubMenu){
19337             return this.el;
19338         }
19339         
19340         return this.el.select('ul.dropdown-menu', true).first();
19341     },
19342     
19343     onClick : function(e)
19344     {
19345         this.fireEvent("click", this, e);
19346     },
19347     
19348     onTriggerPress  : function(e)
19349     {   
19350         if (this.isVisible()) {
19351             this.hide();
19352         } else {
19353             this.show();
19354         }
19355     },
19356     
19357     isVisible : function(){
19358         return !this.hidden;
19359     },
19360     
19361     show : function()
19362     {
19363         this.fireEvent("beforeshow", this);
19364         
19365         this.hidden = false;
19366         this.el.addClass('open');
19367         
19368         Roo.get(document).on("mouseup", this.onMouseUp, this);
19369         
19370         this.fireEvent("show", this);
19371         
19372         
19373     },
19374     
19375     hide : function()
19376     {
19377         this.fireEvent("beforehide", this);
19378         
19379         this.hidden = true;
19380         this.el.removeClass('open');
19381         
19382         Roo.get(document).un("mouseup", this.onMouseUp);
19383         
19384         this.fireEvent("hide", this);
19385     },
19386     
19387     onMouseUp : function()
19388     {
19389         this.hide();
19390     }
19391     
19392 });
19393
19394  
19395  /*
19396  * - LGPL
19397  *
19398  * menu item
19399  * 
19400  */
19401 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19402
19403 /**
19404  * @class Roo.bootstrap.menu.Item
19405  * @extends Roo.bootstrap.Component
19406  * Bootstrap MenuItem class
19407  * @cfg {Boolean} submenu (true | false) default false
19408  * @cfg {String} html text of the item
19409  * @cfg {String} href the link
19410  * @cfg {Boolean} disable (true | false) default false
19411  * @cfg {Boolean} preventDefault (true | false) default true
19412  * @cfg {String} icon Font awesome icon
19413  * @cfg {String} pos Submenu align to (left | right) default right 
19414  * 
19415  * 
19416  * @constructor
19417  * Create a new Item
19418  * @param {Object} config The config object
19419  */
19420
19421
19422 Roo.bootstrap.menu.Item = function(config){
19423     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19424     this.addEvents({
19425         /**
19426          * @event mouseover
19427          * Fires when the mouse is hovering over this menu
19428          * @param {Roo.bootstrap.menu.Item} this
19429          * @param {Roo.EventObject} e
19430          */
19431         mouseover : true,
19432         /**
19433          * @event mouseout
19434          * Fires when the mouse exits this menu
19435          * @param {Roo.bootstrap.menu.Item} this
19436          * @param {Roo.EventObject} e
19437          */
19438         mouseout : true,
19439         // raw events
19440         /**
19441          * @event click
19442          * The raw click event for the entire grid.
19443          * @param {Roo.EventObject} e
19444          */
19445         click : true
19446     });
19447 };
19448
19449 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
19450     
19451     submenu : false,
19452     href : '',
19453     html : '',
19454     preventDefault: true,
19455     disable : false,
19456     icon : false,
19457     pos : 'right',
19458     
19459     getAutoCreate : function()
19460     {
19461         var text = [
19462             {
19463                 tag : 'span',
19464                 cls : 'roo-menu-item-text',
19465                 html : this.html
19466             }
19467         ];
19468         
19469         if(this.icon){
19470             text.unshift({
19471                 tag : 'i',
19472                 cls : 'fa ' + this.icon
19473             })
19474         }
19475         
19476         var cfg = {
19477             tag : 'li',
19478             cn : [
19479                 {
19480                     tag : 'a',
19481                     href : this.href || '#',
19482                     cn : text
19483                 }
19484             ]
19485         };
19486         
19487         if(this.disable){
19488             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19489         }
19490         
19491         if(this.submenu){
19492             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19493             
19494             if(this.pos == 'left'){
19495                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19496             }
19497         }
19498         
19499         return cfg;
19500     },
19501     
19502     initEvents : function() 
19503     {
19504         this.el.on('mouseover', this.onMouseOver, this);
19505         this.el.on('mouseout', this.onMouseOut, this);
19506         
19507         this.el.select('a', true).first().on('click', this.onClick, this);
19508         
19509     },
19510     
19511     onClick : function(e)
19512     {
19513         if(this.preventDefault){
19514             e.preventDefault();
19515         }
19516         
19517         this.fireEvent("click", this, e);
19518     },
19519     
19520     onMouseOver : function(e)
19521     {
19522         if(this.submenu && this.pos == 'left'){
19523             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19524         }
19525         
19526         this.fireEvent("mouseover", this, e);
19527     },
19528     
19529     onMouseOut : function(e)
19530     {
19531         this.fireEvent("mouseout", this, e);
19532     }
19533 });
19534
19535  
19536
19537  /*
19538  * - LGPL
19539  *
19540  * menu separator
19541  * 
19542  */
19543 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19544
19545 /**
19546  * @class Roo.bootstrap.menu.Separator
19547  * @extends Roo.bootstrap.Component
19548  * Bootstrap Separator class
19549  * 
19550  * @constructor
19551  * Create a new Separator
19552  * @param {Object} config The config object
19553  */
19554
19555
19556 Roo.bootstrap.menu.Separator = function(config){
19557     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19558 };
19559
19560 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
19561     
19562     getAutoCreate : function(){
19563         var cfg = {
19564             tag : 'li',
19565             cls: 'divider'
19566         };
19567         
19568         return cfg;
19569     }
19570    
19571 });
19572
19573  
19574
19575