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         if(this.formatedValue){
6969             return this.value;
6970         }
6971         
6972         return this.inputEl().getValue();
6973     },
6974     /**
6975      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
6976      * @return {Mixed} value The field value
6977      */
6978     getRawValue : function(){
6979         var v = this.inputEl().getValue();
6980         
6981         return v;
6982     },
6983     
6984     /**
6985      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
6986      * @param {Mixed} value The value to set
6987      */
6988     setRawValue : function(v){
6989         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6990     },
6991     
6992     selectText : function(start, end){
6993         var v = this.getRawValue();
6994         if(v.length > 0){
6995             start = start === undefined ? 0 : start;
6996             end = end === undefined ? v.length : end;
6997             var d = this.inputEl().dom;
6998             if(d.setSelectionRange){
6999                 d.setSelectionRange(start, end);
7000             }else if(d.createTextRange){
7001                 var range = d.createTextRange();
7002                 range.moveStart("character", start);
7003                 range.moveEnd("character", v.length-end);
7004                 range.select();
7005             }
7006         }
7007     },
7008     
7009     /**
7010      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7011      * @param {Mixed} value The value to set
7012      */
7013     setValue : function(v){
7014         this.value = v;
7015         if(this.rendered){
7016             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7017             this.validate();
7018         }
7019     },
7020     
7021     /*
7022     processValue : function(value){
7023         if(this.stripCharsRe){
7024             var newValue = value.replace(this.stripCharsRe, '');
7025             if(newValue !== value){
7026                 this.setRawValue(newValue);
7027                 return newValue;
7028             }
7029         }
7030         return value;
7031     },
7032   */
7033     preFocus : function(){
7034         
7035         if(this.selectOnFocus){
7036             this.inputEl().dom.select();
7037         }
7038     },
7039     filterKeys : function(e){
7040         var k = e.getKey();
7041         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7042             return;
7043         }
7044         var c = e.getCharCode(), cc = String.fromCharCode(c);
7045         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7046             return;
7047         }
7048         if(!this.maskRe.test(cc)){
7049             e.stopEvent();
7050         }
7051     },
7052      /**
7053      * Clear any invalid styles/messages for this field
7054      */
7055     clearInvalid : function(){
7056         
7057         if(!this.el || this.preventMark){ // not rendered
7058             return;
7059         }
7060         this.el.removeClass(this.invalidClass);
7061         /*
7062         switch(this.msgTarget){
7063             case 'qtip':
7064                 this.el.dom.qtip = '';
7065                 break;
7066             case 'title':
7067                 this.el.dom.title = '';
7068                 break;
7069             case 'under':
7070                 if(this.errorEl){
7071                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7072                 }
7073                 break;
7074             case 'side':
7075                 if(this.errorIcon){
7076                     this.errorIcon.dom.qtip = '';
7077                     this.errorIcon.hide();
7078                     this.un('resize', this.alignErrorIcon, this);
7079                 }
7080                 break;
7081             default:
7082                 var t = Roo.getDom(this.msgTarget);
7083                 t.innerHTML = '';
7084                 t.style.display = 'none';
7085                 break;
7086         }
7087         */
7088         this.fireEvent('valid', this);
7089     },
7090      /**
7091      * Mark this field as invalid
7092      * @param {String} msg The validation message
7093      */
7094     markInvalid : function(msg){
7095         if(!this.el  || this.preventMark){ // not rendered
7096             return;
7097         }
7098         this.el.addClass(this.invalidClass);
7099         /*
7100         msg = msg || this.invalidText;
7101         switch(this.msgTarget){
7102             case 'qtip':
7103                 this.el.dom.qtip = msg;
7104                 this.el.dom.qclass = 'x-form-invalid-tip';
7105                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7106                     Roo.QuickTips.enable();
7107                 }
7108                 break;
7109             case 'title':
7110                 this.el.dom.title = msg;
7111                 break;
7112             case 'under':
7113                 if(!this.errorEl){
7114                     var elp = this.el.findParent('.x-form-element', 5, true);
7115                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7116                     this.errorEl.setWidth(elp.getWidth(true)-20);
7117                 }
7118                 this.errorEl.update(msg);
7119                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7120                 break;
7121             case 'side':
7122                 if(!this.errorIcon){
7123                     var elp = this.el.findParent('.x-form-element', 5, true);
7124                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7125                 }
7126                 this.alignErrorIcon();
7127                 this.errorIcon.dom.qtip = msg;
7128                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7129                 this.errorIcon.show();
7130                 this.on('resize', this.alignErrorIcon, this);
7131                 break;
7132             default:
7133                 var t = Roo.getDom(this.msgTarget);
7134                 t.innerHTML = msg;
7135                 t.style.display = this.msgDisplay;
7136                 break;
7137         }
7138         */
7139         this.fireEvent('invalid', this, msg);
7140     },
7141     // private
7142     SafariOnKeyDown : function(event)
7143     {
7144         // this is a workaround for a password hang bug on chrome/ webkit.
7145         
7146         var isSelectAll = false;
7147         
7148         if(this.inputEl().dom.selectionEnd > 0){
7149             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7150         }
7151         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7152             event.preventDefault();
7153             this.setValue('');
7154             return;
7155         }
7156         
7157         if(isSelectAll){ // backspace and delete key
7158             
7159             event.preventDefault();
7160             // this is very hacky as keydown always get's upper case.
7161             //
7162             var cc = String.fromCharCode(event.getCharCode());
7163             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7164             
7165         }
7166     },
7167     adjustWidth : function(tag, w){
7168         tag = tag.toLowerCase();
7169         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7170             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7171                 if(tag == 'input'){
7172                     return w + 2;
7173                 }
7174                 if(tag == 'textarea'){
7175                     return w-2;
7176                 }
7177             }else if(Roo.isOpera){
7178                 if(tag == 'input'){
7179                     return w + 2;
7180                 }
7181                 if(tag == 'textarea'){
7182                     return w-2;
7183                 }
7184             }
7185         }
7186         return w;
7187     }
7188     
7189 });
7190
7191  
7192 /*
7193  * - LGPL
7194  *
7195  * Input
7196  * 
7197  */
7198
7199 /**
7200  * @class Roo.bootstrap.TextArea
7201  * @extends Roo.bootstrap.Input
7202  * Bootstrap TextArea class
7203  * @cfg {Number} cols Specifies the visible width of a text area
7204  * @cfg {Number} rows Specifies the visible number of lines in a text area
7205  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7206  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7207  * @cfg {string} html text
7208  * 
7209  * @constructor
7210  * Create a new TextArea
7211  * @param {Object} config The config object
7212  */
7213
7214 Roo.bootstrap.TextArea = function(config){
7215     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7216    
7217 };
7218
7219 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7220      
7221     cols : false,
7222     rows : 5,
7223     readOnly : false,
7224     warp : 'soft',
7225     resize : false,
7226     value: false,
7227     html: false,
7228     
7229     getAutoCreate : function(){
7230         
7231         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7232         
7233         var id = Roo.id();
7234         
7235         var cfg = {};
7236         
7237         var input =  {
7238             tag: 'textarea',
7239             id : id,
7240             warp : this.warp,
7241             rows : this.rows,
7242             value : this.value || '',
7243             html: this.html || '',
7244             cls : 'form-control',
7245             placeholder : this.placeholder || '' 
7246             
7247         };
7248         
7249         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7250             input.maxLength = this.maxLength;
7251         }
7252         
7253         if(this.resize){
7254             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7255         }
7256         
7257         if(this.cols){
7258             input.cols = this.cols;
7259         }
7260         
7261         if (this.readOnly) {
7262             input.readonly = true;
7263         }
7264         
7265         if (this.name) {
7266             input.name = this.name;
7267         }
7268         
7269         if (this.size) {
7270             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7271         }
7272         
7273         var settings=this;
7274         ['xs','sm','md','lg'].map(function(size){
7275             if (settings[size]) {
7276                 cfg.cls += ' col-' + size + '-' + settings[size];
7277             }
7278         });
7279         
7280         var inputblock = input;
7281         
7282         if (this.before || this.after) {
7283             
7284             inputblock = {
7285                 cls : 'input-group',
7286                 cn :  [] 
7287             };
7288             if (this.before) {
7289                 inputblock.cn.push({
7290                     tag :'span',
7291                     cls : 'input-group-addon',
7292                     html : this.before
7293                 });
7294             }
7295             inputblock.cn.push(input);
7296             if (this.after) {
7297                 inputblock.cn.push({
7298                     tag :'span',
7299                     cls : 'input-group-addon',
7300                     html : this.after
7301                 });
7302             }
7303             
7304         }
7305         
7306         if (align ==='left' && this.fieldLabel.length) {
7307                 Roo.log("left and has label");
7308                 cfg.cn = [
7309                     
7310                     {
7311                         tag: 'label',
7312                         'for' :  id,
7313                         cls : 'control-label col-sm-' + this.labelWidth,
7314                         html : this.fieldLabel
7315                         
7316                     },
7317                     {
7318                         cls : "col-sm-" + (12 - this.labelWidth), 
7319                         cn: [
7320                             inputblock
7321                         ]
7322                     }
7323                     
7324                 ];
7325         } else if ( this.fieldLabel.length) {
7326                 Roo.log(" label");
7327                  cfg.cn = [
7328                    
7329                     {
7330                         tag: 'label',
7331                         //cls : 'input-group-addon',
7332                         html : this.fieldLabel
7333                         
7334                     },
7335                     
7336                     inputblock
7337                     
7338                 ];
7339
7340         } else {
7341             
7342                    Roo.log(" no label && no align");
7343                 cfg.cn = [
7344                     
7345                         inputblock
7346                     
7347                 ];
7348                 
7349                 
7350         }
7351         
7352         if (this.disabled) {
7353             input.disabled=true;
7354         }
7355         
7356         return cfg;
7357         
7358     },
7359     /**
7360      * return the real textarea element.
7361      */
7362     inputEl: function ()
7363     {
7364         return this.el.select('textarea.form-control',true).first();
7365     }
7366 });
7367
7368  
7369 /*
7370  * - LGPL
7371  *
7372  * trigger field - base class for combo..
7373  * 
7374  */
7375  
7376 /**
7377  * @class Roo.bootstrap.TriggerField
7378  * @extends Roo.bootstrap.Input
7379  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7380  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7381  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7382  * for which you can provide a custom implementation.  For example:
7383  * <pre><code>
7384 var trigger = new Roo.bootstrap.TriggerField();
7385 trigger.onTriggerClick = myTriggerFn;
7386 trigger.applyTo('my-field');
7387 </code></pre>
7388  *
7389  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7390  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7391  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
7392  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7393  * @constructor
7394  * Create a new TriggerField.
7395  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7396  * to the base TextField)
7397  */
7398 Roo.bootstrap.TriggerField = function(config){
7399     this.mimicing = false;
7400     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7401 };
7402
7403 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
7404     /**
7405      * @cfg {String} triggerClass A CSS class to apply to the trigger
7406      */
7407      /**
7408      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7409      */
7410     hideTrigger:false,
7411
7412     /** @cfg {Boolean} grow @hide */
7413     /** @cfg {Number} growMin @hide */
7414     /** @cfg {Number} growMax @hide */
7415
7416     /**
7417      * @hide 
7418      * @method
7419      */
7420     autoSize: Roo.emptyFn,
7421     // private
7422     monitorTab : true,
7423     // private
7424     deferHeight : true,
7425
7426     
7427     actionMode : 'wrap',
7428     
7429     
7430     
7431     getAutoCreate : function(){
7432        
7433         var parent = this.parent();
7434         
7435         var align = this.labelAlign || this.parentLabelAlign();
7436         
7437         var id = Roo.id();
7438         
7439         var cfg = {
7440             cls: 'form-group' //input-group
7441         };
7442         
7443         
7444         var input =  {
7445             tag: 'input',
7446             id : id,
7447             type : this.inputType,
7448             cls : 'form-control',
7449             autocomplete: 'off',
7450             placeholder : this.placeholder || '' 
7451             
7452         };
7453         if (this.name) {
7454             input.name = this.name;
7455         }
7456         if (this.size) {
7457             input.cls += ' input-' + this.size;
7458         }
7459         
7460         if (this.disabled) {
7461             input.disabled=true;
7462         }
7463         
7464         var inputblock = input;
7465         
7466         if (this.before || this.after) {
7467             
7468             inputblock = {
7469                 cls : 'input-group',
7470                 cn :  [] 
7471             };
7472             if (this.before) {
7473                 inputblock.cn.push({
7474                     tag :'span',
7475                     cls : 'input-group-addon',
7476                     html : this.before
7477                 });
7478             }
7479             inputblock.cn.push(input);
7480             if (this.after) {
7481                 inputblock.cn.push({
7482                     tag :'span',
7483                     cls : 'input-group-addon',
7484                     html : this.after
7485                 });
7486             }
7487             
7488         };
7489         
7490         var box = {
7491             tag: 'div',
7492             cn: [
7493                 {
7494                     tag: 'input',
7495                     type : 'hidden',
7496                     cls: 'form-hidden-field'
7497                 },
7498                 inputblock
7499             ]
7500             
7501         };
7502         
7503         if(this.multiple){
7504             Roo.log('multiple');
7505             
7506             box = {
7507                 tag: 'div',
7508                 cn: [
7509                     {
7510                         tag: 'input',
7511                         type : 'hidden',
7512                         cls: 'form-hidden-field'
7513                     },
7514                     {
7515                         tag: 'ul',
7516                         cls: 'select2-choices',
7517                         cn:[
7518                             {
7519                                 tag: 'li',
7520                                 cls: 'select2-search-field',
7521                                 cn: [
7522
7523                                     inputblock
7524                                 ]
7525                             }
7526                         ]
7527                     }
7528                 ]
7529             }
7530         };
7531         
7532         var combobox = {
7533             cls: 'select2-container input-group',
7534             cn: [
7535                 box,
7536                 {
7537                     tag: 'ul',
7538                     cls: 'typeahead typeahead-long dropdown-menu',
7539                     style: 'display:none'
7540                 }
7541             ]
7542         };
7543         
7544         if(!this.multiple){
7545             combobox.cn.push({
7546                 tag :'span',
7547                 cls : 'input-group-addon btn dropdown-toggle',
7548                 cn : [
7549                     {
7550                         tag: 'span',
7551                         cls: 'caret'
7552                     },
7553                     {
7554                         tag: 'span',
7555                         cls: 'combobox-clear',
7556                         cn  : [
7557                             {
7558                                 tag : 'i',
7559                                 cls: 'icon-remove'
7560                             }
7561                         ]
7562                     }
7563                 ]
7564
7565             })
7566         }
7567         
7568         if(this.multiple){
7569             combobox.cls += ' select2-container-multi';
7570         }
7571         
7572         if (align ==='left' && this.fieldLabel.length) {
7573             
7574                 Roo.log("left and has label");
7575                 cfg.cn = [
7576                     
7577                     {
7578                         tag: 'label',
7579                         'for' :  id,
7580                         cls : 'control-label col-sm-' + this.labelWidth,
7581                         html : this.fieldLabel
7582                         
7583                     },
7584                     {
7585                         cls : "col-sm-" + (12 - this.labelWidth), 
7586                         cn: [
7587                             combobox
7588                         ]
7589                     }
7590                     
7591                 ];
7592         } else if ( this.fieldLabel.length) {
7593                 Roo.log(" label");
7594                  cfg.cn = [
7595                    
7596                     {
7597                         tag: 'label',
7598                         //cls : 'input-group-addon',
7599                         html : this.fieldLabel
7600                         
7601                     },
7602                     
7603                     combobox
7604                     
7605                 ];
7606
7607         } else {
7608             
7609                 Roo.log(" no label && no align");
7610                 cfg = combobox
7611                      
7612                 
7613         }
7614          
7615         var settings=this;
7616         ['xs','sm','md','lg'].map(function(size){
7617             if (settings[size]) {
7618                 cfg.cls += ' col-' + size + '-' + settings[size];
7619             }
7620         });
7621         
7622         return cfg;
7623         
7624     },
7625     
7626     
7627     
7628     // private
7629     onResize : function(w, h){
7630 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7631 //        if(typeof w == 'number'){
7632 //            var x = w - this.trigger.getWidth();
7633 //            this.inputEl().setWidth(this.adjustWidth('input', x));
7634 //            this.trigger.setStyle('left', x+'px');
7635 //        }
7636     },
7637
7638     // private
7639     adjustSize : Roo.BoxComponent.prototype.adjustSize,
7640
7641     // private
7642     getResizeEl : function(){
7643         return this.inputEl();
7644     },
7645
7646     // private
7647     getPositionEl : function(){
7648         return this.inputEl();
7649     },
7650
7651     // private
7652     alignErrorIcon : function(){
7653         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7654     },
7655
7656     // private
7657     initEvents : function(){
7658         
7659         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7660         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7661         if(!this.multiple){
7662             this.trigger = this.el.select('span.dropdown-toggle',true).first();
7663             if(this.hideTrigger){
7664                 this.trigger.setDisplayed(false);
7665             }
7666             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7667         }
7668         
7669         if(this.multiple){
7670             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7671         }
7672         
7673         //this.trigger.addClassOnOver('x-form-trigger-over');
7674         //this.trigger.addClassOnClick('x-form-trigger-click');
7675         
7676         //if(!this.width){
7677         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7678         //}
7679     },
7680
7681     // private
7682     initTrigger : function(){
7683        
7684     },
7685
7686     // private
7687     onDestroy : function(){
7688         if(this.trigger){
7689             this.trigger.removeAllListeners();
7690           //  this.trigger.remove();
7691         }
7692         //if(this.wrap){
7693         //    this.wrap.remove();
7694         //}
7695         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7696     },
7697
7698     // private
7699     onFocus : function(){
7700         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7701         /*
7702         if(!this.mimicing){
7703             this.wrap.addClass('x-trigger-wrap-focus');
7704             this.mimicing = true;
7705             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7706             if(this.monitorTab){
7707                 this.el.on("keydown", this.checkTab, this);
7708             }
7709         }
7710         */
7711     },
7712
7713     // private
7714     checkTab : function(e){
7715         if(e.getKey() == e.TAB){
7716             this.triggerBlur();
7717         }
7718     },
7719
7720     // private
7721     onBlur : function(){
7722         // do nothing
7723     },
7724
7725     // private
7726     mimicBlur : function(e, t){
7727         /*
7728         if(!this.wrap.contains(t) && this.validateBlur()){
7729             this.triggerBlur();
7730         }
7731         */
7732     },
7733
7734     // private
7735     triggerBlur : function(){
7736         this.mimicing = false;
7737         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7738         if(this.monitorTab){
7739             this.el.un("keydown", this.checkTab, this);
7740         }
7741         //this.wrap.removeClass('x-trigger-wrap-focus');
7742         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7743     },
7744
7745     // private
7746     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7747     validateBlur : function(e, t){
7748         return true;
7749     },
7750
7751     // private
7752     onDisable : function(){
7753         this.inputEl().dom.disabled = true;
7754         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7755         //if(this.wrap){
7756         //    this.wrap.addClass('x-item-disabled');
7757         //}
7758     },
7759
7760     // private
7761     onEnable : function(){
7762         this.inputEl().dom.disabled = false;
7763         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7764         //if(this.wrap){
7765         //    this.el.removeClass('x-item-disabled');
7766         //}
7767     },
7768
7769     // private
7770     onShow : function(){
7771         var ae = this.getActionEl();
7772         
7773         if(ae){
7774             ae.dom.style.display = '';
7775             ae.dom.style.visibility = 'visible';
7776         }
7777     },
7778
7779     // private
7780     
7781     onHide : function(){
7782         var ae = this.getActionEl();
7783         ae.dom.style.display = 'none';
7784     },
7785
7786     /**
7787      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
7788      * by an implementing function.
7789      * @method
7790      * @param {EventObject} e
7791      */
7792     onTriggerClick : Roo.emptyFn
7793 });
7794  /*
7795  * Based on:
7796  * Ext JS Library 1.1.1
7797  * Copyright(c) 2006-2007, Ext JS, LLC.
7798  *
7799  * Originally Released Under LGPL - original licence link has changed is not relivant.
7800  *
7801  * Fork - LGPL
7802  * <script type="text/javascript">
7803  */
7804
7805
7806 /**
7807  * @class Roo.data.SortTypes
7808  * @singleton
7809  * Defines the default sorting (casting?) comparison functions used when sorting data.
7810  */
7811 Roo.data.SortTypes = {
7812     /**
7813      * Default sort that does nothing
7814      * @param {Mixed} s The value being converted
7815      * @return {Mixed} The comparison value
7816      */
7817     none : function(s){
7818         return s;
7819     },
7820     
7821     /**
7822      * The regular expression used to strip tags
7823      * @type {RegExp}
7824      * @property
7825      */
7826     stripTagsRE : /<\/?[^>]+>/gi,
7827     
7828     /**
7829      * Strips all HTML tags to sort on text only
7830      * @param {Mixed} s The value being converted
7831      * @return {String} The comparison value
7832      */
7833     asText : function(s){
7834         return String(s).replace(this.stripTagsRE, "");
7835     },
7836     
7837     /**
7838      * Strips all HTML tags to sort on text only - Case insensitive
7839      * @param {Mixed} s The value being converted
7840      * @return {String} The comparison value
7841      */
7842     asUCText : function(s){
7843         return String(s).toUpperCase().replace(this.stripTagsRE, "");
7844     },
7845     
7846     /**
7847      * Case insensitive string
7848      * @param {Mixed} s The value being converted
7849      * @return {String} The comparison value
7850      */
7851     asUCString : function(s) {
7852         return String(s).toUpperCase();
7853     },
7854     
7855     /**
7856      * Date sorting
7857      * @param {Mixed} s The value being converted
7858      * @return {Number} The comparison value
7859      */
7860     asDate : function(s) {
7861         if(!s){
7862             return 0;
7863         }
7864         if(s instanceof Date){
7865             return s.getTime();
7866         }
7867         return Date.parse(String(s));
7868     },
7869     
7870     /**
7871      * Float sorting
7872      * @param {Mixed} s The value being converted
7873      * @return {Float} The comparison value
7874      */
7875     asFloat : function(s) {
7876         var val = parseFloat(String(s).replace(/,/g, ""));
7877         if(isNaN(val)) val = 0;
7878         return val;
7879     },
7880     
7881     /**
7882      * Integer sorting
7883      * @param {Mixed} s The value being converted
7884      * @return {Number} The comparison value
7885      */
7886     asInt : function(s) {
7887         var val = parseInt(String(s).replace(/,/g, ""));
7888         if(isNaN(val)) val = 0;
7889         return val;
7890     }
7891 };/*
7892  * Based on:
7893  * Ext JS Library 1.1.1
7894  * Copyright(c) 2006-2007, Ext JS, LLC.
7895  *
7896  * Originally Released Under LGPL - original licence link has changed is not relivant.
7897  *
7898  * Fork - LGPL
7899  * <script type="text/javascript">
7900  */
7901
7902 /**
7903 * @class Roo.data.Record
7904  * Instances of this class encapsulate both record <em>definition</em> information, and record
7905  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7906  * to access Records cached in an {@link Roo.data.Store} object.<br>
7907  * <p>
7908  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7909  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7910  * objects.<br>
7911  * <p>
7912  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7913  * @constructor
7914  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7915  * {@link #create}. The parameters are the same.
7916  * @param {Array} data An associative Array of data values keyed by the field name.
7917  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7918  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7919  * not specified an integer id is generated.
7920  */
7921 Roo.data.Record = function(data, id){
7922     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7923     this.data = data;
7924 };
7925
7926 /**
7927  * Generate a constructor for a specific record layout.
7928  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7929  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7930  * Each field definition object may contain the following properties: <ul>
7931  * <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,
7932  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7933  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7934  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7935  * is being used, then this is a string containing the javascript expression to reference the data relative to 
7936  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7937  * to the data item relative to the record element. If the mapping expression is the same as the field name,
7938  * this may be omitted.</p></li>
7939  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7940  * <ul><li>auto (Default, implies no conversion)</li>
7941  * <li>string</li>
7942  * <li>int</li>
7943  * <li>float</li>
7944  * <li>boolean</li>
7945  * <li>date</li></ul></p></li>
7946  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7947  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7948  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7949  * by the Reader into an object that will be stored in the Record. It is passed the
7950  * following parameters:<ul>
7951  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7952  * </ul></p></li>
7953  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7954  * </ul>
7955  * <br>usage:<br><pre><code>
7956 var TopicRecord = Roo.data.Record.create(
7957     {name: 'title', mapping: 'topic_title'},
7958     {name: 'author', mapping: 'username'},
7959     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7960     {name: 'lastPost', mapping: 'post_time', type: 'date'},
7961     {name: 'lastPoster', mapping: 'user2'},
7962     {name: 'excerpt', mapping: 'post_text'}
7963 );
7964
7965 var myNewRecord = new TopicRecord({
7966     title: 'Do my job please',
7967     author: 'noobie',
7968     totalPosts: 1,
7969     lastPost: new Date(),
7970     lastPoster: 'Animal',
7971     excerpt: 'No way dude!'
7972 });
7973 myStore.add(myNewRecord);
7974 </code></pre>
7975  * @method create
7976  * @static
7977  */
7978 Roo.data.Record.create = function(o){
7979     var f = function(){
7980         f.superclass.constructor.apply(this, arguments);
7981     };
7982     Roo.extend(f, Roo.data.Record);
7983     var p = f.prototype;
7984     p.fields = new Roo.util.MixedCollection(false, function(field){
7985         return field.name;
7986     });
7987     for(var i = 0, len = o.length; i < len; i++){
7988         p.fields.add(new Roo.data.Field(o[i]));
7989     }
7990     f.getField = function(name){
7991         return p.fields.get(name);  
7992     };
7993     return f;
7994 };
7995
7996 Roo.data.Record.AUTO_ID = 1000;
7997 Roo.data.Record.EDIT = 'edit';
7998 Roo.data.Record.REJECT = 'reject';
7999 Roo.data.Record.COMMIT = 'commit';
8000
8001 Roo.data.Record.prototype = {
8002     /**
8003      * Readonly flag - true if this record has been modified.
8004      * @type Boolean
8005      */
8006     dirty : false,
8007     editing : false,
8008     error: null,
8009     modified: null,
8010
8011     // private
8012     join : function(store){
8013         this.store = store;
8014     },
8015
8016     /**
8017      * Set the named field to the specified value.
8018      * @param {String} name The name of the field to set.
8019      * @param {Object} value The value to set the field to.
8020      */
8021     set : function(name, value){
8022         if(this.data[name] == value){
8023             return;
8024         }
8025         this.dirty = true;
8026         if(!this.modified){
8027             this.modified = {};
8028         }
8029         if(typeof this.modified[name] == 'undefined'){
8030             this.modified[name] = this.data[name];
8031         }
8032         this.data[name] = value;
8033         if(!this.editing && this.store){
8034             this.store.afterEdit(this);
8035         }       
8036     },
8037
8038     /**
8039      * Get the value of the named field.
8040      * @param {String} name The name of the field to get the value of.
8041      * @return {Object} The value of the field.
8042      */
8043     get : function(name){
8044         return this.data[name]; 
8045     },
8046
8047     // private
8048     beginEdit : function(){
8049         this.editing = true;
8050         this.modified = {}; 
8051     },
8052
8053     // private
8054     cancelEdit : function(){
8055         this.editing = false;
8056         delete this.modified;
8057     },
8058
8059     // private
8060     endEdit : function(){
8061         this.editing = false;
8062         if(this.dirty && this.store){
8063             this.store.afterEdit(this);
8064         }
8065     },
8066
8067     /**
8068      * Usually called by the {@link Roo.data.Store} which owns the Record.
8069      * Rejects all changes made to the Record since either creation, or the last commit operation.
8070      * Modified fields are reverted to their original values.
8071      * <p>
8072      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8073      * of reject operations.
8074      */
8075     reject : function(){
8076         var m = this.modified;
8077         for(var n in m){
8078             if(typeof m[n] != "function"){
8079                 this.data[n] = m[n];
8080             }
8081         }
8082         this.dirty = false;
8083         delete this.modified;
8084         this.editing = false;
8085         if(this.store){
8086             this.store.afterReject(this);
8087         }
8088     },
8089
8090     /**
8091      * Usually called by the {@link Roo.data.Store} which owns the Record.
8092      * Commits all changes made to the Record since either creation, or the last commit operation.
8093      * <p>
8094      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8095      * of commit operations.
8096      */
8097     commit : function(){
8098         this.dirty = false;
8099         delete this.modified;
8100         this.editing = false;
8101         if(this.store){
8102             this.store.afterCommit(this);
8103         }
8104     },
8105
8106     // private
8107     hasError : function(){
8108         return this.error != null;
8109     },
8110
8111     // private
8112     clearError : function(){
8113         this.error = null;
8114     },
8115
8116     /**
8117      * Creates a copy of this record.
8118      * @param {String} id (optional) A new record id if you don't want to use this record's id
8119      * @return {Record}
8120      */
8121     copy : function(newId) {
8122         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8123     }
8124 };/*
8125  * Based on:
8126  * Ext JS Library 1.1.1
8127  * Copyright(c) 2006-2007, Ext JS, LLC.
8128  *
8129  * Originally Released Under LGPL - original licence link has changed is not relivant.
8130  *
8131  * Fork - LGPL
8132  * <script type="text/javascript">
8133  */
8134
8135
8136
8137 /**
8138  * @class Roo.data.Store
8139  * @extends Roo.util.Observable
8140  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8141  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8142  * <p>
8143  * 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
8144  * has no knowledge of the format of the data returned by the Proxy.<br>
8145  * <p>
8146  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8147  * instances from the data object. These records are cached and made available through accessor functions.
8148  * @constructor
8149  * Creates a new Store.
8150  * @param {Object} config A config object containing the objects needed for the Store to access data,
8151  * and read the data into Records.
8152  */
8153 Roo.data.Store = function(config){
8154     this.data = new Roo.util.MixedCollection(false);
8155     this.data.getKey = function(o){
8156         return o.id;
8157     };
8158     this.baseParams = {};
8159     // private
8160     this.paramNames = {
8161         "start" : "start",
8162         "limit" : "limit",
8163         "sort" : "sort",
8164         "dir" : "dir",
8165         "multisort" : "_multisort"
8166     };
8167
8168     if(config && config.data){
8169         this.inlineData = config.data;
8170         delete config.data;
8171     }
8172
8173     Roo.apply(this, config);
8174     
8175     if(this.reader){ // reader passed
8176         this.reader = Roo.factory(this.reader, Roo.data);
8177         this.reader.xmodule = this.xmodule || false;
8178         if(!this.recordType){
8179             this.recordType = this.reader.recordType;
8180         }
8181         if(this.reader.onMetaChange){
8182             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8183         }
8184     }
8185
8186     if(this.recordType){
8187         this.fields = this.recordType.prototype.fields;
8188     }
8189     this.modified = [];
8190
8191     this.addEvents({
8192         /**
8193          * @event datachanged
8194          * Fires when the data cache has changed, and a widget which is using this Store
8195          * as a Record cache should refresh its view.
8196          * @param {Store} this
8197          */
8198         datachanged : true,
8199         /**
8200          * @event metachange
8201          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8202          * @param {Store} this
8203          * @param {Object} meta The JSON metadata
8204          */
8205         metachange : true,
8206         /**
8207          * @event add
8208          * Fires when Records have been added to the Store
8209          * @param {Store} this
8210          * @param {Roo.data.Record[]} records The array of Records added
8211          * @param {Number} index The index at which the record(s) were added
8212          */
8213         add : true,
8214         /**
8215          * @event remove
8216          * Fires when a Record has been removed from the Store
8217          * @param {Store} this
8218          * @param {Roo.data.Record} record The Record that was removed
8219          * @param {Number} index The index at which the record was removed
8220          */
8221         remove : true,
8222         /**
8223          * @event update
8224          * Fires when a Record has been updated
8225          * @param {Store} this
8226          * @param {Roo.data.Record} record The Record that was updated
8227          * @param {String} operation The update operation being performed.  Value may be one of:
8228          * <pre><code>
8229  Roo.data.Record.EDIT
8230  Roo.data.Record.REJECT
8231  Roo.data.Record.COMMIT
8232          * </code></pre>
8233          */
8234         update : true,
8235         /**
8236          * @event clear
8237          * Fires when the data cache has been cleared.
8238          * @param {Store} this
8239          */
8240         clear : true,
8241         /**
8242          * @event beforeload
8243          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8244          * the load action will be canceled.
8245          * @param {Store} this
8246          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8247          */
8248         beforeload : true,
8249         /**
8250          * @event beforeloadadd
8251          * Fires after a new set of Records has been loaded.
8252          * @param {Store} this
8253          * @param {Roo.data.Record[]} records The Records that were loaded
8254          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8255          */
8256         beforeloadadd : true,
8257         /**
8258          * @event load
8259          * Fires after a new set of Records has been loaded, before they are added to the store.
8260          * @param {Store} this
8261          * @param {Roo.data.Record[]} records The Records that were loaded
8262          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8263          * @params {Object} return from reader
8264          */
8265         load : true,
8266         /**
8267          * @event loadexception
8268          * Fires if an exception occurs in the Proxy during loading.
8269          * Called with the signature of the Proxy's "loadexception" event.
8270          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8271          * 
8272          * @param {Proxy} 
8273          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8274          * @param {Object} load options 
8275          * @param {Object} jsonData from your request (normally this contains the Exception)
8276          */
8277         loadexception : true
8278     });
8279     
8280     if(this.proxy){
8281         this.proxy = Roo.factory(this.proxy, Roo.data);
8282         this.proxy.xmodule = this.xmodule || false;
8283         this.relayEvents(this.proxy,  ["loadexception"]);
8284     }
8285     this.sortToggle = {};
8286     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8287
8288     Roo.data.Store.superclass.constructor.call(this);
8289
8290     if(this.inlineData){
8291         this.loadData(this.inlineData);
8292         delete this.inlineData;
8293     }
8294 };
8295
8296 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8297      /**
8298     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8299     * without a remote query - used by combo/forms at present.
8300     */
8301     
8302     /**
8303     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8304     */
8305     /**
8306     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8307     */
8308     /**
8309     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8310     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8311     */
8312     /**
8313     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8314     * on any HTTP request
8315     */
8316     /**
8317     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8318     */
8319     /**
8320     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8321     */
8322     multiSort: false,
8323     /**
8324     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8325     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8326     */
8327     remoteSort : false,
8328
8329     /**
8330     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8331      * loaded or when a record is removed. (defaults to false).
8332     */
8333     pruneModifiedRecords : false,
8334
8335     // private
8336     lastOptions : null,
8337
8338     /**
8339      * Add Records to the Store and fires the add event.
8340      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8341      */
8342     add : function(records){
8343         records = [].concat(records);
8344         for(var i = 0, len = records.length; i < len; i++){
8345             records[i].join(this);
8346         }
8347         var index = this.data.length;
8348         this.data.addAll(records);
8349         this.fireEvent("add", this, records, index);
8350     },
8351
8352     /**
8353      * Remove a Record from the Store and fires the remove event.
8354      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8355      */
8356     remove : function(record){
8357         var index = this.data.indexOf(record);
8358         this.data.removeAt(index);
8359         if(this.pruneModifiedRecords){
8360             this.modified.remove(record);
8361         }
8362         this.fireEvent("remove", this, record, index);
8363     },
8364
8365     /**
8366      * Remove all Records from the Store and fires the clear event.
8367      */
8368     removeAll : function(){
8369         this.data.clear();
8370         if(this.pruneModifiedRecords){
8371             this.modified = [];
8372         }
8373         this.fireEvent("clear", this);
8374     },
8375
8376     /**
8377      * Inserts Records to the Store at the given index and fires the add event.
8378      * @param {Number} index The start index at which to insert the passed Records.
8379      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8380      */
8381     insert : function(index, records){
8382         records = [].concat(records);
8383         for(var i = 0, len = records.length; i < len; i++){
8384             this.data.insert(index, records[i]);
8385             records[i].join(this);
8386         }
8387         this.fireEvent("add", this, records, index);
8388     },
8389
8390     /**
8391      * Get the index within the cache of the passed Record.
8392      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8393      * @return {Number} The index of the passed Record. Returns -1 if not found.
8394      */
8395     indexOf : function(record){
8396         return this.data.indexOf(record);
8397     },
8398
8399     /**
8400      * Get the index within the cache of the Record with the passed id.
8401      * @param {String} id The id of the Record to find.
8402      * @return {Number} The index of the Record. Returns -1 if not found.
8403      */
8404     indexOfId : function(id){
8405         return this.data.indexOfKey(id);
8406     },
8407
8408     /**
8409      * Get the Record with the specified id.
8410      * @param {String} id The id of the Record to find.
8411      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8412      */
8413     getById : function(id){
8414         return this.data.key(id);
8415     },
8416
8417     /**
8418      * Get the Record at the specified index.
8419      * @param {Number} index The index of the Record to find.
8420      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8421      */
8422     getAt : function(index){
8423         return this.data.itemAt(index);
8424     },
8425
8426     /**
8427      * Returns a range of Records between specified indices.
8428      * @param {Number} startIndex (optional) The starting index (defaults to 0)
8429      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8430      * @return {Roo.data.Record[]} An array of Records
8431      */
8432     getRange : function(start, end){
8433         return this.data.getRange(start, end);
8434     },
8435
8436     // private
8437     storeOptions : function(o){
8438         o = Roo.apply({}, o);
8439         delete o.callback;
8440         delete o.scope;
8441         this.lastOptions = o;
8442     },
8443
8444     /**
8445      * Loads the Record cache from the configured Proxy using the configured Reader.
8446      * <p>
8447      * If using remote paging, then the first load call must specify the <em>start</em>
8448      * and <em>limit</em> properties in the options.params property to establish the initial
8449      * position within the dataset, and the number of Records to cache on each read from the Proxy.
8450      * <p>
8451      * <strong>It is important to note that for remote data sources, loading is asynchronous,
8452      * and this call will return before the new data has been loaded. Perform any post-processing
8453      * in a callback function, or in a "load" event handler.</strong>
8454      * <p>
8455      * @param {Object} options An object containing properties which control loading options:<ul>
8456      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8457      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8458      * passed the following arguments:<ul>
8459      * <li>r : Roo.data.Record[]</li>
8460      * <li>options: Options object from the load call</li>
8461      * <li>success: Boolean success indicator</li></ul></li>
8462      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8463      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8464      * </ul>
8465      */
8466     load : function(options){
8467         options = options || {};
8468         if(this.fireEvent("beforeload", this, options) !== false){
8469             this.storeOptions(options);
8470             var p = Roo.apply(options.params || {}, this.baseParams);
8471             // if meta was not loaded from remote source.. try requesting it.
8472             if (!this.reader.metaFromRemote) {
8473                 p._requestMeta = 1;
8474             }
8475             if(this.sortInfo && this.remoteSort){
8476                 var pn = this.paramNames;
8477                 p[pn["sort"]] = this.sortInfo.field;
8478                 p[pn["dir"]] = this.sortInfo.direction;
8479             }
8480             if (this.multiSort) {
8481                 var pn = this.paramNames;
8482                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8483             }
8484             
8485             this.proxy.load(p, this.reader, this.loadRecords, this, options);
8486         }
8487     },
8488
8489     /**
8490      * Reloads the Record cache from the configured Proxy using the configured Reader and
8491      * the options from the last load operation performed.
8492      * @param {Object} options (optional) An object containing properties which may override the options
8493      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8494      * the most recently used options are reused).
8495      */
8496     reload : function(options){
8497         this.load(Roo.applyIf(options||{}, this.lastOptions));
8498     },
8499
8500     // private
8501     // Called as a callback by the Reader during a load operation.
8502     loadRecords : function(o, options, success){
8503         if(!o || success === false){
8504             if(success !== false){
8505                 this.fireEvent("load", this, [], options, o);
8506             }
8507             if(options.callback){
8508                 options.callback.call(options.scope || this, [], options, false);
8509             }
8510             return;
8511         }
8512         // if data returned failure - throw an exception.
8513         if (o.success === false) {
8514             // show a message if no listener is registered.
8515             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8516                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8517             }
8518             // loadmask wil be hooked into this..
8519             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8520             return;
8521         }
8522         var r = o.records, t = o.totalRecords || r.length;
8523         
8524         this.fireEvent("beforeloadadd", this, r, options, o);
8525         
8526         if(!options || options.add !== true){
8527             if(this.pruneModifiedRecords){
8528                 this.modified = [];
8529             }
8530             for(var i = 0, len = r.length; i < len; i++){
8531                 r[i].join(this);
8532             }
8533             if(this.snapshot){
8534                 this.data = this.snapshot;
8535                 delete this.snapshot;
8536             }
8537             this.data.clear();
8538             this.data.addAll(r);
8539             this.totalLength = t;
8540             this.applySort();
8541             this.fireEvent("datachanged", this);
8542         }else{
8543             this.totalLength = Math.max(t, this.data.length+r.length);
8544             this.add(r);
8545         }
8546         this.fireEvent("load", this, r, options, o);
8547         if(options.callback){
8548             options.callback.call(options.scope || this, r, options, true);
8549         }
8550     },
8551
8552
8553     /**
8554      * Loads data from a passed data block. A Reader which understands the format of the data
8555      * must have been configured in the constructor.
8556      * @param {Object} data The data block from which to read the Records.  The format of the data expected
8557      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8558      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8559      */
8560     loadData : function(o, append){
8561         var r = this.reader.readRecords(o);
8562         this.loadRecords(r, {add: append}, true);
8563     },
8564
8565     /**
8566      * Gets the number of cached records.
8567      * <p>
8568      * <em>If using paging, this may not be the total size of the dataset. If the data object
8569      * used by the Reader contains the dataset size, then the getTotalCount() function returns
8570      * the data set size</em>
8571      */
8572     getCount : function(){
8573         return this.data.length || 0;
8574     },
8575
8576     /**
8577      * Gets the total number of records in the dataset as returned by the server.
8578      * <p>
8579      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8580      * the dataset size</em>
8581      */
8582     getTotalCount : function(){
8583         return this.totalLength || 0;
8584     },
8585
8586     /**
8587      * Returns the sort state of the Store as an object with two properties:
8588      * <pre><code>
8589  field {String} The name of the field by which the Records are sorted
8590  direction {String} The sort order, "ASC" or "DESC"
8591      * </code></pre>
8592      */
8593     getSortState : function(){
8594         return this.sortInfo;
8595     },
8596
8597     // private
8598     applySort : function(){
8599         if(this.sortInfo && !this.remoteSort){
8600             var s = this.sortInfo, f = s.field;
8601             var st = this.fields.get(f).sortType;
8602             var fn = function(r1, r2){
8603                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8604                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8605             };
8606             this.data.sort(s.direction, fn);
8607             if(this.snapshot && this.snapshot != this.data){
8608                 this.snapshot.sort(s.direction, fn);
8609             }
8610         }
8611     },
8612
8613     /**
8614      * Sets the default sort column and order to be used by the next load operation.
8615      * @param {String} fieldName The name of the field to sort by.
8616      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8617      */
8618     setDefaultSort : function(field, dir){
8619         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8620     },
8621
8622     /**
8623      * Sort the Records.
8624      * If remote sorting is used, the sort is performed on the server, and the cache is
8625      * reloaded. If local sorting is used, the cache is sorted internally.
8626      * @param {String} fieldName The name of the field to sort by.
8627      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8628      */
8629     sort : function(fieldName, dir){
8630         var f = this.fields.get(fieldName);
8631         if(!dir){
8632             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8633             
8634             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8635                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8636             }else{
8637                 dir = f.sortDir;
8638             }
8639         }
8640         this.sortToggle[f.name] = dir;
8641         this.sortInfo = {field: f.name, direction: dir};
8642         if(!this.remoteSort){
8643             this.applySort();
8644             this.fireEvent("datachanged", this);
8645         }else{
8646             this.load(this.lastOptions);
8647         }
8648     },
8649
8650     /**
8651      * Calls the specified function for each of the Records in the cache.
8652      * @param {Function} fn The function to call. The Record is passed as the first parameter.
8653      * Returning <em>false</em> aborts and exits the iteration.
8654      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8655      */
8656     each : function(fn, scope){
8657         this.data.each(fn, scope);
8658     },
8659
8660     /**
8661      * Gets all records modified since the last commit.  Modified records are persisted across load operations
8662      * (e.g., during paging).
8663      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8664      */
8665     getModifiedRecords : function(){
8666         return this.modified;
8667     },
8668
8669     // private
8670     createFilterFn : function(property, value, anyMatch){
8671         if(!value.exec){ // not a regex
8672             value = String(value);
8673             if(value.length == 0){
8674                 return false;
8675             }
8676             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8677         }
8678         return function(r){
8679             return value.test(r.data[property]);
8680         };
8681     },
8682
8683     /**
8684      * Sums the value of <i>property</i> for each record between start and end and returns the result.
8685      * @param {String} property A field on your records
8686      * @param {Number} start The record index to start at (defaults to 0)
8687      * @param {Number} end The last record index to include (defaults to length - 1)
8688      * @return {Number} The sum
8689      */
8690     sum : function(property, start, end){
8691         var rs = this.data.items, v = 0;
8692         start = start || 0;
8693         end = (end || end === 0) ? end : rs.length-1;
8694
8695         for(var i = start; i <= end; i++){
8696             v += (rs[i].data[property] || 0);
8697         }
8698         return v;
8699     },
8700
8701     /**
8702      * Filter the records by a specified property.
8703      * @param {String} field A field on your records
8704      * @param {String/RegExp} value Either a string that the field
8705      * should start with or a RegExp to test against the field
8706      * @param {Boolean} anyMatch True to match any part not just the beginning
8707      */
8708     filter : function(property, value, anyMatch){
8709         var fn = this.createFilterFn(property, value, anyMatch);
8710         return fn ? this.filterBy(fn) : this.clearFilter();
8711     },
8712
8713     /**
8714      * Filter by a function. The specified function will be called with each
8715      * record in this data source. If the function returns true the record is included,
8716      * otherwise it is filtered.
8717      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8718      * @param {Object} scope (optional) The scope of the function (defaults to this)
8719      */
8720     filterBy : function(fn, scope){
8721         this.snapshot = this.snapshot || this.data;
8722         this.data = this.queryBy(fn, scope||this);
8723         this.fireEvent("datachanged", this);
8724     },
8725
8726     /**
8727      * Query the records by a specified property.
8728      * @param {String} field A field on your records
8729      * @param {String/RegExp} value Either a string that the field
8730      * should start with or a RegExp to test against the field
8731      * @param {Boolean} anyMatch True to match any part not just the beginning
8732      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8733      */
8734     query : function(property, value, anyMatch){
8735         var fn = this.createFilterFn(property, value, anyMatch);
8736         return fn ? this.queryBy(fn) : this.data.clone();
8737     },
8738
8739     /**
8740      * Query by a function. The specified function will be called with each
8741      * record in this data source. If the function returns true the record is included
8742      * in the results.
8743      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8744      * @param {Object} scope (optional) The scope of the function (defaults to this)
8745       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8746      **/
8747     queryBy : function(fn, scope){
8748         var data = this.snapshot || this.data;
8749         return data.filterBy(fn, scope||this);
8750     },
8751
8752     /**
8753      * Collects unique values for a particular dataIndex from this store.
8754      * @param {String} dataIndex The property to collect
8755      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8756      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8757      * @return {Array} An array of the unique values
8758      **/
8759     collect : function(dataIndex, allowNull, bypassFilter){
8760         var d = (bypassFilter === true && this.snapshot) ?
8761                 this.snapshot.items : this.data.items;
8762         var v, sv, r = [], l = {};
8763         for(var i = 0, len = d.length; i < len; i++){
8764             v = d[i].data[dataIndex];
8765             sv = String(v);
8766             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8767                 l[sv] = true;
8768                 r[r.length] = v;
8769             }
8770         }
8771         return r;
8772     },
8773
8774     /**
8775      * Revert to a view of the Record cache with no filtering applied.
8776      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8777      */
8778     clearFilter : function(suppressEvent){
8779         if(this.snapshot && this.snapshot != this.data){
8780             this.data = this.snapshot;
8781             delete this.snapshot;
8782             if(suppressEvent !== true){
8783                 this.fireEvent("datachanged", this);
8784             }
8785         }
8786     },
8787
8788     // private
8789     afterEdit : function(record){
8790         if(this.modified.indexOf(record) == -1){
8791             this.modified.push(record);
8792         }
8793         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8794     },
8795     
8796     // private
8797     afterReject : function(record){
8798         this.modified.remove(record);
8799         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8800     },
8801
8802     // private
8803     afterCommit : function(record){
8804         this.modified.remove(record);
8805         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8806     },
8807
8808     /**
8809      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8810      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8811      */
8812     commitChanges : function(){
8813         var m = this.modified.slice(0);
8814         this.modified = [];
8815         for(var i = 0, len = m.length; i < len; i++){
8816             m[i].commit();
8817         }
8818     },
8819
8820     /**
8821      * Cancel outstanding changes on all changed records.
8822      */
8823     rejectChanges : function(){
8824         var m = this.modified.slice(0);
8825         this.modified = [];
8826         for(var i = 0, len = m.length; i < len; i++){
8827             m[i].reject();
8828         }
8829     },
8830
8831     onMetaChange : function(meta, rtype, o){
8832         this.recordType = rtype;
8833         this.fields = rtype.prototype.fields;
8834         delete this.snapshot;
8835         this.sortInfo = meta.sortInfo || this.sortInfo;
8836         this.modified = [];
8837         this.fireEvent('metachange', this, this.reader.meta);
8838     },
8839     
8840     moveIndex : function(data, type)
8841     {
8842         var index = this.indexOf(data);
8843         
8844         var newIndex = index + type;
8845         
8846         this.remove(data);
8847         
8848         this.insert(newIndex, data);
8849         
8850     }
8851 });/*
8852  * Based on:
8853  * Ext JS Library 1.1.1
8854  * Copyright(c) 2006-2007, Ext JS, LLC.
8855  *
8856  * Originally Released Under LGPL - original licence link has changed is not relivant.
8857  *
8858  * Fork - LGPL
8859  * <script type="text/javascript">
8860  */
8861
8862 /**
8863  * @class Roo.data.SimpleStore
8864  * @extends Roo.data.Store
8865  * Small helper class to make creating Stores from Array data easier.
8866  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8867  * @cfg {Array} fields An array of field definition objects, or field name strings.
8868  * @cfg {Array} data The multi-dimensional array of data
8869  * @constructor
8870  * @param {Object} config
8871  */
8872 Roo.data.SimpleStore = function(config){
8873     Roo.data.SimpleStore.superclass.constructor.call(this, {
8874         isLocal : true,
8875         reader: new Roo.data.ArrayReader({
8876                 id: config.id
8877             },
8878             Roo.data.Record.create(config.fields)
8879         ),
8880         proxy : new Roo.data.MemoryProxy(config.data)
8881     });
8882     this.load();
8883 };
8884 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8885  * Based on:
8886  * Ext JS Library 1.1.1
8887  * Copyright(c) 2006-2007, Ext JS, LLC.
8888  *
8889  * Originally Released Under LGPL - original licence link has changed is not relivant.
8890  *
8891  * Fork - LGPL
8892  * <script type="text/javascript">
8893  */
8894
8895 /**
8896 /**
8897  * @extends Roo.data.Store
8898  * @class Roo.data.JsonStore
8899  * Small helper class to make creating Stores for JSON data easier. <br/>
8900 <pre><code>
8901 var store = new Roo.data.JsonStore({
8902     url: 'get-images.php',
8903     root: 'images',
8904     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8905 });
8906 </code></pre>
8907  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8908  * JsonReader and HttpProxy (unless inline data is provided).</b>
8909  * @cfg {Array} fields An array of field definition objects, or field name strings.
8910  * @constructor
8911  * @param {Object} config
8912  */
8913 Roo.data.JsonStore = function(c){
8914     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8915         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8916         reader: new Roo.data.JsonReader(c, c.fields)
8917     }));
8918 };
8919 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8920  * Based on:
8921  * Ext JS Library 1.1.1
8922  * Copyright(c) 2006-2007, Ext JS, LLC.
8923  *
8924  * Originally Released Under LGPL - original licence link has changed is not relivant.
8925  *
8926  * Fork - LGPL
8927  * <script type="text/javascript">
8928  */
8929
8930  
8931 Roo.data.Field = function(config){
8932     if(typeof config == "string"){
8933         config = {name: config};
8934     }
8935     Roo.apply(this, config);
8936     
8937     if(!this.type){
8938         this.type = "auto";
8939     }
8940     
8941     var st = Roo.data.SortTypes;
8942     // named sortTypes are supported, here we look them up
8943     if(typeof this.sortType == "string"){
8944         this.sortType = st[this.sortType];
8945     }
8946     
8947     // set default sortType for strings and dates
8948     if(!this.sortType){
8949         switch(this.type){
8950             case "string":
8951                 this.sortType = st.asUCString;
8952                 break;
8953             case "date":
8954                 this.sortType = st.asDate;
8955                 break;
8956             default:
8957                 this.sortType = st.none;
8958         }
8959     }
8960
8961     // define once
8962     var stripRe = /[\$,%]/g;
8963
8964     // prebuilt conversion function for this field, instead of
8965     // switching every time we're reading a value
8966     if(!this.convert){
8967         var cv, dateFormat = this.dateFormat;
8968         switch(this.type){
8969             case "":
8970             case "auto":
8971             case undefined:
8972                 cv = function(v){ return v; };
8973                 break;
8974             case "string":
8975                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8976                 break;
8977             case "int":
8978                 cv = function(v){
8979                     return v !== undefined && v !== null && v !== '' ?
8980                            parseInt(String(v).replace(stripRe, ""), 10) : '';
8981                     };
8982                 break;
8983             case "float":
8984                 cv = function(v){
8985                     return v !== undefined && v !== null && v !== '' ?
8986                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
8987                     };
8988                 break;
8989             case "bool":
8990             case "boolean":
8991                 cv = function(v){ return v === true || v === "true" || v == 1; };
8992                 break;
8993             case "date":
8994                 cv = function(v){
8995                     if(!v){
8996                         return '';
8997                     }
8998                     if(v instanceof Date){
8999                         return v;
9000                     }
9001                     if(dateFormat){
9002                         if(dateFormat == "timestamp"){
9003                             return new Date(v*1000);
9004                         }
9005                         return Date.parseDate(v, dateFormat);
9006                     }
9007                     var parsed = Date.parse(v);
9008                     return parsed ? new Date(parsed) : null;
9009                 };
9010              break;
9011             
9012         }
9013         this.convert = cv;
9014     }
9015 };
9016
9017 Roo.data.Field.prototype = {
9018     dateFormat: null,
9019     defaultValue: "",
9020     mapping: null,
9021     sortType : null,
9022     sortDir : "ASC"
9023 };/*
9024  * Based on:
9025  * Ext JS Library 1.1.1
9026  * Copyright(c) 2006-2007, Ext JS, LLC.
9027  *
9028  * Originally Released Under LGPL - original licence link has changed is not relivant.
9029  *
9030  * Fork - LGPL
9031  * <script type="text/javascript">
9032  */
9033  
9034 // Base class for reading structured data from a data source.  This class is intended to be
9035 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9036
9037 /**
9038  * @class Roo.data.DataReader
9039  * Base class for reading structured data from a data source.  This class is intended to be
9040  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9041  */
9042
9043 Roo.data.DataReader = function(meta, recordType){
9044     
9045     this.meta = meta;
9046     
9047     this.recordType = recordType instanceof Array ? 
9048         Roo.data.Record.create(recordType) : recordType;
9049 };
9050
9051 Roo.data.DataReader.prototype = {
9052      /**
9053      * Create an empty record
9054      * @param {Object} data (optional) - overlay some values
9055      * @return {Roo.data.Record} record created.
9056      */
9057     newRow :  function(d) {
9058         var da =  {};
9059         this.recordType.prototype.fields.each(function(c) {
9060             switch( c.type) {
9061                 case 'int' : da[c.name] = 0; break;
9062                 case 'date' : da[c.name] = new Date(); break;
9063                 case 'float' : da[c.name] = 0.0; break;
9064                 case 'boolean' : da[c.name] = false; break;
9065                 default : da[c.name] = ""; break;
9066             }
9067             
9068         });
9069         return new this.recordType(Roo.apply(da, d));
9070     }
9071     
9072 };/*
9073  * Based on:
9074  * Ext JS Library 1.1.1
9075  * Copyright(c) 2006-2007, Ext JS, LLC.
9076  *
9077  * Originally Released Under LGPL - original licence link has changed is not relivant.
9078  *
9079  * Fork - LGPL
9080  * <script type="text/javascript">
9081  */
9082
9083 /**
9084  * @class Roo.data.DataProxy
9085  * @extends Roo.data.Observable
9086  * This class is an abstract base class for implementations which provide retrieval of
9087  * unformatted data objects.<br>
9088  * <p>
9089  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9090  * (of the appropriate type which knows how to parse the data object) to provide a block of
9091  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9092  * <p>
9093  * Custom implementations must implement the load method as described in
9094  * {@link Roo.data.HttpProxy#load}.
9095  */
9096 Roo.data.DataProxy = function(){
9097     this.addEvents({
9098         /**
9099          * @event beforeload
9100          * Fires before a network request is made to retrieve a data object.
9101          * @param {Object} This DataProxy object.
9102          * @param {Object} params The params parameter to the load function.
9103          */
9104         beforeload : true,
9105         /**
9106          * @event load
9107          * Fires before the load method's callback is called.
9108          * @param {Object} This DataProxy object.
9109          * @param {Object} o The data object.
9110          * @param {Object} arg The callback argument object passed to the load function.
9111          */
9112         load : true,
9113         /**
9114          * @event loadexception
9115          * Fires if an Exception occurs during data retrieval.
9116          * @param {Object} This DataProxy object.
9117          * @param {Object} o The data object.
9118          * @param {Object} arg The callback argument object passed to the load function.
9119          * @param {Object} e The Exception.
9120          */
9121         loadexception : true
9122     });
9123     Roo.data.DataProxy.superclass.constructor.call(this);
9124 };
9125
9126 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9127
9128     /**
9129      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9130      */
9131 /*
9132  * Based on:
9133  * Ext JS Library 1.1.1
9134  * Copyright(c) 2006-2007, Ext JS, LLC.
9135  *
9136  * Originally Released Under LGPL - original licence link has changed is not relivant.
9137  *
9138  * Fork - LGPL
9139  * <script type="text/javascript">
9140  */
9141 /**
9142  * @class Roo.data.MemoryProxy
9143  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9144  * to the Reader when its load method is called.
9145  * @constructor
9146  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9147  */
9148 Roo.data.MemoryProxy = function(data){
9149     if (data.data) {
9150         data = data.data;
9151     }
9152     Roo.data.MemoryProxy.superclass.constructor.call(this);
9153     this.data = data;
9154 };
9155
9156 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9157     /**
9158      * Load data from the requested source (in this case an in-memory
9159      * data object passed to the constructor), read the data object into
9160      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9161      * process that block using the passed callback.
9162      * @param {Object} params This parameter is not used by the MemoryProxy class.
9163      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9164      * object into a block of Roo.data.Records.
9165      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9166      * The function must be passed <ul>
9167      * <li>The Record block object</li>
9168      * <li>The "arg" argument from the load function</li>
9169      * <li>A boolean success indicator</li>
9170      * </ul>
9171      * @param {Object} scope The scope in which to call the callback
9172      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9173      */
9174     load : function(params, reader, callback, scope, arg){
9175         params = params || {};
9176         var result;
9177         try {
9178             result = reader.readRecords(this.data);
9179         }catch(e){
9180             this.fireEvent("loadexception", this, arg, null, e);
9181             callback.call(scope, null, arg, false);
9182             return;
9183         }
9184         callback.call(scope, result, arg, true);
9185     },
9186     
9187     // private
9188     update : function(params, records){
9189         
9190     }
9191 });/*
9192  * Based on:
9193  * Ext JS Library 1.1.1
9194  * Copyright(c) 2006-2007, Ext JS, LLC.
9195  *
9196  * Originally Released Under LGPL - original licence link has changed is not relivant.
9197  *
9198  * Fork - LGPL
9199  * <script type="text/javascript">
9200  */
9201 /**
9202  * @class Roo.data.HttpProxy
9203  * @extends Roo.data.DataProxy
9204  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9205  * configured to reference a certain URL.<br><br>
9206  * <p>
9207  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9208  * from which the running page was served.<br><br>
9209  * <p>
9210  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9211  * <p>
9212  * Be aware that to enable the browser to parse an XML document, the server must set
9213  * the Content-Type header in the HTTP response to "text/xml".
9214  * @constructor
9215  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9216  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9217  * will be used to make the request.
9218  */
9219 Roo.data.HttpProxy = function(conn){
9220     Roo.data.HttpProxy.superclass.constructor.call(this);
9221     // is conn a conn config or a real conn?
9222     this.conn = conn;
9223     this.useAjax = !conn || !conn.events;
9224   
9225 };
9226
9227 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9228     // thse are take from connection...
9229     
9230     /**
9231      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9232      */
9233     /**
9234      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9235      * extra parameters to each request made by this object. (defaults to undefined)
9236      */
9237     /**
9238      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9239      *  to each request made by this object. (defaults to undefined)
9240      */
9241     /**
9242      * @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)
9243      */
9244     /**
9245      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9246      */
9247      /**
9248      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9249      * @type Boolean
9250      */
9251   
9252
9253     /**
9254      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9255      * @type Boolean
9256      */
9257     /**
9258      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9259      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9260      * a finer-grained basis than the DataProxy events.
9261      */
9262     getConnection : function(){
9263         return this.useAjax ? Roo.Ajax : this.conn;
9264     },
9265
9266     /**
9267      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9268      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9269      * process that block using the passed callback.
9270      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9271      * for the request to the remote server.
9272      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9273      * object into a block of Roo.data.Records.
9274      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9275      * The function must be passed <ul>
9276      * <li>The Record block object</li>
9277      * <li>The "arg" argument from the load function</li>
9278      * <li>A boolean success indicator</li>
9279      * </ul>
9280      * @param {Object} scope The scope in which to call the callback
9281      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9282      */
9283     load : function(params, reader, callback, scope, arg){
9284         if(this.fireEvent("beforeload", this, params) !== false){
9285             var  o = {
9286                 params : params || {},
9287                 request: {
9288                     callback : callback,
9289                     scope : scope,
9290                     arg : arg
9291                 },
9292                 reader: reader,
9293                 callback : this.loadResponse,
9294                 scope: this
9295             };
9296             if(this.useAjax){
9297                 Roo.applyIf(o, this.conn);
9298                 if(this.activeRequest){
9299                     Roo.Ajax.abort(this.activeRequest);
9300                 }
9301                 this.activeRequest = Roo.Ajax.request(o);
9302             }else{
9303                 this.conn.request(o);
9304             }
9305         }else{
9306             callback.call(scope||this, null, arg, false);
9307         }
9308     },
9309
9310     // private
9311     loadResponse : function(o, success, response){
9312         delete this.activeRequest;
9313         if(!success){
9314             this.fireEvent("loadexception", this, o, response);
9315             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9316             return;
9317         }
9318         var result;
9319         try {
9320             result = o.reader.read(response);
9321         }catch(e){
9322             this.fireEvent("loadexception", this, o, response, e);
9323             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9324             return;
9325         }
9326         
9327         this.fireEvent("load", this, o, o.request.arg);
9328         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9329     },
9330
9331     // private
9332     update : function(dataSet){
9333
9334     },
9335
9336     // private
9337     updateResponse : function(dataSet){
9338
9339     }
9340 });/*
9341  * Based on:
9342  * Ext JS Library 1.1.1
9343  * Copyright(c) 2006-2007, Ext JS, LLC.
9344  *
9345  * Originally Released Under LGPL - original licence link has changed is not relivant.
9346  *
9347  * Fork - LGPL
9348  * <script type="text/javascript">
9349  */
9350
9351 /**
9352  * @class Roo.data.ScriptTagProxy
9353  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9354  * other than the originating domain of the running page.<br><br>
9355  * <p>
9356  * <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
9357  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9358  * <p>
9359  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9360  * source code that is used as the source inside a &lt;script> tag.<br><br>
9361  * <p>
9362  * In order for the browser to process the returned data, the server must wrap the data object
9363  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9364  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9365  * depending on whether the callback name was passed:
9366  * <p>
9367  * <pre><code>
9368 boolean scriptTag = false;
9369 String cb = request.getParameter("callback");
9370 if (cb != null) {
9371     scriptTag = true;
9372     response.setContentType("text/javascript");
9373 } else {
9374     response.setContentType("application/x-json");
9375 }
9376 Writer out = response.getWriter();
9377 if (scriptTag) {
9378     out.write(cb + "(");
9379 }
9380 out.print(dataBlock.toJsonString());
9381 if (scriptTag) {
9382     out.write(");");
9383 }
9384 </pre></code>
9385  *
9386  * @constructor
9387  * @param {Object} config A configuration object.
9388  */
9389 Roo.data.ScriptTagProxy = function(config){
9390     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9391     Roo.apply(this, config);
9392     this.head = document.getElementsByTagName("head")[0];
9393 };
9394
9395 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9396
9397 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9398     /**
9399      * @cfg {String} url The URL from which to request the data object.
9400      */
9401     /**
9402      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9403      */
9404     timeout : 30000,
9405     /**
9406      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9407      * the server the name of the callback function set up by the load call to process the returned data object.
9408      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9409      * javascript output which calls this named function passing the data object as its only parameter.
9410      */
9411     callbackParam : "callback",
9412     /**
9413      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9414      * name to the request.
9415      */
9416     nocache : true,
9417
9418     /**
9419      * Load data from the configured URL, read the data object into
9420      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9421      * process that block using the passed callback.
9422      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9423      * for the request to the remote server.
9424      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9425      * object into a block of Roo.data.Records.
9426      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9427      * The function must be passed <ul>
9428      * <li>The Record block object</li>
9429      * <li>The "arg" argument from the load function</li>
9430      * <li>A boolean success indicator</li>
9431      * </ul>
9432      * @param {Object} scope The scope in which to call the callback
9433      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9434      */
9435     load : function(params, reader, callback, scope, arg){
9436         if(this.fireEvent("beforeload", this, params) !== false){
9437
9438             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9439
9440             var url = this.url;
9441             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9442             if(this.nocache){
9443                 url += "&_dc=" + (new Date().getTime());
9444             }
9445             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9446             var trans = {
9447                 id : transId,
9448                 cb : "stcCallback"+transId,
9449                 scriptId : "stcScript"+transId,
9450                 params : params,
9451                 arg : arg,
9452                 url : url,
9453                 callback : callback,
9454                 scope : scope,
9455                 reader : reader
9456             };
9457             var conn = this;
9458
9459             window[trans.cb] = function(o){
9460                 conn.handleResponse(o, trans);
9461             };
9462
9463             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9464
9465             if(this.autoAbort !== false){
9466                 this.abort();
9467             }
9468
9469             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9470
9471             var script = document.createElement("script");
9472             script.setAttribute("src", url);
9473             script.setAttribute("type", "text/javascript");
9474             script.setAttribute("id", trans.scriptId);
9475             this.head.appendChild(script);
9476
9477             this.trans = trans;
9478         }else{
9479             callback.call(scope||this, null, arg, false);
9480         }
9481     },
9482
9483     // private
9484     isLoading : function(){
9485         return this.trans ? true : false;
9486     },
9487
9488     /**
9489      * Abort the current server request.
9490      */
9491     abort : function(){
9492         if(this.isLoading()){
9493             this.destroyTrans(this.trans);
9494         }
9495     },
9496
9497     // private
9498     destroyTrans : function(trans, isLoaded){
9499         this.head.removeChild(document.getElementById(trans.scriptId));
9500         clearTimeout(trans.timeoutId);
9501         if(isLoaded){
9502             window[trans.cb] = undefined;
9503             try{
9504                 delete window[trans.cb];
9505             }catch(e){}
9506         }else{
9507             // if hasn't been loaded, wait for load to remove it to prevent script error
9508             window[trans.cb] = function(){
9509                 window[trans.cb] = undefined;
9510                 try{
9511                     delete window[trans.cb];
9512                 }catch(e){}
9513             };
9514         }
9515     },
9516
9517     // private
9518     handleResponse : function(o, trans){
9519         this.trans = false;
9520         this.destroyTrans(trans, true);
9521         var result;
9522         try {
9523             result = trans.reader.readRecords(o);
9524         }catch(e){
9525             this.fireEvent("loadexception", this, o, trans.arg, e);
9526             trans.callback.call(trans.scope||window, null, trans.arg, false);
9527             return;
9528         }
9529         this.fireEvent("load", this, o, trans.arg);
9530         trans.callback.call(trans.scope||window, result, trans.arg, true);
9531     },
9532
9533     // private
9534     handleFailure : function(trans){
9535         this.trans = false;
9536         this.destroyTrans(trans, false);
9537         this.fireEvent("loadexception", this, null, trans.arg);
9538         trans.callback.call(trans.scope||window, null, trans.arg, false);
9539     }
9540 });/*
9541  * Based on:
9542  * Ext JS Library 1.1.1
9543  * Copyright(c) 2006-2007, Ext JS, LLC.
9544  *
9545  * Originally Released Under LGPL - original licence link has changed is not relivant.
9546  *
9547  * Fork - LGPL
9548  * <script type="text/javascript">
9549  */
9550
9551 /**
9552  * @class Roo.data.JsonReader
9553  * @extends Roo.data.DataReader
9554  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9555  * based on mappings in a provided Roo.data.Record constructor.
9556  * 
9557  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9558  * in the reply previously. 
9559  * 
9560  * <p>
9561  * Example code:
9562  * <pre><code>
9563 var RecordDef = Roo.data.Record.create([
9564     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
9565     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
9566 ]);
9567 var myReader = new Roo.data.JsonReader({
9568     totalProperty: "results",    // The property which contains the total dataset size (optional)
9569     root: "rows",                // The property which contains an Array of row objects
9570     id: "id"                     // The property within each row object that provides an ID for the record (optional)
9571 }, RecordDef);
9572 </code></pre>
9573  * <p>
9574  * This would consume a JSON file like this:
9575  * <pre><code>
9576 { 'results': 2, 'rows': [
9577     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9578     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9579 }
9580 </code></pre>
9581  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9582  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9583  * paged from the remote server.
9584  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9585  * @cfg {String} root name of the property which contains the Array of row objects.
9586  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9587  * @constructor
9588  * Create a new JsonReader
9589  * @param {Object} meta Metadata configuration options
9590  * @param {Object} recordType Either an Array of field definition objects,
9591  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9592  */
9593 Roo.data.JsonReader = function(meta, recordType){
9594     
9595     meta = meta || {};
9596     // set some defaults:
9597     Roo.applyIf(meta, {
9598         totalProperty: 'total',
9599         successProperty : 'success',
9600         root : 'data',
9601         id : 'id'
9602     });
9603     
9604     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9605 };
9606 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9607     
9608     /**
9609      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
9610      * Used by Store query builder to append _requestMeta to params.
9611      * 
9612      */
9613     metaFromRemote : false,
9614     /**
9615      * This method is only used by a DataProxy which has retrieved data from a remote server.
9616      * @param {Object} response The XHR object which contains the JSON data in its responseText.
9617      * @return {Object} data A data block which is used by an Roo.data.Store object as
9618      * a cache of Roo.data.Records.
9619      */
9620     read : function(response){
9621         var json = response.responseText;
9622        
9623         var o = /* eval:var:o */ eval("("+json+")");
9624         if(!o) {
9625             throw {message: "JsonReader.read: Json object not found"};
9626         }
9627         
9628         if(o.metaData){
9629             
9630             delete this.ef;
9631             this.metaFromRemote = true;
9632             this.meta = o.metaData;
9633             this.recordType = Roo.data.Record.create(o.metaData.fields);
9634             this.onMetaChange(this.meta, this.recordType, o);
9635         }
9636         return this.readRecords(o);
9637     },
9638
9639     // private function a store will implement
9640     onMetaChange : function(meta, recordType, o){
9641
9642     },
9643
9644     /**
9645          * @ignore
9646          */
9647     simpleAccess: function(obj, subsc) {
9648         return obj[subsc];
9649     },
9650
9651         /**
9652          * @ignore
9653          */
9654     getJsonAccessor: function(){
9655         var re = /[\[\.]/;
9656         return function(expr) {
9657             try {
9658                 return(re.test(expr))
9659                     ? new Function("obj", "return obj." + expr)
9660                     : function(obj){
9661                         return obj[expr];
9662                     };
9663             } catch(e){}
9664             return Roo.emptyFn;
9665         };
9666     }(),
9667
9668     /**
9669      * Create a data block containing Roo.data.Records from an XML document.
9670      * @param {Object} o An object which contains an Array of row objects in the property specified
9671      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9672      * which contains the total size of the dataset.
9673      * @return {Object} data A data block which is used by an Roo.data.Store object as
9674      * a cache of Roo.data.Records.
9675      */
9676     readRecords : function(o){
9677         /**
9678          * After any data loads, the raw JSON data is available for further custom processing.
9679          * @type Object
9680          */
9681         this.o = o;
9682         var s = this.meta, Record = this.recordType,
9683             f = Record.prototype.fields, fi = f.items, fl = f.length;
9684
9685 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
9686         if (!this.ef) {
9687             if(s.totalProperty) {
9688                     this.getTotal = this.getJsonAccessor(s.totalProperty);
9689                 }
9690                 if(s.successProperty) {
9691                     this.getSuccess = this.getJsonAccessor(s.successProperty);
9692                 }
9693                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9694                 if (s.id) {
9695                         var g = this.getJsonAccessor(s.id);
9696                         this.getId = function(rec) {
9697                                 var r = g(rec);
9698                                 return (r === undefined || r === "") ? null : r;
9699                         };
9700                 } else {
9701                         this.getId = function(){return null;};
9702                 }
9703             this.ef = [];
9704             for(var jj = 0; jj < fl; jj++){
9705                 f = fi[jj];
9706                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9707                 this.ef[jj] = this.getJsonAccessor(map);
9708             }
9709         }
9710
9711         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9712         if(s.totalProperty){
9713             var vt = parseInt(this.getTotal(o), 10);
9714             if(!isNaN(vt)){
9715                 totalRecords = vt;
9716             }
9717         }
9718         if(s.successProperty){
9719             var vs = this.getSuccess(o);
9720             if(vs === false || vs === 'false'){
9721                 success = false;
9722             }
9723         }
9724         var records = [];
9725             for(var i = 0; i < c; i++){
9726                     var n = root[i];
9727                 var values = {};
9728                 var id = this.getId(n);
9729                 for(var j = 0; j < fl; j++){
9730                     f = fi[j];
9731                 var v = this.ef[j](n);
9732                 if (!f.convert) {
9733                     Roo.log('missing convert for ' + f.name);
9734                     Roo.log(f);
9735                     continue;
9736                 }
9737                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9738                 }
9739                 var record = new Record(values, id);
9740                 record.json = n;
9741                 records[i] = record;
9742             }
9743             return {
9744             raw : o,
9745                 success : success,
9746                 records : records,
9747                 totalRecords : totalRecords
9748             };
9749     }
9750 });/*
9751  * Based on:
9752  * Ext JS Library 1.1.1
9753  * Copyright(c) 2006-2007, Ext JS, LLC.
9754  *
9755  * Originally Released Under LGPL - original licence link has changed is not relivant.
9756  *
9757  * Fork - LGPL
9758  * <script type="text/javascript">
9759  */
9760
9761 /**
9762  * @class Roo.data.ArrayReader
9763  * @extends Roo.data.DataReader
9764  * Data reader class to create an Array of Roo.data.Record objects from an Array.
9765  * Each element of that Array represents a row of data fields. The
9766  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9767  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9768  * <p>
9769  * Example code:.
9770  * <pre><code>
9771 var RecordDef = Roo.data.Record.create([
9772     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
9773     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
9774 ]);
9775 var myReader = new Roo.data.ArrayReader({
9776     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
9777 }, RecordDef);
9778 </code></pre>
9779  * <p>
9780  * This would consume an Array like this:
9781  * <pre><code>
9782 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9783   </code></pre>
9784  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9785  * @constructor
9786  * Create a new JsonReader
9787  * @param {Object} meta Metadata configuration options.
9788  * @param {Object} recordType Either an Array of field definition objects
9789  * as specified to {@link Roo.data.Record#create},
9790  * or an {@link Roo.data.Record} object
9791  * created using {@link Roo.data.Record#create}.
9792  */
9793 Roo.data.ArrayReader = function(meta, recordType){
9794     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9795 };
9796
9797 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9798     /**
9799      * Create a data block containing Roo.data.Records from an XML document.
9800      * @param {Object} o An Array of row objects which represents the dataset.
9801      * @return {Object} data A data block which is used by an Roo.data.Store object as
9802      * a cache of Roo.data.Records.
9803      */
9804     readRecords : function(o){
9805         var sid = this.meta ? this.meta.id : null;
9806         var recordType = this.recordType, fields = recordType.prototype.fields;
9807         var records = [];
9808         var root = o;
9809             for(var i = 0; i < root.length; i++){
9810                     var n = root[i];
9811                 var values = {};
9812                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9813                 for(var j = 0, jlen = fields.length; j < jlen; j++){
9814                 var f = fields.items[j];
9815                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9816                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9817                 v = f.convert(v);
9818                 values[f.name] = v;
9819             }
9820                 var record = new recordType(values, id);
9821                 record.json = n;
9822                 records[records.length] = record;
9823             }
9824             return {
9825                 records : records,
9826                 totalRecords : records.length
9827             };
9828     }
9829 });/*
9830  * - LGPL
9831  * * 
9832  */
9833
9834 /**
9835  * @class Roo.bootstrap.ComboBox
9836  * @extends Roo.bootstrap.TriggerField
9837  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9838  * @cfg {Boolean} append (true|false) default false
9839  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9840  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9841  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9842  * @constructor
9843  * Create a new ComboBox.
9844  * @param {Object} config Configuration options
9845  */
9846 Roo.bootstrap.ComboBox = function(config){
9847     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9848     this.addEvents({
9849         /**
9850          * @event expand
9851          * Fires when the dropdown list is expanded
9852              * @param {Roo.bootstrap.ComboBox} combo This combo box
9853              */
9854         'expand' : true,
9855         /**
9856          * @event collapse
9857          * Fires when the dropdown list is collapsed
9858              * @param {Roo.bootstrap.ComboBox} combo This combo box
9859              */
9860         'collapse' : true,
9861         /**
9862          * @event beforeselect
9863          * Fires before a list item is selected. Return false to cancel the selection.
9864              * @param {Roo.bootstrap.ComboBox} combo This combo box
9865              * @param {Roo.data.Record} record The data record returned from the underlying store
9866              * @param {Number} index The index of the selected item in the dropdown list
9867              */
9868         'beforeselect' : true,
9869         /**
9870          * @event select
9871          * Fires when a list item is selected
9872              * @param {Roo.bootstrap.ComboBox} combo This combo box
9873              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9874              * @param {Number} index The index of the selected item in the dropdown list
9875              */
9876         'select' : true,
9877         /**
9878          * @event beforequery
9879          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9880          * The event object passed has these properties:
9881              * @param {Roo.bootstrap.ComboBox} combo This combo box
9882              * @param {String} query The query
9883              * @param {Boolean} forceAll true to force "all" query
9884              * @param {Boolean} cancel true to cancel the query
9885              * @param {Object} e The query event object
9886              */
9887         'beforequery': true,
9888          /**
9889          * @event add
9890          * Fires when the 'add' icon is pressed (add a listener to enable add button)
9891              * @param {Roo.bootstrap.ComboBox} combo This combo box
9892              */
9893         'add' : true,
9894         /**
9895          * @event edit
9896          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9897              * @param {Roo.bootstrap.ComboBox} combo This combo box
9898              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9899              */
9900         'edit' : true,
9901         /**
9902          * @event remove
9903          * Fires when the remove value from the combobox array
9904              * @param {Roo.bootstrap.ComboBox} combo This combo box
9905              */
9906         'remove' : true
9907         
9908     });
9909     
9910     this.item = [];
9911     this.tickItems = [];
9912     
9913     this.selectedIndex = -1;
9914     if(this.mode == 'local'){
9915         if(config.queryDelay === undefined){
9916             this.queryDelay = 10;
9917         }
9918         if(config.minChars === undefined){
9919             this.minChars = 0;
9920         }
9921     }
9922 };
9923
9924 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9925      
9926     /**
9927      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9928      * rendering into an Roo.Editor, defaults to false)
9929      */
9930     /**
9931      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9932      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9933      */
9934     /**
9935      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9936      */
9937     /**
9938      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9939      * the dropdown list (defaults to undefined, with no header element)
9940      */
9941
9942      /**
9943      * @cfg {String/Roo.Template} tpl The template to use to render the output
9944      */
9945      
9946      /**
9947      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9948      */
9949     listWidth: undefined,
9950     /**
9951      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9952      * mode = 'remote' or 'text' if mode = 'local')
9953      */
9954     displayField: undefined,
9955     /**
9956      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9957      * mode = 'remote' or 'value' if mode = 'local'). 
9958      * Note: use of a valueField requires the user make a selection
9959      * in order for a value to be mapped.
9960      */
9961     valueField: undefined,
9962     
9963     
9964     /**
9965      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9966      * field's data value (defaults to the underlying DOM element's name)
9967      */
9968     hiddenName: undefined,
9969     /**
9970      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9971      */
9972     listClass: '',
9973     /**
9974      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9975      */
9976     selectedClass: 'active',
9977     
9978     /**
9979      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9980      */
9981     shadow:'sides',
9982     /**
9983      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9984      * anchor positions (defaults to 'tl-bl')
9985      */
9986     listAlign: 'tl-bl?',
9987     /**
9988      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9989      */
9990     maxHeight: 300,
9991     /**
9992      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
9993      * query specified by the allQuery config option (defaults to 'query')
9994      */
9995     triggerAction: 'query',
9996     /**
9997      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9998      * (defaults to 4, does not apply if editable = false)
9999      */
10000     minChars : 4,
10001     /**
10002      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10003      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10004      */
10005     typeAhead: false,
10006     /**
10007      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10008      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10009      */
10010     queryDelay: 500,
10011     /**
10012      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10013      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10014      */
10015     pageSize: 0,
10016     /**
10017      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10018      * when editable = true (defaults to false)
10019      */
10020     selectOnFocus:false,
10021     /**
10022      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10023      */
10024     queryParam: 'query',
10025     /**
10026      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10027      * when mode = 'remote' (defaults to 'Loading...')
10028      */
10029     loadingText: 'Loading...',
10030     /**
10031      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10032      */
10033     resizable: false,
10034     /**
10035      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10036      */
10037     handleHeight : 8,
10038     /**
10039      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10040      * traditional select (defaults to true)
10041      */
10042     editable: true,
10043     /**
10044      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10045      */
10046     allQuery: '',
10047     /**
10048      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10049      */
10050     mode: 'remote',
10051     /**
10052      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10053      * listWidth has a higher value)
10054      */
10055     minListWidth : 70,
10056     /**
10057      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10058      * allow the user to set arbitrary text into the field (defaults to false)
10059      */
10060     forceSelection:false,
10061     /**
10062      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10063      * if typeAhead = true (defaults to 250)
10064      */
10065     typeAheadDelay : 250,
10066     /**
10067      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10068      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10069      */
10070     valueNotFoundText : undefined,
10071     /**
10072      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10073      */
10074     blockFocus : false,
10075     
10076     /**
10077      * @cfg {Boolean} disableClear Disable showing of clear button.
10078      */
10079     disableClear : false,
10080     /**
10081      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10082      */
10083     alwaysQuery : false,
10084     
10085     /**
10086      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10087      */
10088     multiple : false,
10089     
10090     //private
10091     addicon : false,
10092     editicon: false,
10093     
10094     page: 0,
10095     hasQuery: false,
10096     append: false,
10097     loadNext: false,
10098     autoFocus : true,
10099     tickable : false,
10100     btnPosition : 'right',
10101     
10102     // element that contains real text value.. (when hidden is used..)
10103     
10104     getAutoCreate : function()
10105     {
10106         var cfg = false;
10107         
10108         /*
10109          *  Normal ComboBox
10110          */
10111         if(!this.tickable){
10112             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10113             return cfg;
10114         }
10115         
10116         /*
10117          *  ComboBox with tickable selections
10118          */
10119              
10120         var align = this.labelAlign || this.parentLabelAlign();
10121         
10122         cfg = {
10123             cls : 'form-group roo-combobox-tickable' //input-group
10124         };
10125         
10126         
10127         var buttons = {
10128             tag : 'div',
10129             cls : 'tickable-buttons',
10130             cn : [
10131                 {
10132                     tag : 'button',
10133                     type : 'button',
10134                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10135                     html : 'Edit'
10136                 },
10137                 {
10138                     tag : 'button',
10139                     type : 'button',
10140                     name : 'ok',
10141                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10142                     html : 'Done'
10143                 },
10144                 {
10145                     tag : 'button',
10146                     type : 'button',
10147                     name : 'cancel',
10148                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10149                     html : 'Cancel'
10150                 }
10151             ]
10152         };
10153         
10154         var _this = this;
10155         Roo.each(buttons.cn, function(c){
10156             if (_this.size) {
10157                 c.cls += ' btn-' + _this.size;
10158             }
10159
10160             if (_this.disabled) {
10161                 c.disabled = true;
10162             }
10163         });
10164         
10165         var box = {
10166             tag: 'div',
10167             cn: [
10168                 {
10169                     tag: 'input',
10170                     type : 'hidden',
10171                     cls: 'form-hidden-field'
10172                 },
10173                 {
10174                     tag: 'ul',
10175                     cls: 'select2-choices',
10176                     cn:[
10177                         {
10178                             tag: 'li',
10179                             cls: 'select2-search-field',
10180                             cn: [
10181
10182                                 buttons
10183                             ]
10184                         }
10185                     ]
10186                 }
10187             ]
10188         }
10189         
10190         var combobox = {
10191             cls: 'select2-container input-group select2-container-multi',
10192             cn: [
10193                 box,
10194                 {
10195                     tag: 'ul',
10196                     cls: 'typeahead typeahead-long dropdown-menu',
10197                     style: 'display:none; max-height:' + this.maxHeight + 'px;'
10198                 }
10199             ]
10200         };
10201         
10202         if (align ==='left' && this.fieldLabel.length) {
10203             
10204                 Roo.log("left and has label");
10205                 cfg.cn = [
10206                     
10207                     {
10208                         tag: 'label',
10209                         'for' :  id,
10210                         cls : 'control-label col-sm-' + this.labelWidth,
10211                         html : this.fieldLabel
10212                         
10213                     },
10214                     {
10215                         cls : "col-sm-" + (12 - this.labelWidth), 
10216                         cn: [
10217                             combobox
10218                         ]
10219                     }
10220                     
10221                 ];
10222         } else if ( this.fieldLabel.length) {
10223                 Roo.log(" label");
10224                  cfg.cn = [
10225                    
10226                     {
10227                         tag: 'label',
10228                         //cls : 'input-group-addon',
10229                         html : this.fieldLabel
10230                         
10231                     },
10232                     
10233                     combobox
10234                     
10235                 ];
10236
10237         } else {
10238             
10239                 Roo.log(" no label && no align");
10240                 cfg = combobox
10241                      
10242                 
10243         }
10244          
10245         var settings=this;
10246         ['xs','sm','md','lg'].map(function(size){
10247             if (settings[size]) {
10248                 cfg.cls += ' col-' + size + '-' + settings[size];
10249             }
10250         });
10251         
10252         return cfg;
10253         
10254     },
10255     
10256     // private
10257     initEvents: function()
10258     {
10259         
10260         if (!this.store) {
10261             throw "can not find store for combo";
10262         }
10263         this.store = Roo.factory(this.store, Roo.data);
10264         
10265         if(this.tickable){
10266             this.initTickableEvnets();
10267             return;
10268         }
10269         
10270         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10271         
10272         
10273         if(this.hiddenName){
10274             
10275             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10276             
10277             this.hiddenField.dom.value =
10278                 this.hiddenValue !== undefined ? this.hiddenValue :
10279                 this.value !== undefined ? this.value : '';
10280
10281             // prevent input submission
10282             this.el.dom.removeAttribute('name');
10283             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10284              
10285              
10286         }
10287         //if(Roo.isGecko){
10288         //    this.el.dom.setAttribute('autocomplete', 'off');
10289         //}
10290
10291         var cls = 'x-combo-list';
10292         this.list = this.el.select('ul.dropdown-menu',true).first();
10293
10294         //this.list = new Roo.Layer({
10295         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10296         //});
10297         
10298         var _this = this;
10299         
10300         (function(){
10301             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10302             _this.list.setWidth(lw);
10303         }).defer(100);
10304         
10305         this.list.on('mouseover', this.onViewOver, this);
10306         this.list.on('mousemove', this.onViewMove, this);
10307         
10308         this.list.on('scroll', this.onViewScroll, this);
10309         
10310         /*
10311         this.list.swallowEvent('mousewheel');
10312         this.assetHeight = 0;
10313
10314         if(this.title){
10315             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10316             this.assetHeight += this.header.getHeight();
10317         }
10318
10319         this.innerList = this.list.createChild({cls:cls+'-inner'});
10320         this.innerList.on('mouseover', this.onViewOver, this);
10321         this.innerList.on('mousemove', this.onViewMove, this);
10322         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10323         
10324         if(this.allowBlank && !this.pageSize && !this.disableClear){
10325             this.footer = this.list.createChild({cls:cls+'-ft'});
10326             this.pageTb = new Roo.Toolbar(this.footer);
10327            
10328         }
10329         if(this.pageSize){
10330             this.footer = this.list.createChild({cls:cls+'-ft'});
10331             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10332                     {pageSize: this.pageSize});
10333             
10334         }
10335         
10336         if (this.pageTb && this.allowBlank && !this.disableClear) {
10337             var _this = this;
10338             this.pageTb.add(new Roo.Toolbar.Fill(), {
10339                 cls: 'x-btn-icon x-btn-clear',
10340                 text: '&#160;',
10341                 handler: function()
10342                 {
10343                     _this.collapse();
10344                     _this.clearValue();
10345                     _this.onSelect(false, -1);
10346                 }
10347             });
10348         }
10349         if (this.footer) {
10350             this.assetHeight += this.footer.getHeight();
10351         }
10352         */
10353             
10354         if(!this.tpl){
10355             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10356         }
10357
10358         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10359             singleSelect:true, store: this.store, selectedClass: this.selectedClass
10360         });
10361         //this.view.wrapEl.setDisplayed(false);
10362         this.view.on('click', this.onViewClick, this);
10363         
10364         
10365         
10366         this.store.on('beforeload', this.onBeforeLoad, this);
10367         this.store.on('load', this.onLoad, this);
10368         this.store.on('loadexception', this.onLoadException, this);
10369         /*
10370         if(this.resizable){
10371             this.resizer = new Roo.Resizable(this.list,  {
10372                pinned:true, handles:'se'
10373             });
10374             this.resizer.on('resize', function(r, w, h){
10375                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10376                 this.listWidth = w;
10377                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10378                 this.restrictHeight();
10379             }, this);
10380             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10381         }
10382         */
10383         if(!this.editable){
10384             this.editable = true;
10385             this.setEditable(false);
10386         }
10387         
10388         /*
10389         
10390         if (typeof(this.events.add.listeners) != 'undefined') {
10391             
10392             this.addicon = this.wrap.createChild(
10393                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
10394        
10395             this.addicon.on('click', function(e) {
10396                 this.fireEvent('add', this);
10397             }, this);
10398         }
10399         if (typeof(this.events.edit.listeners) != 'undefined') {
10400             
10401             this.editicon = this.wrap.createChild(
10402                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
10403             if (this.addicon) {
10404                 this.editicon.setStyle('margin-left', '40px');
10405             }
10406             this.editicon.on('click', function(e) {
10407                 
10408                 // we fire even  if inothing is selected..
10409                 this.fireEvent('edit', this, this.lastData );
10410                 
10411             }, this);
10412         }
10413         */
10414         
10415         this.keyNav = new Roo.KeyNav(this.inputEl(), {
10416             "up" : function(e){
10417                 this.inKeyMode = true;
10418                 this.selectPrev();
10419             },
10420
10421             "down" : function(e){
10422                 if(!this.isExpanded()){
10423                     this.onTriggerClick();
10424                 }else{
10425                     this.inKeyMode = true;
10426                     this.selectNext();
10427                 }
10428             },
10429
10430             "enter" : function(e){
10431 //                this.onViewClick();
10432                 //return true;
10433                 this.collapse();
10434                 
10435                 if(this.fireEvent("specialkey", this, e)){
10436                     this.onViewClick(false);
10437                 }
10438                 
10439                 return true;
10440             },
10441
10442             "esc" : function(e){
10443                 this.collapse();
10444             },
10445
10446             "tab" : function(e){
10447                 this.collapse();
10448                 
10449                 if(this.fireEvent("specialkey", this, e)){
10450                     this.onViewClick(false);
10451                 }
10452                 
10453                 return true;
10454             },
10455
10456             scope : this,
10457
10458             doRelay : function(foo, bar, hname){
10459                 if(hname == 'down' || this.scope.isExpanded()){
10460                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10461                 }
10462                 return true;
10463             },
10464
10465             forceKeyDown: true
10466         });
10467         
10468         
10469         this.queryDelay = Math.max(this.queryDelay || 10,
10470                 this.mode == 'local' ? 10 : 250);
10471         
10472         
10473         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10474         
10475         if(this.typeAhead){
10476             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10477         }
10478         if(this.editable !== false){
10479             this.inputEl().on("keyup", this.onKeyUp, this);
10480         }
10481         if(this.forceSelection){
10482             this.inputEl().on('blur', this.doForce, this);
10483         }
10484         
10485         if(this.multiple){
10486             this.choices = this.el.select('ul.select2-choices', true).first();
10487             this.searchField = this.el.select('ul li.select2-search-field', true).first();
10488         }
10489     },
10490     
10491     initTickableEvnets: function()
10492     {   
10493         if(this.hiddenName){
10494             
10495             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10496             
10497             this.hiddenField.dom.value =
10498                 this.hiddenValue !== undefined ? this.hiddenValue :
10499                 this.value !== undefined ? this.value : '';
10500
10501             // prevent input submission
10502             this.el.dom.removeAttribute('name');
10503             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10504              
10505              
10506         }
10507         
10508         this.list = this.el.select('ul.dropdown-menu',true).first();
10509         
10510         this.choices = this.el.select('ul.select2-choices', true).first();
10511         this.searchField = this.el.select('ul li.select2-search-field', true).first();
10512         
10513         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10514         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10515         
10516         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10517         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10518         
10519         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10520         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10521         
10522         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10523         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10524         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10525         
10526         this.okBtn.hide();
10527         this.cancelBtn.hide();
10528         
10529         var _this = this;
10530         
10531         (function(){
10532             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10533             _this.list.setWidth(lw);
10534         }).defer(100);
10535         
10536         this.list.on('mouseover', this.onViewOver, this);
10537         this.list.on('mousemove', this.onViewMove, this);
10538         
10539         this.list.on('scroll', this.onViewScroll, this);
10540         
10541         if(!this.tpl){
10542             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>';
10543         }
10544
10545         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10546             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10547         });
10548         
10549         //this.view.wrapEl.setDisplayed(false);
10550         this.view.on('click', this.onViewClick, this);
10551         
10552         
10553         
10554         this.store.on('beforeload', this.onBeforeLoad, this);
10555         this.store.on('load', this.onLoad, this);
10556         this.store.on('loadexception', this.onLoadException, this);
10557         
10558 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
10559 //            "up" : function(e){
10560 //                this.inKeyMode = true;
10561 //                this.selectPrev();
10562 //            },
10563 //
10564 //            "down" : function(e){
10565 //                if(!this.isExpanded()){
10566 //                    this.onTriggerClick();
10567 //                }else{
10568 //                    this.inKeyMode = true;
10569 //                    this.selectNext();
10570 //                }
10571 //            },
10572 //
10573 //            "enter" : function(e){
10574 ////                this.onViewClick();
10575 //                //return true;
10576 //                this.collapse();
10577 //                
10578 //                if(this.fireEvent("specialkey", this, e)){
10579 //                    this.onViewClick(false);
10580 //                }
10581 //                
10582 //                return true;
10583 //            },
10584 //
10585 //            "esc" : function(e){
10586 //                this.collapse();
10587 //            },
10588 //
10589 //            "tab" : function(e){
10590 //                this.collapse();
10591 //                
10592 //                if(this.fireEvent("specialkey", this, e)){
10593 //                    this.onViewClick(false);
10594 //                }
10595 //                
10596 //                return true;
10597 //            },
10598 //
10599 //            scope : this,
10600 //
10601 //            doRelay : function(foo, bar, hname){
10602 //                if(hname == 'down' || this.scope.isExpanded()){
10603 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10604 //                }
10605 //                return true;
10606 //            },
10607 //
10608 //            forceKeyDown: true
10609 //        });
10610         
10611         
10612         this.queryDelay = Math.max(this.queryDelay || 10,
10613                 this.mode == 'local' ? 10 : 250);
10614         
10615         
10616         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10617         
10618         if(this.typeAhead){
10619             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10620         }
10621     },
10622
10623     onDestroy : function(){
10624         if(this.view){
10625             this.view.setStore(null);
10626             this.view.el.removeAllListeners();
10627             this.view.el.remove();
10628             this.view.purgeListeners();
10629         }
10630         if(this.list){
10631             this.list.dom.innerHTML  = '';
10632         }
10633         
10634         if(this.store){
10635             this.store.un('beforeload', this.onBeforeLoad, this);
10636             this.store.un('load', this.onLoad, this);
10637             this.store.un('loadexception', this.onLoadException, this);
10638         }
10639         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10640     },
10641
10642     // private
10643     fireKey : function(e){
10644         if(e.isNavKeyPress() && !this.list.isVisible()){
10645             this.fireEvent("specialkey", this, e);
10646         }
10647     },
10648
10649     // private
10650     onResize: function(w, h){
10651 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10652 //        
10653 //        if(typeof w != 'number'){
10654 //            // we do not handle it!?!?
10655 //            return;
10656 //        }
10657 //        var tw = this.trigger.getWidth();
10658 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
10659 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
10660 //        var x = w - tw;
10661 //        this.inputEl().setWidth( this.adjustWidth('input', x));
10662 //            
10663 //        //this.trigger.setStyle('left', x+'px');
10664 //        
10665 //        if(this.list && this.listWidth === undefined){
10666 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10667 //            this.list.setWidth(lw);
10668 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10669 //        }
10670         
10671     
10672         
10673     },
10674
10675     /**
10676      * Allow or prevent the user from directly editing the field text.  If false is passed,
10677      * the user will only be able to select from the items defined in the dropdown list.  This method
10678      * is the runtime equivalent of setting the 'editable' config option at config time.
10679      * @param {Boolean} value True to allow the user to directly edit the field text
10680      */
10681     setEditable : function(value){
10682         if(value == this.editable){
10683             return;
10684         }
10685         this.editable = value;
10686         if(!value){
10687             this.inputEl().dom.setAttribute('readOnly', true);
10688             this.inputEl().on('mousedown', this.onTriggerClick,  this);
10689             this.inputEl().addClass('x-combo-noedit');
10690         }else{
10691             this.inputEl().dom.setAttribute('readOnly', false);
10692             this.inputEl().un('mousedown', this.onTriggerClick,  this);
10693             this.inputEl().removeClass('x-combo-noedit');
10694         }
10695     },
10696
10697     // private
10698     
10699     onBeforeLoad : function(combo,opts){
10700         if(!this.hasFocus){
10701             return;
10702         }
10703          if (!opts.add) {
10704             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10705          }
10706         this.restrictHeight();
10707         this.selectedIndex = -1;
10708     },
10709
10710     // private
10711     onLoad : function(){
10712         
10713         this.hasQuery = false;
10714         
10715         if(!this.hasFocus){
10716             return;
10717         }
10718         
10719         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10720             this.loading.hide();
10721         }
10722         
10723         if(this.store.getCount() > 0){
10724             this.expand();
10725             this.restrictHeight();
10726             if(this.lastQuery == this.allQuery){
10727                 if(this.editable && !this.tickable){
10728                     this.inputEl().dom.select();
10729                 }
10730                 if(!this.selectByValue(this.value, true) && this.autoFocus){
10731                     this.select(0, true);
10732                 }
10733             }else{
10734                 if(this.autoFocus){
10735                     this.selectNext();
10736                 }
10737                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10738                     this.taTask.delay(this.typeAheadDelay);
10739                 }
10740             }
10741         }else{
10742             this.onEmptyResults();
10743         }
10744         
10745         //this.el.focus();
10746     },
10747     // private
10748     onLoadException : function()
10749     {
10750         this.hasQuery = false;
10751         
10752         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10753             this.loading.hide();
10754         }
10755         
10756         this.collapse();
10757         Roo.log(this.store.reader.jsonData);
10758         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10759             // fixme
10760             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10761         }
10762         
10763         
10764     },
10765     // private
10766     onTypeAhead : function(){
10767         if(this.store.getCount() > 0){
10768             var r = this.store.getAt(0);
10769             var newValue = r.data[this.displayField];
10770             var len = newValue.length;
10771             var selStart = this.getRawValue().length;
10772             
10773             if(selStart != len){
10774                 this.setRawValue(newValue);
10775                 this.selectText(selStart, newValue.length);
10776             }
10777         }
10778     },
10779
10780     // private
10781     onSelect : function(record, index){
10782         
10783         if(this.fireEvent('beforeselect', this, record, index) !== false){
10784         
10785             this.setFromData(index > -1 ? record.data : false);
10786             
10787             this.collapse();
10788             this.fireEvent('select', this, record, index);
10789         }
10790     },
10791
10792     /**
10793      * Returns the currently selected field value or empty string if no value is set.
10794      * @return {String} value The selected value
10795      */
10796     getValue : function(){
10797         
10798         if(this.multiple){
10799             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10800         }
10801         
10802         if(this.valueField){
10803             return typeof this.value != 'undefined' ? this.value : '';
10804         }else{
10805             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10806         }
10807     },
10808
10809     /**
10810      * Clears any text/value currently set in the field
10811      */
10812     clearValue : function(){
10813         if(this.hiddenField){
10814             this.hiddenField.dom.value = '';
10815         }
10816         this.value = '';
10817         this.setRawValue('');
10818         this.lastSelectionText = '';
10819         
10820     },
10821
10822     /**
10823      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
10824      * will be displayed in the field.  If the value does not match the data value of an existing item,
10825      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10826      * Otherwise the field will be blank (although the value will still be set).
10827      * @param {String} value The value to match
10828      */
10829     setValue : function(v){
10830         if(this.multiple){
10831             this.syncValue();
10832             return;
10833         }
10834         
10835         var text = v;
10836         if(this.valueField){
10837             var r = this.findRecord(this.valueField, v);
10838             if(r){
10839                 text = r.data[this.displayField];
10840             }else if(this.valueNotFoundText !== undefined){
10841                 text = this.valueNotFoundText;
10842             }
10843         }
10844         this.lastSelectionText = text;
10845         if(this.hiddenField){
10846             this.hiddenField.dom.value = v;
10847         }
10848         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10849         this.value = v;
10850     },
10851     /**
10852      * @property {Object} the last set data for the element
10853      */
10854     
10855     lastData : false,
10856     /**
10857      * Sets the value of the field based on a object which is related to the record format for the store.
10858      * @param {Object} value the value to set as. or false on reset?
10859      */
10860     setFromData : function(o){
10861         
10862         if(this.multiple){
10863             this.addItem(o);
10864             return;
10865         }
10866             
10867         var dv = ''; // display value
10868         var vv = ''; // value value..
10869         this.lastData = o;
10870         if (this.displayField) {
10871             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10872         } else {
10873             // this is an error condition!!!
10874             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
10875         }
10876         
10877         if(this.valueField){
10878             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10879         }
10880         
10881         if(this.hiddenField){
10882             this.hiddenField.dom.value = vv;
10883             
10884             this.lastSelectionText = dv;
10885             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10886             this.value = vv;
10887             return;
10888         }
10889         // no hidden field.. - we store the value in 'value', but still display
10890         // display field!!!!
10891         this.lastSelectionText = dv;
10892         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10893         this.value = vv;
10894         
10895         
10896     },
10897     // private
10898     reset : function(){
10899         // overridden so that last data is reset..
10900         this.setValue(this.originalValue);
10901         this.clearInvalid();
10902         this.lastData = false;
10903         if (this.view) {
10904             this.view.clearSelections();
10905         }
10906     },
10907     // private
10908     findRecord : function(prop, value){
10909         var record;
10910         if(this.store.getCount() > 0){
10911             this.store.each(function(r){
10912                 if(r.data[prop] == value){
10913                     record = r;
10914                     return false;
10915                 }
10916                 return true;
10917             });
10918         }
10919         return record;
10920     },
10921     
10922     getName: function()
10923     {
10924         // returns hidden if it's set..
10925         if (!this.rendered) {return ''};
10926         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
10927         
10928     },
10929     // private
10930     onViewMove : function(e, t){
10931         this.inKeyMode = false;
10932     },
10933
10934     // private
10935     onViewOver : function(e, t){
10936         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10937             return;
10938         }
10939         var item = this.view.findItemFromChild(t);
10940         
10941         if(item){
10942             var index = this.view.indexOf(item);
10943             this.select(index, false);
10944         }
10945     },
10946
10947     // private
10948     onViewClick : function(view, doFocus, el, e)
10949     {
10950         var index = this.view.getSelectedIndexes()[0];
10951         
10952         var r = this.store.getAt(index);
10953         
10954         if(this.tickable){
10955             
10956             if(e.getTarget().nodeName.toLowerCase() != 'input'){
10957                 return;
10958             }
10959             
10960             var rm = false;
10961             var _this = this;
10962             
10963             Roo.each(this.tickItems, function(v,k){
10964                 
10965                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10966                     _this.tickItems.splice(k, 1);
10967                     rm = true;
10968                     return;
10969                 }
10970             })
10971             
10972             if(rm){
10973                 return;
10974             }
10975             
10976             this.tickItems.push(r.data);
10977             return;
10978         }
10979         
10980         if(r){
10981             this.onSelect(r, index);
10982         }
10983         if(doFocus !== false && !this.blockFocus){
10984             this.inputEl().focus();
10985         }
10986     },
10987
10988     // private
10989     restrictHeight : function(){
10990         //this.innerList.dom.style.height = '';
10991         //var inner = this.innerList.dom;
10992         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10993         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10994         //this.list.beginUpdate();
10995         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10996         this.list.alignTo(this.inputEl(), this.listAlign);
10997         //this.list.endUpdate();
10998     },
10999
11000     // private
11001     onEmptyResults : function(){
11002         this.collapse();
11003     },
11004
11005     /**
11006      * Returns true if the dropdown list is expanded, else false.
11007      */
11008     isExpanded : function(){
11009         return this.list.isVisible();
11010     },
11011
11012     /**
11013      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11014      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11015      * @param {String} value The data value of the item to select
11016      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11017      * selected item if it is not currently in view (defaults to true)
11018      * @return {Boolean} True if the value matched an item in the list, else false
11019      */
11020     selectByValue : function(v, scrollIntoView){
11021         if(v !== undefined && v !== null){
11022             var r = this.findRecord(this.valueField || this.displayField, v);
11023             if(r){
11024                 this.select(this.store.indexOf(r), scrollIntoView);
11025                 return true;
11026             }
11027         }
11028         return false;
11029     },
11030
11031     /**
11032      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11033      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11034      * @param {Number} index The zero-based index of the list item to select
11035      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11036      * selected item if it is not currently in view (defaults to true)
11037      */
11038     select : function(index, scrollIntoView){
11039         this.selectedIndex = index;
11040         this.view.select(index);
11041         if(scrollIntoView !== false){
11042             var el = this.view.getNode(index);
11043             if(el){
11044                 //this.innerList.scrollChildIntoView(el, false);
11045                 
11046             }
11047         }
11048     },
11049
11050     // private
11051     selectNext : function(){
11052         var ct = this.store.getCount();
11053         if(ct > 0){
11054             if(this.selectedIndex == -1){
11055                 this.select(0);
11056             }else if(this.selectedIndex < ct-1){
11057                 this.select(this.selectedIndex+1);
11058             }
11059         }
11060     },
11061
11062     // private
11063     selectPrev : function(){
11064         var ct = this.store.getCount();
11065         if(ct > 0){
11066             if(this.selectedIndex == -1){
11067                 this.select(0);
11068             }else if(this.selectedIndex != 0){
11069                 this.select(this.selectedIndex-1);
11070             }
11071         }
11072     },
11073
11074     // private
11075     onKeyUp : function(e){
11076         if(this.editable !== false && !e.isSpecialKey()){
11077             this.lastKey = e.getKey();
11078             this.dqTask.delay(this.queryDelay);
11079         }
11080     },
11081
11082     // private
11083     validateBlur : function(){
11084         return !this.list || !this.list.isVisible();   
11085     },
11086
11087     // private
11088     initQuery : function(){
11089         this.doQuery(this.getRawValue());
11090     },
11091
11092     // private
11093     doForce : function(){
11094         if(this.inputEl().dom.value.length > 0){
11095             this.inputEl().dom.value =
11096                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11097              
11098         }
11099     },
11100
11101     /**
11102      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11103      * query allowing the query action to be canceled if needed.
11104      * @param {String} query The SQL query to execute
11105      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11106      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11107      * saved in the current store (defaults to false)
11108      */
11109     doQuery : function(q, forceAll){
11110         
11111         if(q === undefined || q === null){
11112             q = '';
11113         }
11114         var qe = {
11115             query: q,
11116             forceAll: forceAll,
11117             combo: this,
11118             cancel:false
11119         };
11120         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11121             return false;
11122         }
11123         q = qe.query;
11124         
11125         forceAll = qe.forceAll;
11126         if(forceAll === true || (q.length >= this.minChars)){
11127             
11128             this.hasQuery = true;
11129             
11130             if(this.lastQuery != q || this.alwaysQuery){
11131                 this.lastQuery = q;
11132                 if(this.mode == 'local'){
11133                     this.selectedIndex = -1;
11134                     if(forceAll){
11135                         this.store.clearFilter();
11136                     }else{
11137                         this.store.filter(this.displayField, q);
11138                     }
11139                     this.onLoad();
11140                 }else{
11141                     this.store.baseParams[this.queryParam] = q;
11142                     
11143                     var options = {params : this.getParams(q)};
11144                     
11145                     if(this.loadNext){
11146                         options.add = true;
11147                         options.params.start = this.page * this.pageSize;
11148                     }
11149                     
11150                     this.store.load(options);
11151                     /*
11152                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11153                      *  we should expand the list on onLoad
11154                      *  so command out it
11155                      */
11156 //                    this.expand();
11157                 }
11158             }else{
11159                 this.selectedIndex = -1;
11160                 this.onLoad();   
11161             }
11162         }
11163         
11164         this.loadNext = false;
11165     },
11166
11167     // private
11168     getParams : function(q){
11169         var p = {};
11170         //p[this.queryParam] = q;
11171         
11172         if(this.pageSize){
11173             p.start = 0;
11174             p.limit = this.pageSize;
11175         }
11176         return p;
11177     },
11178
11179     /**
11180      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11181      */
11182     collapse : function(){
11183         if(!this.isExpanded()){
11184             return;
11185         }
11186         
11187         this.list.hide();
11188         
11189         if(this.tickable){
11190             this.okBtn.hide();
11191             this.cancelBtn.hide();
11192             this.trigger.show();
11193         }
11194         
11195         Roo.get(document).un('mousedown', this.collapseIf, this);
11196         Roo.get(document).un('mousewheel', this.collapseIf, this);
11197         if (!this.editable) {
11198             Roo.get(document).un('keydown', this.listKeyPress, this);
11199         }
11200         this.fireEvent('collapse', this);
11201     },
11202
11203     // private
11204     collapseIf : function(e){
11205         var in_combo  = e.within(this.el);
11206         var in_list =  e.within(this.list);
11207         
11208         if (in_combo || in_list) {
11209             //e.stopPropagation();
11210             return;
11211         }
11212         
11213         if(this.tickable){
11214             this.onTickableFooterButtonClick(e, false, false);
11215         }
11216
11217         this.collapse();
11218         
11219     },
11220
11221     /**
11222      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11223      */
11224     expand : function(){
11225        
11226         if(this.isExpanded() || !this.hasFocus){
11227             return;
11228         }
11229          Roo.log('expand');
11230         this.list.alignTo(this.inputEl(), this.listAlign);
11231         this.list.show();
11232         
11233         if(this.tickable){
11234             
11235             this.tickItems = Roo.apply([], this.item);
11236             
11237             this.okBtn.show();
11238             this.cancelBtn.show();
11239             this.trigger.hide();
11240             
11241         }
11242         
11243         Roo.get(document).on('mousedown', this.collapseIf, this);
11244         Roo.get(document).on('mousewheel', this.collapseIf, this);
11245         if (!this.editable) {
11246             Roo.get(document).on('keydown', this.listKeyPress, this);
11247         }
11248         
11249         this.fireEvent('expand', this);
11250     },
11251
11252     // private
11253     // Implements the default empty TriggerField.onTriggerClick function
11254     onTriggerClick : function()
11255     {
11256         Roo.log('trigger click');
11257         
11258         if(this.disabled){
11259             return;
11260         }
11261         
11262         if(this.tickable){
11263             this.onTickableTriggerClick();
11264             return;
11265         }
11266         
11267         this.page = 0;
11268         this.loadNext = false;
11269         
11270         if(this.isExpanded()){
11271             this.collapse();
11272             if (!this.blockFocus) {
11273                 this.inputEl().focus();
11274             }
11275             
11276         }else {
11277             this.hasFocus = true;
11278             if(this.triggerAction == 'all') {
11279                 this.doQuery(this.allQuery, true);
11280             } else {
11281                 this.doQuery(this.getRawValue());
11282             }
11283             if (!this.blockFocus) {
11284                 this.inputEl().focus();
11285             }
11286         }
11287     },
11288     
11289     onTickableTriggerClick : function()
11290     {
11291         this.page = 0;
11292         this.loadNext = false;
11293         this.hasFocus = true;
11294         
11295         if(this.triggerAction == 'all') {
11296             this.doQuery(this.allQuery, true);
11297         } else {
11298             this.doQuery(this.getRawValue());
11299         }
11300     },
11301     
11302     listKeyPress : function(e)
11303     {
11304         //Roo.log('listkeypress');
11305         // scroll to first matching element based on key pres..
11306         if (e.isSpecialKey()) {
11307             return false;
11308         }
11309         var k = String.fromCharCode(e.getKey()).toUpperCase();
11310         //Roo.log(k);
11311         var match  = false;
11312         var csel = this.view.getSelectedNodes();
11313         var cselitem = false;
11314         if (csel.length) {
11315             var ix = this.view.indexOf(csel[0]);
11316             cselitem  = this.store.getAt(ix);
11317             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11318                 cselitem = false;
11319             }
11320             
11321         }
11322         
11323         this.store.each(function(v) { 
11324             if (cselitem) {
11325                 // start at existing selection.
11326                 if (cselitem.id == v.id) {
11327                     cselitem = false;
11328                 }
11329                 return true;
11330             }
11331                 
11332             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11333                 match = this.store.indexOf(v);
11334                 return false;
11335             }
11336             return true;
11337         }, this);
11338         
11339         if (match === false) {
11340             return true; // no more action?
11341         }
11342         // scroll to?
11343         this.view.select(match);
11344         var sn = Roo.get(this.view.getSelectedNodes()[0])
11345         //sn.scrollIntoView(sn.dom.parentNode, false);
11346     },
11347     
11348     onViewScroll : function(e, t){
11349         
11350         if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11351             return;
11352         }
11353         
11354         this.hasQuery = true;
11355         
11356         this.loading = this.list.select('.loading', true).first();
11357         
11358         if(this.loading === null){
11359             this.list.createChild({
11360                 tag: 'div',
11361                 cls: 'loading select2-more-results select2-active',
11362                 html: 'Loading more results...'
11363             })
11364             
11365             this.loading = this.list.select('.loading', true).first();
11366             
11367             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11368             
11369             this.loading.hide();
11370         }
11371         
11372         this.loading.show();
11373         
11374         var _combo = this;
11375         
11376         this.page++;
11377         this.loadNext = true;
11378         
11379         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11380         
11381         return;
11382     },
11383     
11384     addItem : function(o)
11385     {   
11386         var dv = ''; // display value
11387         
11388         if (this.displayField) {
11389             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11390         } else {
11391             // this is an error condition!!!
11392             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11393         }
11394         
11395         if(!dv.length){
11396             return;
11397         }
11398         
11399         var choice = this.choices.createChild({
11400             tag: 'li',
11401             cls: 'select2-search-choice',
11402             cn: [
11403                 {
11404                     tag: 'div',
11405                     html: dv
11406                 },
11407                 {
11408                     tag: 'a',
11409                     href: '#',
11410                     cls: 'select2-search-choice-close',
11411                     tabindex: '-1'
11412                 }
11413             ]
11414             
11415         }, this.searchField);
11416         
11417         var close = choice.select('a.select2-search-choice-close', true).first()
11418         
11419         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11420         
11421         this.item.push(o);
11422         
11423         this.lastData = o;
11424         
11425         this.syncValue();
11426         
11427         this.inputEl().dom.value = '';
11428         
11429     },
11430     
11431     onRemoveItem : function(e, _self, o)
11432     {
11433         e.preventDefault();
11434         var index = this.item.indexOf(o.data) * 1;
11435         
11436         if( index < 0){
11437             Roo.log('not this item?!');
11438             return;
11439         }
11440         
11441         this.item.splice(index, 1);
11442         o.item.remove();
11443         
11444         this.syncValue();
11445         
11446         this.fireEvent('remove', this, e);
11447         
11448     },
11449     
11450     syncValue : function()
11451     {
11452         if(!this.item.length){
11453             this.clearValue();
11454             return;
11455         }
11456             
11457         var value = [];
11458         var _this = this;
11459         Roo.each(this.item, function(i){
11460             if(_this.valueField){
11461                 value.push(i[_this.valueField]);
11462                 return;
11463             }
11464
11465             value.push(i);
11466         });
11467
11468         this.value = value.join(',');
11469
11470         if(this.hiddenField){
11471             this.hiddenField.dom.value = this.value;
11472         }
11473     },
11474     
11475     clearItem : function()
11476     {
11477         if(!this.multiple){
11478             return;
11479         }
11480         
11481         this.item = [];
11482         
11483         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11484            c.remove();
11485         });
11486         
11487         this.syncValue();
11488     },
11489     
11490     inputEl: function ()
11491     {
11492         if(this.tickable){
11493             return this.searchField;
11494         }
11495         return this.el.select('input.form-control',true).first();
11496     },
11497     
11498     
11499     onTickableFooterButtonClick : function(e, btn, el)
11500     {
11501         e.preventDefault();
11502         
11503         if(btn && btn.name == 'cancel'){
11504             this.tickItems = Roo.apply([], this.item);
11505             this.collapse();
11506             return;
11507         }
11508         
11509         this.clearItem();
11510         
11511         var _this = this;
11512         
11513         Roo.each(this.tickItems, function(o){
11514             _this.addItem(o);
11515         });
11516         
11517         this.collapse();
11518         
11519     }
11520     
11521     
11522
11523     /** 
11524     * @cfg {Boolean} grow 
11525     * @hide 
11526     */
11527     /** 
11528     * @cfg {Number} growMin 
11529     * @hide 
11530     */
11531     /** 
11532     * @cfg {Number} growMax 
11533     * @hide 
11534     */
11535     /**
11536      * @hide
11537      * @method autoSize
11538      */
11539 });
11540 /*
11541  * Based on:
11542  * Ext JS Library 1.1.1
11543  * Copyright(c) 2006-2007, Ext JS, LLC.
11544  *
11545  * Originally Released Under LGPL - original licence link has changed is not relivant.
11546  *
11547  * Fork - LGPL
11548  * <script type="text/javascript">
11549  */
11550
11551 /**
11552  * @class Roo.View
11553  * @extends Roo.util.Observable
11554  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
11555  * This class also supports single and multi selection modes. <br>
11556  * Create a data model bound view:
11557  <pre><code>
11558  var store = new Roo.data.Store(...);
11559
11560  var view = new Roo.View({
11561     el : "my-element",
11562     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
11563  
11564     singleSelect: true,
11565     selectedClass: "ydataview-selected",
11566     store: store
11567  });
11568
11569  // listen for node click?
11570  view.on("click", function(vw, index, node, e){
11571  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11572  });
11573
11574  // load XML data
11575  dataModel.load("foobar.xml");
11576  </code></pre>
11577  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11578  * <br><br>
11579  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11580  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11581  * 
11582  * Note: old style constructor is still suported (container, template, config)
11583  * 
11584  * @constructor
11585  * Create a new View
11586  * @param {Object} config The config object
11587  * 
11588  */
11589 Roo.View = function(config, depreciated_tpl, depreciated_config){
11590     
11591     this.parent = false;
11592     
11593     if (typeof(depreciated_tpl) == 'undefined') {
11594         // new way.. - universal constructor.
11595         Roo.apply(this, config);
11596         this.el  = Roo.get(this.el);
11597     } else {
11598         // old format..
11599         this.el  = Roo.get(config);
11600         this.tpl = depreciated_tpl;
11601         Roo.apply(this, depreciated_config);
11602     }
11603     this.wrapEl  = this.el.wrap().wrap();
11604     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11605     
11606     
11607     if(typeof(this.tpl) == "string"){
11608         this.tpl = new Roo.Template(this.tpl);
11609     } else {
11610         // support xtype ctors..
11611         this.tpl = new Roo.factory(this.tpl, Roo);
11612     }
11613     
11614     
11615     this.tpl.compile();
11616     
11617     /** @private */
11618     this.addEvents({
11619         /**
11620          * @event beforeclick
11621          * Fires before a click is processed. Returns false to cancel the default action.
11622          * @param {Roo.View} this
11623          * @param {Number} index The index of the target node
11624          * @param {HTMLElement} node The target node
11625          * @param {Roo.EventObject} e The raw event object
11626          */
11627             "beforeclick" : true,
11628         /**
11629          * @event click
11630          * Fires when a template node is clicked.
11631          * @param {Roo.View} this
11632          * @param {Number} index The index of the target node
11633          * @param {HTMLElement} node The target node
11634          * @param {Roo.EventObject} e The raw event object
11635          */
11636             "click" : true,
11637         /**
11638          * @event dblclick
11639          * Fires when a template node is double clicked.
11640          * @param {Roo.View} this
11641          * @param {Number} index The index of the target node
11642          * @param {HTMLElement} node The target node
11643          * @param {Roo.EventObject} e The raw event object
11644          */
11645             "dblclick" : true,
11646         /**
11647          * @event contextmenu
11648          * Fires when a template node is right clicked.
11649          * @param {Roo.View} this
11650          * @param {Number} index The index of the target node
11651          * @param {HTMLElement} node The target node
11652          * @param {Roo.EventObject} e The raw event object
11653          */
11654             "contextmenu" : true,
11655         /**
11656          * @event selectionchange
11657          * Fires when the selected nodes change.
11658          * @param {Roo.View} this
11659          * @param {Array} selections Array of the selected nodes
11660          */
11661             "selectionchange" : true,
11662     
11663         /**
11664          * @event beforeselect
11665          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11666          * @param {Roo.View} this
11667          * @param {HTMLElement} node The node to be selected
11668          * @param {Array} selections Array of currently selected nodes
11669          */
11670             "beforeselect" : true,
11671         /**
11672          * @event preparedata
11673          * Fires on every row to render, to allow you to change the data.
11674          * @param {Roo.View} this
11675          * @param {Object} data to be rendered (change this)
11676          */
11677           "preparedata" : true
11678           
11679           
11680         });
11681
11682
11683
11684     this.el.on({
11685         "click": this.onClick,
11686         "dblclick": this.onDblClick,
11687         "contextmenu": this.onContextMenu,
11688         scope:this
11689     });
11690
11691     this.selections = [];
11692     this.nodes = [];
11693     this.cmp = new Roo.CompositeElementLite([]);
11694     if(this.store){
11695         this.store = Roo.factory(this.store, Roo.data);
11696         this.setStore(this.store, true);
11697     }
11698     
11699     if ( this.footer && this.footer.xtype) {
11700            
11701          var fctr = this.wrapEl.appendChild(document.createElement("div"));
11702         
11703         this.footer.dataSource = this.store
11704         this.footer.container = fctr;
11705         this.footer = Roo.factory(this.footer, Roo);
11706         fctr.insertFirst(this.el);
11707         
11708         // this is a bit insane - as the paging toolbar seems to detach the el..
11709 //        dom.parentNode.parentNode.parentNode
11710          // they get detached?
11711     }
11712     
11713     
11714     Roo.View.superclass.constructor.call(this);
11715     
11716     
11717 };
11718
11719 Roo.extend(Roo.View, Roo.util.Observable, {
11720     
11721      /**
11722      * @cfg {Roo.data.Store} store Data store to load data from.
11723      */
11724     store : false,
11725     
11726     /**
11727      * @cfg {String|Roo.Element} el The container element.
11728      */
11729     el : '',
11730     
11731     /**
11732      * @cfg {String|Roo.Template} tpl The template used by this View 
11733      */
11734     tpl : false,
11735     /**
11736      * @cfg {String} dataName the named area of the template to use as the data area
11737      *                          Works with domtemplates roo-name="name"
11738      */
11739     dataName: false,
11740     /**
11741      * @cfg {String} selectedClass The css class to add to selected nodes
11742      */
11743     selectedClass : "x-view-selected",
11744      /**
11745      * @cfg {String} emptyText The empty text to show when nothing is loaded.
11746      */
11747     emptyText : "",
11748     
11749     /**
11750      * @cfg {String} text to display on mask (default Loading)
11751      */
11752     mask : false,
11753     /**
11754      * @cfg {Boolean} multiSelect Allow multiple selection
11755      */
11756     multiSelect : false,
11757     /**
11758      * @cfg {Boolean} singleSelect Allow single selection
11759      */
11760     singleSelect:  false,
11761     
11762     /**
11763      * @cfg {Boolean} toggleSelect - selecting 
11764      */
11765     toggleSelect : false,
11766     
11767     /**
11768      * @cfg {Boolean} tickable - selecting 
11769      */
11770     tickable : false,
11771     
11772     /**
11773      * Returns the element this view is bound to.
11774      * @return {Roo.Element}
11775      */
11776     getEl : function(){
11777         return this.wrapEl;
11778     },
11779     
11780     
11781
11782     /**
11783      * Refreshes the view. - called by datachanged on the store. - do not call directly.
11784      */
11785     refresh : function(){
11786         Roo.log('refresh');
11787         var t = this.tpl;
11788         
11789         // if we are using something like 'domtemplate', then
11790         // the what gets used is:
11791         // t.applySubtemplate(NAME, data, wrapping data..)
11792         // the outer template then get' applied with
11793         //     the store 'extra data'
11794         // and the body get's added to the
11795         //      roo-name="data" node?
11796         //      <span class='roo-tpl-{name}'></span> ?????
11797         
11798         
11799         
11800         this.clearSelections();
11801         this.el.update("");
11802         var html = [];
11803         var records = this.store.getRange();
11804         if(records.length < 1) {
11805             
11806             // is this valid??  = should it render a template??
11807             
11808             this.el.update(this.emptyText);
11809             return;
11810         }
11811         var el = this.el;
11812         if (this.dataName) {
11813             this.el.update(t.apply(this.store.meta)); //????
11814             el = this.el.child('.roo-tpl-' + this.dataName);
11815         }
11816         
11817         for(var i = 0, len = records.length; i < len; i++){
11818             var data = this.prepareData(records[i].data, i, records[i]);
11819             this.fireEvent("preparedata", this, data, i, records[i]);
11820             
11821             var d = Roo.apply({}, data);
11822             
11823             if(this.tickable){
11824                 Roo.apply(d, {'roo-id' : Roo.id()});
11825                 
11826                 var _this = this;
11827             
11828                 Roo.each(this.parent.item, function(item){
11829                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11830                         return;
11831                     }
11832                     Roo.apply(d, {'roo-data-checked' : 'checked'});
11833                 });
11834             }
11835             
11836             html[html.length] = Roo.util.Format.trim(
11837                 this.dataName ?
11838                     t.applySubtemplate(this.dataName, d, this.store.meta) :
11839                     t.apply(d)
11840             );
11841         }
11842         
11843         
11844         
11845         el.update(html.join(""));
11846         this.nodes = el.dom.childNodes;
11847         this.updateIndexes(0);
11848     },
11849     
11850
11851     /**
11852      * Function to override to reformat the data that is sent to
11853      * the template for each node.
11854      * DEPRICATED - use the preparedata event handler.
11855      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11856      * a JSON object for an UpdateManager bound view).
11857      */
11858     prepareData : function(data, index, record)
11859     {
11860         this.fireEvent("preparedata", this, data, index, record);
11861         return data;
11862     },
11863
11864     onUpdate : function(ds, record){
11865          Roo.log('on update');   
11866         this.clearSelections();
11867         var index = this.store.indexOf(record);
11868         var n = this.nodes[index];
11869         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11870         n.parentNode.removeChild(n);
11871         this.updateIndexes(index, index);
11872     },
11873
11874     
11875     
11876 // --------- FIXME     
11877     onAdd : function(ds, records, index)
11878     {
11879         Roo.log(['on Add', ds, records, index] );        
11880         this.clearSelections();
11881         if(this.nodes.length == 0){
11882             this.refresh();
11883             return;
11884         }
11885         var n = this.nodes[index];
11886         for(var i = 0, len = records.length; i < len; i++){
11887             var d = this.prepareData(records[i].data, i, records[i]);
11888             if(n){
11889                 this.tpl.insertBefore(n, d);
11890             }else{
11891                 
11892                 this.tpl.append(this.el, d);
11893             }
11894         }
11895         this.updateIndexes(index);
11896     },
11897
11898     onRemove : function(ds, record, index){
11899         Roo.log('onRemove');
11900         this.clearSelections();
11901         var el = this.dataName  ?
11902             this.el.child('.roo-tpl-' + this.dataName) :
11903             this.el; 
11904         
11905         el.dom.removeChild(this.nodes[index]);
11906         this.updateIndexes(index);
11907     },
11908
11909     /**
11910      * Refresh an individual node.
11911      * @param {Number} index
11912      */
11913     refreshNode : function(index){
11914         this.onUpdate(this.store, this.store.getAt(index));
11915     },
11916
11917     updateIndexes : function(startIndex, endIndex){
11918         var ns = this.nodes;
11919         startIndex = startIndex || 0;
11920         endIndex = endIndex || ns.length - 1;
11921         for(var i = startIndex; i <= endIndex; i++){
11922             ns[i].nodeIndex = i;
11923         }
11924     },
11925
11926     /**
11927      * Changes the data store this view uses and refresh the view.
11928      * @param {Store} store
11929      */
11930     setStore : function(store, initial){
11931         if(!initial && this.store){
11932             this.store.un("datachanged", this.refresh);
11933             this.store.un("add", this.onAdd);
11934             this.store.un("remove", this.onRemove);
11935             this.store.un("update", this.onUpdate);
11936             this.store.un("clear", this.refresh);
11937             this.store.un("beforeload", this.onBeforeLoad);
11938             this.store.un("load", this.onLoad);
11939             this.store.un("loadexception", this.onLoad);
11940         }
11941         if(store){
11942           
11943             store.on("datachanged", this.refresh, this);
11944             store.on("add", this.onAdd, this);
11945             store.on("remove", this.onRemove, this);
11946             store.on("update", this.onUpdate, this);
11947             store.on("clear", this.refresh, this);
11948             store.on("beforeload", this.onBeforeLoad, this);
11949             store.on("load", this.onLoad, this);
11950             store.on("loadexception", this.onLoad, this);
11951         }
11952         
11953         if(store){
11954             this.refresh();
11955         }
11956     },
11957     /**
11958      * onbeforeLoad - masks the loading area.
11959      *
11960      */
11961     onBeforeLoad : function(store,opts)
11962     {
11963          Roo.log('onBeforeLoad');   
11964         if (!opts.add) {
11965             this.el.update("");
11966         }
11967         this.el.mask(this.mask ? this.mask : "Loading" ); 
11968     },
11969     onLoad : function ()
11970     {
11971         this.el.unmask();
11972     },
11973     
11974
11975     /**
11976      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11977      * @param {HTMLElement} node
11978      * @return {HTMLElement} The template node
11979      */
11980     findItemFromChild : function(node){
11981         var el = this.dataName  ?
11982             this.el.child('.roo-tpl-' + this.dataName,true) :
11983             this.el.dom; 
11984         
11985         if(!node || node.parentNode == el){
11986                     return node;
11987             }
11988             var p = node.parentNode;
11989             while(p && p != el){
11990             if(p.parentNode == el){
11991                 return p;
11992             }
11993             p = p.parentNode;
11994         }
11995             return null;
11996     },
11997
11998     /** @ignore */
11999     onClick : function(e){
12000         var item = this.findItemFromChild(e.getTarget());
12001         if(item){
12002             var index = this.indexOf(item);
12003             if(this.onItemClick(item, index, e) !== false){
12004                 this.fireEvent("click", this, index, item, e);
12005             }
12006         }else{
12007             this.clearSelections();
12008         }
12009     },
12010
12011     /** @ignore */
12012     onContextMenu : function(e){
12013         var item = this.findItemFromChild(e.getTarget());
12014         if(item){
12015             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12016         }
12017     },
12018
12019     /** @ignore */
12020     onDblClick : function(e){
12021         var item = this.findItemFromChild(e.getTarget());
12022         if(item){
12023             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12024         }
12025     },
12026
12027     onItemClick : function(item, index, e)
12028     {
12029         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12030             return false;
12031         }
12032         if (this.toggleSelect) {
12033             var m = this.isSelected(item) ? 'unselect' : 'select';
12034             Roo.log(m);
12035             var _t = this;
12036             _t[m](item, true, false);
12037             return true;
12038         }
12039         if(this.multiSelect || this.singleSelect){
12040             if(this.multiSelect && e.shiftKey && this.lastSelection){
12041                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12042             }else{
12043                 this.select(item, this.multiSelect && e.ctrlKey);
12044                 this.lastSelection = item;
12045             }
12046             
12047             if(!this.tickable){
12048                 e.preventDefault();
12049             }
12050             
12051         }
12052         return true;
12053     },
12054
12055     /**
12056      * Get the number of selected nodes.
12057      * @return {Number}
12058      */
12059     getSelectionCount : function(){
12060         return this.selections.length;
12061     },
12062
12063     /**
12064      * Get the currently selected nodes.
12065      * @return {Array} An array of HTMLElements
12066      */
12067     getSelectedNodes : function(){
12068         return this.selections;
12069     },
12070
12071     /**
12072      * Get the indexes of the selected nodes.
12073      * @return {Array}
12074      */
12075     getSelectedIndexes : function(){
12076         var indexes = [], s = this.selections;
12077         for(var i = 0, len = s.length; i < len; i++){
12078             indexes.push(s[i].nodeIndex);
12079         }
12080         return indexes;
12081     },
12082
12083     /**
12084      * Clear all selections
12085      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12086      */
12087     clearSelections : function(suppressEvent){
12088         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12089             this.cmp.elements = this.selections;
12090             this.cmp.removeClass(this.selectedClass);
12091             this.selections = [];
12092             if(!suppressEvent){
12093                 this.fireEvent("selectionchange", this, this.selections);
12094             }
12095         }
12096     },
12097
12098     /**
12099      * Returns true if the passed node is selected
12100      * @param {HTMLElement/Number} node The node or node index
12101      * @return {Boolean}
12102      */
12103     isSelected : function(node){
12104         var s = this.selections;
12105         if(s.length < 1){
12106             return false;
12107         }
12108         node = this.getNode(node);
12109         return s.indexOf(node) !== -1;
12110     },
12111
12112     /**
12113      * Selects nodes.
12114      * @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
12115      * @param {Boolean} keepExisting (optional) true to keep existing selections
12116      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12117      */
12118     select : function(nodeInfo, keepExisting, suppressEvent){
12119         if(nodeInfo instanceof Array){
12120             if(!keepExisting){
12121                 this.clearSelections(true);
12122             }
12123             for(var i = 0, len = nodeInfo.length; i < len; i++){
12124                 this.select(nodeInfo[i], true, true);
12125             }
12126             return;
12127         } 
12128         var node = this.getNode(nodeInfo);
12129         if(!node || this.isSelected(node)){
12130             return; // already selected.
12131         }
12132         if(!keepExisting){
12133             this.clearSelections(true);
12134         }
12135         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12136             Roo.fly(node).addClass(this.selectedClass);
12137             this.selections.push(node);
12138             if(!suppressEvent){
12139                 this.fireEvent("selectionchange", this, this.selections);
12140             }
12141         }
12142         
12143         
12144     },
12145       /**
12146      * Unselects nodes.
12147      * @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
12148      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12149      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12150      */
12151     unselect : function(nodeInfo, keepExisting, suppressEvent)
12152     {
12153         if(nodeInfo instanceof Array){
12154             Roo.each(this.selections, function(s) {
12155                 this.unselect(s, nodeInfo);
12156             }, this);
12157             return;
12158         }
12159         var node = this.getNode(nodeInfo);
12160         if(!node || !this.isSelected(node)){
12161             Roo.log("not selected");
12162             return; // not selected.
12163         }
12164         // fireevent???
12165         var ns = [];
12166         Roo.each(this.selections, function(s) {
12167             if (s == node ) {
12168                 Roo.fly(node).removeClass(this.selectedClass);
12169
12170                 return;
12171             }
12172             ns.push(s);
12173         },this);
12174         
12175         this.selections= ns;
12176         this.fireEvent("selectionchange", this, this.selections);
12177     },
12178
12179     /**
12180      * Gets a template node.
12181      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12182      * @return {HTMLElement} The node or null if it wasn't found
12183      */
12184     getNode : function(nodeInfo){
12185         if(typeof nodeInfo == "string"){
12186             return document.getElementById(nodeInfo);
12187         }else if(typeof nodeInfo == "number"){
12188             return this.nodes[nodeInfo];
12189         }
12190         return nodeInfo;
12191     },
12192
12193     /**
12194      * Gets a range template nodes.
12195      * @param {Number} startIndex
12196      * @param {Number} endIndex
12197      * @return {Array} An array of nodes
12198      */
12199     getNodes : function(start, end){
12200         var ns = this.nodes;
12201         start = start || 0;
12202         end = typeof end == "undefined" ? ns.length - 1 : end;
12203         var nodes = [];
12204         if(start <= end){
12205             for(var i = start; i <= end; i++){
12206                 nodes.push(ns[i]);
12207             }
12208         } else{
12209             for(var i = start; i >= end; i--){
12210                 nodes.push(ns[i]);
12211             }
12212         }
12213         return nodes;
12214     },
12215
12216     /**
12217      * Finds the index of the passed node
12218      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12219      * @return {Number} The index of the node or -1
12220      */
12221     indexOf : function(node){
12222         node = this.getNode(node);
12223         if(typeof node.nodeIndex == "number"){
12224             return node.nodeIndex;
12225         }
12226         var ns = this.nodes;
12227         for(var i = 0, len = ns.length; i < len; i++){
12228             if(ns[i] == node){
12229                 return i;
12230             }
12231         }
12232         return -1;
12233     }
12234 });
12235 /*
12236  * - LGPL
12237  *
12238  * based on jquery fullcalendar
12239  * 
12240  */
12241
12242 Roo.bootstrap = Roo.bootstrap || {};
12243 /**
12244  * @class Roo.bootstrap.Calendar
12245  * @extends Roo.bootstrap.Component
12246  * Bootstrap Calendar class
12247  * @cfg {Boolean} loadMask (true|false) default false
12248  * @cfg {Object} header generate the user specific header of the calendar, default false
12249
12250  * @constructor
12251  * Create a new Container
12252  * @param {Object} config The config object
12253  */
12254
12255
12256
12257 Roo.bootstrap.Calendar = function(config){
12258     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12259      this.addEvents({
12260         /**
12261              * @event select
12262              * Fires when a date is selected
12263              * @param {DatePicker} this
12264              * @param {Date} date The selected date
12265              */
12266         'select': true,
12267         /**
12268              * @event monthchange
12269              * Fires when the displayed month changes 
12270              * @param {DatePicker} this
12271              * @param {Date} date The selected month
12272              */
12273         'monthchange': true,
12274         /**
12275              * @event evententer
12276              * Fires when mouse over an event
12277              * @param {Calendar} this
12278              * @param {event} Event
12279              */
12280         'evententer': true,
12281         /**
12282              * @event eventleave
12283              * Fires when the mouse leaves an
12284              * @param {Calendar} this
12285              * @param {event}
12286              */
12287         'eventleave': true,
12288         /**
12289              * @event eventclick
12290              * Fires when the mouse click an
12291              * @param {Calendar} this
12292              * @param {event}
12293              */
12294         'eventclick': true
12295         
12296     });
12297
12298 };
12299
12300 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
12301     
12302      /**
12303      * @cfg {Number} startDay
12304      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12305      */
12306     startDay : 0,
12307     
12308     loadMask : false,
12309     
12310     header : false,
12311       
12312     getAutoCreate : function(){
12313         
12314         
12315         var fc_button = function(name, corner, style, content ) {
12316             return Roo.apply({},{
12317                 tag : 'span',
12318                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
12319                          (corner.length ?
12320                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12321                             ''
12322                         ),
12323                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12324                 unselectable: 'on'
12325             });
12326         };
12327         
12328         var header = {};
12329         
12330         if(!this.header){
12331             header = {
12332                 tag : 'table',
12333                 cls : 'fc-header',
12334                 style : 'width:100%',
12335                 cn : [
12336                     {
12337                         tag: 'tr',
12338                         cn : [
12339                             {
12340                                 tag : 'td',
12341                                 cls : 'fc-header-left',
12342                                 cn : [
12343                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
12344                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
12345                                     { tag: 'span', cls: 'fc-header-space' },
12346                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
12347
12348
12349                                 ]
12350                             },
12351
12352                             {
12353                                 tag : 'td',
12354                                 cls : 'fc-header-center',
12355                                 cn : [
12356                                     {
12357                                         tag: 'span',
12358                                         cls: 'fc-header-title',
12359                                         cn : {
12360                                             tag: 'H2',
12361                                             html : 'month / year'
12362                                         }
12363                                     }
12364
12365                                 ]
12366                             },
12367                             {
12368                                 tag : 'td',
12369                                 cls : 'fc-header-right',
12370                                 cn : [
12371                               /*      fc_button('month', 'left', '', 'month' ),
12372                                     fc_button('week', '', '', 'week' ),
12373                                     fc_button('day', 'right', '', 'day' )
12374                                 */    
12375
12376                                 ]
12377                             }
12378
12379                         ]
12380                     }
12381                 ]
12382             };
12383         }
12384         
12385         header = this.header;
12386         
12387        
12388         var cal_heads = function() {
12389             var ret = [];
12390             // fixme - handle this.
12391             
12392             for (var i =0; i < Date.dayNames.length; i++) {
12393                 var d = Date.dayNames[i];
12394                 ret.push({
12395                     tag: 'th',
12396                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12397                     html : d.substring(0,3)
12398                 });
12399                 
12400             }
12401             ret[0].cls += ' fc-first';
12402             ret[6].cls += ' fc-last';
12403             return ret;
12404         };
12405         var cal_cell = function(n) {
12406             return  {
12407                 tag: 'td',
12408                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12409                 cn : [
12410                     {
12411                         cn : [
12412                             {
12413                                 cls: 'fc-day-number',
12414                                 html: 'D'
12415                             },
12416                             {
12417                                 cls: 'fc-day-content',
12418                              
12419                                 cn : [
12420                                      {
12421                                         style: 'position: relative;' // height: 17px;
12422                                     }
12423                                 ]
12424                             }
12425                             
12426                             
12427                         ]
12428                     }
12429                 ]
12430                 
12431             }
12432         };
12433         var cal_rows = function() {
12434             
12435             var ret = []
12436             for (var r = 0; r < 6; r++) {
12437                 var row= {
12438                     tag : 'tr',
12439                     cls : 'fc-week',
12440                     cn : []
12441                 };
12442                 
12443                 for (var i =0; i < Date.dayNames.length; i++) {
12444                     var d = Date.dayNames[i];
12445                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12446
12447                 }
12448                 row.cn[0].cls+=' fc-first';
12449                 row.cn[0].cn[0].style = 'min-height:90px';
12450                 row.cn[6].cls+=' fc-last';
12451                 ret.push(row);
12452                 
12453             }
12454             ret[0].cls += ' fc-first';
12455             ret[4].cls += ' fc-prev-last';
12456             ret[5].cls += ' fc-last';
12457             return ret;
12458             
12459         };
12460         
12461         var cal_table = {
12462             tag: 'table',
12463             cls: 'fc-border-separate',
12464             style : 'width:100%',
12465             cellspacing  : 0,
12466             cn : [
12467                 { 
12468                     tag: 'thead',
12469                     cn : [
12470                         { 
12471                             tag: 'tr',
12472                             cls : 'fc-first fc-last',
12473                             cn : cal_heads()
12474                         }
12475                     ]
12476                 },
12477                 { 
12478                     tag: 'tbody',
12479                     cn : cal_rows()
12480                 }
12481                   
12482             ]
12483         };
12484          
12485          var cfg = {
12486             cls : 'fc fc-ltr',
12487             cn : [
12488                 header,
12489                 {
12490                     cls : 'fc-content',
12491                     style : "position: relative;",
12492                     cn : [
12493                         {
12494                             cls : 'fc-view fc-view-month fc-grid',
12495                             style : 'position: relative',
12496                             unselectable : 'on',
12497                             cn : [
12498                                 {
12499                                     cls : 'fc-event-container',
12500                                     style : 'position:absolute;z-index:8;top:0;left:0;'
12501                                 },
12502                                 cal_table
12503                             ]
12504                         }
12505                     ]
12506     
12507                 }
12508            ] 
12509             
12510         };
12511         
12512          
12513         
12514         return cfg;
12515     },
12516     
12517     
12518     initEvents : function()
12519     {
12520         if(!this.store){
12521             throw "can not find store for calendar";
12522         }
12523         
12524         var mark = {
12525             tag: "div",
12526             cls:"x-dlg-mask",
12527             style: "text-align:center",
12528             cn: [
12529                 {
12530                     tag: "div",
12531                     style: "background-color:white;width:50%;margin:250 auto",
12532                     cn: [
12533                         {
12534                             tag: "img",
12535                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
12536                         },
12537                         {
12538                             tag: "span",
12539                             html: "Loading"
12540                         }
12541                         
12542                     ]
12543                 }
12544             ]
12545         }
12546         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12547         
12548         var size = this.el.select('.fc-content', true).first().getSize();
12549         this.maskEl.setSize(size.width, size.height);
12550         this.maskEl.enableDisplayMode("block");
12551         if(!this.loadMask){
12552             this.maskEl.hide();
12553         }
12554         
12555         this.store = Roo.factory(this.store, Roo.data);
12556         this.store.on('load', this.onLoad, this);
12557         this.store.on('beforeload', this.onBeforeLoad, this);
12558         
12559         this.resize();
12560         
12561         this.cells = this.el.select('.fc-day',true);
12562         //Roo.log(this.cells);
12563         this.textNodes = this.el.query('.fc-day-number');
12564         this.cells.addClassOnOver('fc-state-hover');
12565         
12566         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12567         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12568         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12569         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12570         
12571         this.on('monthchange', this.onMonthChange, this);
12572         
12573         this.update(new Date().clearTime());
12574     },
12575     
12576     resize : function() {
12577         var sz  = this.el.getSize();
12578         
12579         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12580         this.el.select('.fc-day-content div',true).setHeight(34);
12581     },
12582     
12583     
12584     // private
12585     showPrevMonth : function(e){
12586         this.update(this.activeDate.add("mo", -1));
12587     },
12588     showToday : function(e){
12589         this.update(new Date().clearTime());
12590     },
12591     // private
12592     showNextMonth : function(e){
12593         this.update(this.activeDate.add("mo", 1));
12594     },
12595
12596     // private
12597     showPrevYear : function(){
12598         this.update(this.activeDate.add("y", -1));
12599     },
12600
12601     // private
12602     showNextYear : function(){
12603         this.update(this.activeDate.add("y", 1));
12604     },
12605
12606     
12607    // private
12608     update : function(date)
12609     {
12610         var vd = this.activeDate;
12611         this.activeDate = date;
12612 //        if(vd && this.el){
12613 //            var t = date.getTime();
12614 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12615 //                Roo.log('using add remove');
12616 //                
12617 //                this.fireEvent('monthchange', this, date);
12618 //                
12619 //                this.cells.removeClass("fc-state-highlight");
12620 //                this.cells.each(function(c){
12621 //                   if(c.dateValue == t){
12622 //                       c.addClass("fc-state-highlight");
12623 //                       setTimeout(function(){
12624 //                            try{c.dom.firstChild.focus();}catch(e){}
12625 //                       }, 50);
12626 //                       return false;
12627 //                   }
12628 //                   return true;
12629 //                });
12630 //                return;
12631 //            }
12632 //        }
12633         
12634         var days = date.getDaysInMonth();
12635         
12636         var firstOfMonth = date.getFirstDateOfMonth();
12637         var startingPos = firstOfMonth.getDay()-this.startDay;
12638         
12639         if(startingPos < this.startDay){
12640             startingPos += 7;
12641         }
12642         
12643         var pm = date.add(Date.MONTH, -1);
12644         var prevStart = pm.getDaysInMonth()-startingPos;
12645 //        
12646         this.cells = this.el.select('.fc-day',true);
12647         this.textNodes = this.el.query('.fc-day-number');
12648         this.cells.addClassOnOver('fc-state-hover');
12649         
12650         var cells = this.cells.elements;
12651         var textEls = this.textNodes;
12652         
12653         Roo.each(cells, function(cell){
12654             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12655         });
12656         
12657         days += startingPos;
12658
12659         // convert everything to numbers so it's fast
12660         var day = 86400000;
12661         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12662         //Roo.log(d);
12663         //Roo.log(pm);
12664         //Roo.log(prevStart);
12665         
12666         var today = new Date().clearTime().getTime();
12667         var sel = date.clearTime().getTime();
12668         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12669         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12670         var ddMatch = this.disabledDatesRE;
12671         var ddText = this.disabledDatesText;
12672         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12673         var ddaysText = this.disabledDaysText;
12674         var format = this.format;
12675         
12676         var setCellClass = function(cal, cell){
12677             cell.row = 0;
12678             cell.events = [];
12679             cell.more = [];
12680             //Roo.log('set Cell Class');
12681             cell.title = "";
12682             var t = d.getTime();
12683             
12684             //Roo.log(d);
12685             
12686             cell.dateValue = t;
12687             if(t == today){
12688                 cell.className += " fc-today";
12689                 cell.className += " fc-state-highlight";
12690                 cell.title = cal.todayText;
12691             }
12692             if(t == sel){
12693                 // disable highlight in other month..
12694                 //cell.className += " fc-state-highlight";
12695                 
12696             }
12697             // disabling
12698             if(t < min) {
12699                 cell.className = " fc-state-disabled";
12700                 cell.title = cal.minText;
12701                 return;
12702             }
12703             if(t > max) {
12704                 cell.className = " fc-state-disabled";
12705                 cell.title = cal.maxText;
12706                 return;
12707             }
12708             if(ddays){
12709                 if(ddays.indexOf(d.getDay()) != -1){
12710                     cell.title = ddaysText;
12711                     cell.className = " fc-state-disabled";
12712                 }
12713             }
12714             if(ddMatch && format){
12715                 var fvalue = d.dateFormat(format);
12716                 if(ddMatch.test(fvalue)){
12717                     cell.title = ddText.replace("%0", fvalue);
12718                     cell.className = " fc-state-disabled";
12719                 }
12720             }
12721             
12722             if (!cell.initialClassName) {
12723                 cell.initialClassName = cell.dom.className;
12724             }
12725             
12726             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
12727         };
12728
12729         var i = 0;
12730         
12731         for(; i < startingPos; i++) {
12732             textEls[i].innerHTML = (++prevStart);
12733             d.setDate(d.getDate()+1);
12734             
12735             cells[i].className = "fc-past fc-other-month";
12736             setCellClass(this, cells[i]);
12737         }
12738         
12739         var intDay = 0;
12740         
12741         for(; i < days; i++){
12742             intDay = i - startingPos + 1;
12743             textEls[i].innerHTML = (intDay);
12744             d.setDate(d.getDate()+1);
12745             
12746             cells[i].className = ''; // "x-date-active";
12747             setCellClass(this, cells[i]);
12748         }
12749         var extraDays = 0;
12750         
12751         for(; i < 42; i++) {
12752             textEls[i].innerHTML = (++extraDays);
12753             d.setDate(d.getDate()+1);
12754             
12755             cells[i].className = "fc-future fc-other-month";
12756             setCellClass(this, cells[i]);
12757         }
12758         
12759         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12760         
12761         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12762         
12763         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12764         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12765         
12766         if(totalRows != 6){
12767             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12768             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12769         }
12770         
12771         this.fireEvent('monthchange', this, date);
12772         
12773         
12774         /*
12775         if(!this.internalRender){
12776             var main = this.el.dom.firstChild;
12777             var w = main.offsetWidth;
12778             this.el.setWidth(w + this.el.getBorderWidth("lr"));
12779             Roo.fly(main).setWidth(w);
12780             this.internalRender = true;
12781             // opera does not respect the auto grow header center column
12782             // then, after it gets a width opera refuses to recalculate
12783             // without a second pass
12784             if(Roo.isOpera && !this.secondPass){
12785                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12786                 this.secondPass = true;
12787                 this.update.defer(10, this, [date]);
12788             }
12789         }
12790         */
12791         
12792     },
12793     
12794     findCell : function(dt) {
12795         dt = dt.clearTime().getTime();
12796         var ret = false;
12797         this.cells.each(function(c){
12798             //Roo.log("check " +c.dateValue + '?=' + dt);
12799             if(c.dateValue == dt){
12800                 ret = c;
12801                 return false;
12802             }
12803             return true;
12804         });
12805         
12806         return ret;
12807     },
12808     
12809     findCells : function(ev) {
12810         var s = ev.start.clone().clearTime().getTime();
12811        // Roo.log(s);
12812         var e= ev.end.clone().clearTime().getTime();
12813        // Roo.log(e);
12814         var ret = [];
12815         this.cells.each(function(c){
12816              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12817             
12818             if(c.dateValue > e){
12819                 return ;
12820             }
12821             if(c.dateValue < s){
12822                 return ;
12823             }
12824             ret.push(c);
12825         });
12826         
12827         return ret;    
12828     },
12829     
12830 //    findBestRow: function(cells)
12831 //    {
12832 //        var ret = 0;
12833 //        
12834 //        for (var i =0 ; i < cells.length;i++) {
12835 //            ret  = Math.max(cells[i].rows || 0,ret);
12836 //        }
12837 //        return ret;
12838 //        
12839 //    },
12840     
12841     
12842     addItem : function(ev)
12843     {
12844         // look for vertical location slot in
12845         var cells = this.findCells(ev);
12846         
12847 //        ev.row = this.findBestRow(cells);
12848         
12849         // work out the location.
12850         
12851         var crow = false;
12852         var rows = [];
12853         for(var i =0; i < cells.length; i++) {
12854             
12855             cells[i].row = cells[0].row;
12856             
12857             if(i == 0){
12858                 cells[i].row = cells[i].row + 1;
12859             }
12860             
12861             if (!crow) {
12862                 crow = {
12863                     start : cells[i],
12864                     end :  cells[i]
12865                 };
12866                 continue;
12867             }
12868             if (crow.start.getY() == cells[i].getY()) {
12869                 // on same row.
12870                 crow.end = cells[i];
12871                 continue;
12872             }
12873             // different row.
12874             rows.push(crow);
12875             crow = {
12876                 start: cells[i],
12877                 end : cells[i]
12878             };
12879             
12880         }
12881         
12882         rows.push(crow);
12883         ev.els = [];
12884         ev.rows = rows;
12885         ev.cells = cells;
12886         
12887         cells[0].events.push(ev);
12888         
12889         this.calevents.push(ev);
12890     },
12891     
12892     clearEvents: function() {
12893         
12894         if(!this.calevents){
12895             return;
12896         }
12897         
12898         Roo.each(this.cells.elements, function(c){
12899             c.row = 0;
12900             c.events = [];
12901             c.more = [];
12902         });
12903         
12904         Roo.each(this.calevents, function(e) {
12905             Roo.each(e.els, function(el) {
12906                 el.un('mouseenter' ,this.onEventEnter, this);
12907                 el.un('mouseleave' ,this.onEventLeave, this);
12908                 el.remove();
12909             },this);
12910         },this);
12911         
12912         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12913             e.remove();
12914         });
12915         
12916     },
12917     
12918     renderEvents: function()
12919     {   
12920         var _this = this;
12921         
12922         this.cells.each(function(c) {
12923             
12924             if(c.row < 5){
12925                 return;
12926             }
12927             
12928             var ev = c.events;
12929             
12930             var r = 4;
12931             if(c.row != c.events.length){
12932                 r = 4 - (4 - (c.row - c.events.length));
12933             }
12934             
12935             c.events = ev.slice(0, r);
12936             c.more = ev.slice(r);
12937             
12938             if(c.more.length && c.more.length == 1){
12939                 c.events.push(c.more.pop());
12940             }
12941             
12942             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12943             
12944         });
12945             
12946         this.cells.each(function(c) {
12947             
12948             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12949             
12950             
12951             for (var e = 0; e < c.events.length; e++){
12952                 var ev = c.events[e];
12953                 var rows = ev.rows;
12954                 
12955                 for(var i = 0; i < rows.length; i++) {
12956                 
12957                     // how many rows should it span..
12958
12959                     var  cfg = {
12960                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12961                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12962
12963                         unselectable : "on",
12964                         cn : [
12965                             {
12966                                 cls: 'fc-event-inner',
12967                                 cn : [
12968     //                                {
12969     //                                  tag:'span',
12970     //                                  cls: 'fc-event-time',
12971     //                                  html : cells.length > 1 ? '' : ev.time
12972     //                                },
12973                                     {
12974                                       tag:'span',
12975                                       cls: 'fc-event-title',
12976                                       html : String.format('{0}', ev.title)
12977                                     }
12978
12979
12980                                 ]
12981                             },
12982                             {
12983                                 cls: 'ui-resizable-handle ui-resizable-e',
12984                                 html : '&nbsp;&nbsp;&nbsp'
12985                             }
12986
12987                         ]
12988                     };
12989
12990                     if (i == 0) {
12991                         cfg.cls += ' fc-event-start';
12992                     }
12993                     if ((i+1) == rows.length) {
12994                         cfg.cls += ' fc-event-end';
12995                     }
12996
12997                     var ctr = _this.el.select('.fc-event-container',true).first();
12998                     var cg = ctr.createChild(cfg);
12999
13000                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13001                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13002
13003                     var r = (c.more.length) ? 1 : 0;
13004                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13005                     cg.setWidth(ebox.right - sbox.x -2);
13006
13007                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13008                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13009                     cg.on('click', _this.onEventClick, _this, ev);
13010
13011                     ev.els.push(cg);
13012                     
13013                 }
13014                 
13015             }
13016             
13017             
13018             if(c.more.length){
13019                 var  cfg = {
13020                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13021                     style : 'position: absolute',
13022                     unselectable : "on",
13023                     cn : [
13024                         {
13025                             cls: 'fc-event-inner',
13026                             cn : [
13027                                 {
13028                                   tag:'span',
13029                                   cls: 'fc-event-title',
13030                                   html : 'More'
13031                                 }
13032
13033
13034                             ]
13035                         },
13036                         {
13037                             cls: 'ui-resizable-handle ui-resizable-e',
13038                             html : '&nbsp;&nbsp;&nbsp'
13039                         }
13040
13041                     ]
13042                 };
13043
13044                 var ctr = _this.el.select('.fc-event-container',true).first();
13045                 var cg = ctr.createChild(cfg);
13046
13047                 var sbox = c.select('.fc-day-content',true).first().getBox();
13048                 var ebox = c.select('.fc-day-content',true).first().getBox();
13049                 //Roo.log(cg);
13050                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13051                 cg.setWidth(ebox.right - sbox.x -2);
13052
13053                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13054                 
13055             }
13056             
13057         });
13058         
13059         
13060         
13061     },
13062     
13063     onEventEnter: function (e, el,event,d) {
13064         this.fireEvent('evententer', this, el, event);
13065     },
13066     
13067     onEventLeave: function (e, el,event,d) {
13068         this.fireEvent('eventleave', this, el, event);
13069     },
13070     
13071     onEventClick: function (e, el,event,d) {
13072         this.fireEvent('eventclick', this, el, event);
13073     },
13074     
13075     onMonthChange: function () {
13076         this.store.load();
13077     },
13078     
13079     onMoreEventClick: function(e, el, more)
13080     {
13081         var _this = this;
13082         
13083         this.calpopover.placement = 'right';
13084         this.calpopover.setTitle('More');
13085         
13086         this.calpopover.setContent('');
13087         
13088         var ctr = this.calpopover.el.select('.popover-content', true).first();
13089         
13090         Roo.each(more, function(m){
13091             var cfg = {
13092                 cls : 'fc-event-hori fc-event-draggable',
13093                 html : m.title
13094             }
13095             var cg = ctr.createChild(cfg);
13096             
13097             cg.on('click', _this.onEventClick, _this, m);
13098         });
13099         
13100         this.calpopover.show(el);
13101         
13102         
13103     },
13104     
13105     onLoad: function () 
13106     {   
13107         this.calevents = [];
13108         var cal = this;
13109         
13110         if(this.store.getCount() > 0){
13111             this.store.data.each(function(d){
13112                cal.addItem({
13113                     id : d.data.id,
13114                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13115                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13116                     time : d.data.start_time,
13117                     title : d.data.title,
13118                     description : d.data.description,
13119                     venue : d.data.venue
13120                 });
13121             });
13122         }
13123         
13124         this.renderEvents();
13125         
13126         if(this.calevents.length && this.loadMask){
13127             this.maskEl.hide();
13128         }
13129     },
13130     
13131     onBeforeLoad: function()
13132     {
13133         this.clearEvents();
13134         if(this.loadMask){
13135             this.maskEl.show();
13136         }
13137     }
13138 });
13139
13140  
13141  /*
13142  * - LGPL
13143  *
13144  * element
13145  * 
13146  */
13147
13148 /**
13149  * @class Roo.bootstrap.Popover
13150  * @extends Roo.bootstrap.Component
13151  * Bootstrap Popover class
13152  * @cfg {String} html contents of the popover   (or false to use children..)
13153  * @cfg {String} title of popover (or false to hide)
13154  * @cfg {String} placement how it is placed
13155  * @cfg {String} trigger click || hover (or false to trigger manually)
13156  * @cfg {String} over what (parent or false to trigger manually.)
13157  * 
13158  * @constructor
13159  * Create a new Popover
13160  * @param {Object} config The config object
13161  */
13162
13163 Roo.bootstrap.Popover = function(config){
13164     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13165 };
13166
13167 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13168     
13169     title: 'Fill in a title',
13170     html: false,
13171     
13172     placement : 'right',
13173     trigger : 'hover', // hover
13174     
13175     over: 'parent',
13176     
13177     can_build_overlaid : false,
13178     
13179     getChildContainer : function()
13180     {
13181         return this.el.select('.popover-content',true).first();
13182     },
13183     
13184     getAutoCreate : function(){
13185          Roo.log('make popover?');
13186         var cfg = {
13187            cls : 'popover roo-dynamic',
13188            style: 'display:block',
13189            cn : [
13190                 {
13191                     cls : 'arrow'
13192                 },
13193                 {
13194                     cls : 'popover-inner',
13195                     cn : [
13196                         {
13197                             tag: 'h3',
13198                             cls: 'popover-title',
13199                             html : this.title
13200                         },
13201                         {
13202                             cls : 'popover-content',
13203                             html : this.html
13204                         }
13205                     ]
13206                     
13207                 }
13208            ]
13209         };
13210         
13211         return cfg;
13212     },
13213     setTitle: function(str)
13214     {
13215         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13216     },
13217     setContent: function(str)
13218     {
13219         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13220     },
13221     // as it get's added to the bottom of the page.
13222     onRender : function(ct, position)
13223     {
13224         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13225         if(!this.el){
13226             var cfg = Roo.apply({},  this.getAutoCreate());
13227             cfg.id = Roo.id();
13228             
13229             if (this.cls) {
13230                 cfg.cls += ' ' + this.cls;
13231             }
13232             if (this.style) {
13233                 cfg.style = this.style;
13234             }
13235             Roo.log("adding to ")
13236             this.el = Roo.get(document.body).createChild(cfg, position);
13237             Roo.log(this.el);
13238         }
13239         this.initEvents();
13240     },
13241     
13242     initEvents : function()
13243     {
13244         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13245         this.el.enableDisplayMode('block');
13246         this.el.hide();
13247         if (this.over === false) {
13248             return; 
13249         }
13250         if (this.triggers === false) {
13251             return;
13252         }
13253         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13254         var triggers = this.trigger ? this.trigger.split(' ') : [];
13255         Roo.each(triggers, function(trigger) {
13256         
13257             if (trigger == 'click') {
13258                 on_el.on('click', this.toggle, this);
13259             } else if (trigger != 'manual') {
13260                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
13261                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13262       
13263                 on_el.on(eventIn  ,this.enter, this);
13264                 on_el.on(eventOut, this.leave, this);
13265             }
13266         }, this);
13267         
13268     },
13269     
13270     
13271     // private
13272     timeout : null,
13273     hoverState : null,
13274     
13275     toggle : function () {
13276         this.hoverState == 'in' ? this.leave() : this.enter();
13277     },
13278     
13279     enter : function () {
13280        
13281     
13282         clearTimeout(this.timeout);
13283     
13284         this.hoverState = 'in'
13285     
13286         if (!this.delay || !this.delay.show) {
13287             this.show();
13288             return 
13289         }
13290         var _t = this;
13291         this.timeout = setTimeout(function () {
13292             if (_t.hoverState == 'in') {
13293                 _t.show();
13294             }
13295         }, this.delay.show)
13296     },
13297     leave : function() {
13298         clearTimeout(this.timeout);
13299     
13300         this.hoverState = 'out'
13301     
13302         if (!this.delay || !this.delay.hide) {
13303             this.hide();
13304             return 
13305         }
13306         var _t = this;
13307         this.timeout = setTimeout(function () {
13308             if (_t.hoverState == 'out') {
13309                 _t.hide();
13310             }
13311         }, this.delay.hide)
13312     },
13313     
13314     show : function (on_el)
13315     {
13316         if (!on_el) {
13317             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13318         }
13319         // set content.
13320         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13321         if (this.html !== false) {
13322             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13323         }
13324         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13325         if (!this.title.length) {
13326             this.el.select('.popover-title',true).hide();
13327         }
13328         
13329         var placement = typeof this.placement == 'function' ?
13330             this.placement.call(this, this.el, on_el) :
13331             this.placement;
13332             
13333         var autoToken = /\s?auto?\s?/i;
13334         var autoPlace = autoToken.test(placement);
13335         if (autoPlace) {
13336             placement = placement.replace(autoToken, '') || 'top';
13337         }
13338         
13339         //this.el.detach()
13340         //this.el.setXY([0,0]);
13341         this.el.show();
13342         this.el.dom.style.display='block';
13343         this.el.addClass(placement);
13344         
13345         //this.el.appendTo(on_el);
13346         
13347         var p = this.getPosition();
13348         var box = this.el.getBox();
13349         
13350         if (autoPlace) {
13351             // fixme..
13352         }
13353         var align = Roo.bootstrap.Popover.alignment[placement]
13354         this.el.alignTo(on_el, align[0],align[1]);
13355         //var arrow = this.el.select('.arrow',true).first();
13356         //arrow.set(align[2], 
13357         
13358         this.el.addClass('in');
13359         this.hoverState = null;
13360         
13361         if (this.el.hasClass('fade')) {
13362             // fade it?
13363         }
13364         
13365     },
13366     hide : function()
13367     {
13368         this.el.setXY([0,0]);
13369         this.el.removeClass('in');
13370         this.el.hide();
13371         
13372     }
13373     
13374 });
13375
13376 Roo.bootstrap.Popover.alignment = {
13377     'left' : ['r-l', [-10,0], 'right'],
13378     'right' : ['l-r', [10,0], 'left'],
13379     'bottom' : ['t-b', [0,10], 'top'],
13380     'top' : [ 'b-t', [0,-10], 'bottom']
13381 };
13382
13383  /*
13384  * - LGPL
13385  *
13386  * Progress
13387  * 
13388  */
13389
13390 /**
13391  * @class Roo.bootstrap.Progress
13392  * @extends Roo.bootstrap.Component
13393  * Bootstrap Progress class
13394  * @cfg {Boolean} striped striped of the progress bar
13395  * @cfg {Boolean} active animated of the progress bar
13396  * 
13397  * 
13398  * @constructor
13399  * Create a new Progress
13400  * @param {Object} config The config object
13401  */
13402
13403 Roo.bootstrap.Progress = function(config){
13404     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13405 };
13406
13407 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
13408     
13409     striped : false,
13410     active: false,
13411     
13412     getAutoCreate : function(){
13413         var cfg = {
13414             tag: 'div',
13415             cls: 'progress'
13416         };
13417         
13418         
13419         if(this.striped){
13420             cfg.cls += ' progress-striped';
13421         }
13422       
13423         if(this.active){
13424             cfg.cls += ' active';
13425         }
13426         
13427         
13428         return cfg;
13429     }
13430    
13431 });
13432
13433  
13434
13435  /*
13436  * - LGPL
13437  *
13438  * ProgressBar
13439  * 
13440  */
13441
13442 /**
13443  * @class Roo.bootstrap.ProgressBar
13444  * @extends Roo.bootstrap.Component
13445  * Bootstrap ProgressBar class
13446  * @cfg {Number} aria_valuenow aria-value now
13447  * @cfg {Number} aria_valuemin aria-value min
13448  * @cfg {Number} aria_valuemax aria-value max
13449  * @cfg {String} label label for the progress bar
13450  * @cfg {String} panel (success | info | warning | danger )
13451  * @cfg {String} role role of the progress bar
13452  * @cfg {String} sr_only text
13453  * 
13454  * 
13455  * @constructor
13456  * Create a new ProgressBar
13457  * @param {Object} config The config object
13458  */
13459
13460 Roo.bootstrap.ProgressBar = function(config){
13461     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13462 };
13463
13464 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
13465     
13466     aria_valuenow : 0,
13467     aria_valuemin : 0,
13468     aria_valuemax : 100,
13469     label : false,
13470     panel : false,
13471     role : false,
13472     sr_only: false,
13473     
13474     getAutoCreate : function()
13475     {
13476         
13477         var cfg = {
13478             tag: 'div',
13479             cls: 'progress-bar',
13480             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13481         };
13482         
13483         if(this.sr_only){
13484             cfg.cn = {
13485                 tag: 'span',
13486                 cls: 'sr-only',
13487                 html: this.sr_only
13488             }
13489         }
13490         
13491         if(this.role){
13492             cfg.role = this.role;
13493         }
13494         
13495         if(this.aria_valuenow){
13496             cfg['aria-valuenow'] = this.aria_valuenow;
13497         }
13498         
13499         if(this.aria_valuemin){
13500             cfg['aria-valuemin'] = this.aria_valuemin;
13501         }
13502         
13503         if(this.aria_valuemax){
13504             cfg['aria-valuemax'] = this.aria_valuemax;
13505         }
13506         
13507         if(this.label && !this.sr_only){
13508             cfg.html = this.label;
13509         }
13510         
13511         if(this.panel){
13512             cfg.cls += ' progress-bar-' + this.panel;
13513         }
13514         
13515         return cfg;
13516     },
13517     
13518     update : function(aria_valuenow)
13519     {
13520         this.aria_valuenow = aria_valuenow;
13521         
13522         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13523     }
13524    
13525 });
13526
13527  
13528
13529  /*
13530  * - LGPL
13531  *
13532  * TabPanel
13533  * 
13534  */
13535
13536 /**
13537  * @class Roo.bootstrap.TabPanel
13538  * @extends Roo.bootstrap.Component
13539  * Bootstrap TabPanel class
13540  * @cfg {Boolean} active panel active
13541  * @cfg {String} html panel content
13542  * @cfg {String} tabId tab relate id
13543  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13544  * 
13545  * 
13546  * @constructor
13547  * Create a new TabPanel
13548  * @param {Object} config The config object
13549  */
13550
13551 Roo.bootstrap.TabPanel = function(config){
13552     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13553      this.addEvents({
13554         /**
13555              * @event changed
13556              * Fires when the active status changes
13557              * @param {Roo.bootstrap.TabPanel} this
13558              * @param {Boolean} state the new state
13559             
13560          */
13561         'changed': true
13562      });
13563 };
13564
13565 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
13566     
13567     active: false,
13568     html: false,
13569     tabId: false,
13570     navId : false,
13571     
13572     getAutoCreate : function(){
13573         var cfg = {
13574             tag: 'div',
13575             cls: 'tab-pane',
13576             html: this.html || ''
13577         };
13578         
13579         if(this.active){
13580             cfg.cls += ' active';
13581         }
13582         
13583         if(this.tabId){
13584             cfg.tabId = this.tabId;
13585         }
13586         
13587         return cfg;
13588     },
13589     onRender : function(ct, position)
13590     {
13591        // Roo.log("Call onRender: " + this.xtype);
13592         
13593         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13594         
13595         if (this.navId && this.tabId) {
13596             var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13597             if (!item) {
13598                 Roo.log("could not find navID:"  + this.navId + ", tabId: " + this.tabId);
13599             } else {
13600                 item.on('changed', function(item, state) {
13601                     this.setActive(state);
13602                 }, this);
13603             }
13604         }
13605         
13606     },
13607     setActive: function(state)
13608     {
13609         Roo.log("panel - set active " + this.tabId + "=" + state);
13610         
13611         this.active = state;
13612         if (!state) {
13613             this.el.removeClass('active');
13614             
13615         } else  if (!this.el.hasClass('active')) {
13616             this.el.addClass('active');
13617         }
13618         this.fireEvent('changed', this, state);
13619     }
13620     
13621     
13622 });
13623  
13624
13625  
13626
13627  /*
13628  * - LGPL
13629  *
13630  * DateField
13631  * 
13632  */
13633
13634 /**
13635  * @class Roo.bootstrap.DateField
13636  * @extends Roo.bootstrap.Input
13637  * Bootstrap DateField class
13638  * @cfg {Number} weekStart default 0
13639  * @cfg {Number} weekStart default 0
13640  * @cfg {Number} viewMode default empty, (months|years)
13641  * @cfg {Number} minViewMode default empty, (months|years)
13642  * @cfg {Number} startDate default -Infinity
13643  * @cfg {Number} endDate default Infinity
13644  * @cfg {Boolean} todayHighlight default false
13645  * @cfg {Boolean} todayBtn default false
13646  * @cfg {Boolean} calendarWeeks default false
13647  * @cfg {Object} daysOfWeekDisabled default empty
13648  * 
13649  * @cfg {Boolean} keyboardNavigation default true
13650  * @cfg {String} language default en
13651  * 
13652  * @constructor
13653  * Create a new DateField
13654  * @param {Object} config The config object
13655  */
13656
13657 Roo.bootstrap.DateField = function(config){
13658     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13659      this.addEvents({
13660             /**
13661              * @event show
13662              * Fires when this field show.
13663              * @param {Roo.bootstrap.DateField} this
13664              * @param {Mixed} date The date value
13665              */
13666             show : true,
13667             /**
13668              * @event show
13669              * Fires when this field hide.
13670              * @param {Roo.bootstrap.DateField} this
13671              * @param {Mixed} date The date value
13672              */
13673             hide : true,
13674             /**
13675              * @event select
13676              * Fires when select a date.
13677              * @param {Roo.bootstrap.DateField} this
13678              * @param {Mixed} date The date value
13679              */
13680             select : true
13681         });
13682 };
13683
13684 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
13685     
13686     /**
13687      * @cfg {String} format
13688      * The default date format string which can be overriden for localization support.  The format must be
13689      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13690      */
13691     format : "m/d/y",
13692     /**
13693      * @cfg {String} altFormats
13694      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13695      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13696      */
13697     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13698     
13699     weekStart : 0,
13700     
13701     viewMode : '',
13702     
13703     minViewMode : '',
13704     
13705     todayHighlight : false,
13706     
13707     todayBtn: false,
13708     
13709     language: 'en',
13710     
13711     keyboardNavigation: true,
13712     
13713     calendarWeeks: false,
13714     
13715     startDate: -Infinity,
13716     
13717     endDate: Infinity,
13718     
13719     daysOfWeekDisabled: [],
13720     
13721     _events: [],
13722     
13723     UTCDate: function()
13724     {
13725         return new Date(Date.UTC.apply(Date, arguments));
13726     },
13727     
13728     UTCToday: function()
13729     {
13730         var today = new Date();
13731         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13732     },
13733     
13734     getDate: function() {
13735             var d = this.getUTCDate();
13736             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13737     },
13738     
13739     getUTCDate: function() {
13740             return this.date;
13741     },
13742     
13743     setDate: function(d) {
13744             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13745     },
13746     
13747     setUTCDate: function(d) {
13748             this.date = d;
13749             this.setValue(this.formatDate(this.date));
13750     },
13751         
13752     onRender: function(ct, position)
13753     {
13754         
13755         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13756         
13757         this.language = this.language || 'en';
13758         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13759         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13760         
13761         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13762         this.format = this.format || 'm/d/y';
13763         this.isInline = false;
13764         this.isInput = true;
13765         this.component = this.el.select('.add-on', true).first() || false;
13766         this.component = (this.component && this.component.length === 0) ? false : this.component;
13767         this.hasInput = this.component && this.inputEL().length;
13768         
13769         if (typeof(this.minViewMode === 'string')) {
13770             switch (this.minViewMode) {
13771                 case 'months':
13772                     this.minViewMode = 1;
13773                     break;
13774                 case 'years':
13775                     this.minViewMode = 2;
13776                     break;
13777                 default:
13778                     this.minViewMode = 0;
13779                     break;
13780             }
13781         }
13782         
13783         if (typeof(this.viewMode === 'string')) {
13784             switch (this.viewMode) {
13785                 case 'months':
13786                     this.viewMode = 1;
13787                     break;
13788                 case 'years':
13789                     this.viewMode = 2;
13790                     break;
13791                 default:
13792                     this.viewMode = 0;
13793                     break;
13794             }
13795         }
13796                 
13797         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13798         
13799         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13800         
13801         this.picker().on('mousedown', this.onMousedown, this);
13802         this.picker().on('click', this.onClick, this);
13803         
13804         this.picker().addClass('datepicker-dropdown');
13805         
13806         this.startViewMode = this.viewMode;
13807         
13808         
13809         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13810             if(!this.calendarWeeks){
13811                 v.remove();
13812                 return;
13813             };
13814             
13815             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13816             v.attr('colspan', function(i, val){
13817                 return parseInt(val) + 1;
13818             });
13819         })
13820                         
13821         
13822         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13823         
13824         this.setStartDate(this.startDate);
13825         this.setEndDate(this.endDate);
13826         
13827         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13828         
13829         this.fillDow();
13830         this.fillMonths();
13831         this.update();
13832         this.showMode();
13833         
13834         if(this.isInline) {
13835             this.show();
13836         }
13837     },
13838     
13839     picker : function()
13840     {
13841         return this.el.select('.datepicker', true).first();
13842     },
13843     
13844     fillDow: function()
13845     {
13846         var dowCnt = this.weekStart;
13847         
13848         var dow = {
13849             tag: 'tr',
13850             cn: [
13851                 
13852             ]
13853         };
13854         
13855         if(this.calendarWeeks){
13856             dow.cn.push({
13857                 tag: 'th',
13858                 cls: 'cw',
13859                 html: '&nbsp;'
13860             })
13861         }
13862         
13863         while (dowCnt < this.weekStart + 7) {
13864             dow.cn.push({
13865                 tag: 'th',
13866                 cls: 'dow',
13867                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13868             });
13869         }
13870         
13871         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13872     },
13873     
13874     fillMonths: function()
13875     {    
13876         var i = 0
13877         var months = this.picker().select('>.datepicker-months td', true).first();
13878         
13879         months.dom.innerHTML = '';
13880         
13881         while (i < 12) {
13882             var month = {
13883                 tag: 'span',
13884                 cls: 'month',
13885                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13886             }
13887             
13888             months.createChild(month);
13889         }
13890         
13891     },
13892     
13893     update: function()
13894     {
13895         
13896         this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13897         
13898         if (this.date < this.startDate) {
13899             this.viewDate = new Date(this.startDate);
13900         } else if (this.date > this.endDate) {
13901             this.viewDate = new Date(this.endDate);
13902         } else {
13903             this.viewDate = new Date(this.date);
13904         }
13905         
13906         this.fill();
13907     },
13908     
13909     fill: function() 
13910     {
13911         var d = new Date(this.viewDate),
13912                 year = d.getUTCFullYear(),
13913                 month = d.getUTCMonth(),
13914                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13915                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13916                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13917                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13918                 currentDate = this.date && this.date.valueOf(),
13919                 today = this.UTCToday();
13920         
13921         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13922         
13923 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13924         
13925 //        this.picker.select('>tfoot th.today').
13926 //                                              .text(dates[this.language].today)
13927 //                                              .toggle(this.todayBtn !== false);
13928     
13929         this.updateNavArrows();
13930         this.fillMonths();
13931                                                 
13932         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13933         
13934         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13935          
13936         prevMonth.setUTCDate(day);
13937         
13938         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13939         
13940         var nextMonth = new Date(prevMonth);
13941         
13942         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13943         
13944         nextMonth = nextMonth.valueOf();
13945         
13946         var fillMonths = false;
13947         
13948         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13949         
13950         while(prevMonth.valueOf() < nextMonth) {
13951             var clsName = '';
13952             
13953             if (prevMonth.getUTCDay() === this.weekStart) {
13954                 if(fillMonths){
13955                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13956                 }
13957                     
13958                 fillMonths = {
13959                     tag: 'tr',
13960                     cn: []
13961                 };
13962                 
13963                 if(this.calendarWeeks){
13964                     // ISO 8601: First week contains first thursday.
13965                     // ISO also states week starts on Monday, but we can be more abstract here.
13966                     var
13967                     // Start of current week: based on weekstart/current date
13968                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13969                     // Thursday of this week
13970                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13971                     // First Thursday of year, year from thursday
13972                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13973                     // Calendar week: ms between thursdays, div ms per day, div 7 days
13974                     calWeek =  (th - yth) / 864e5 / 7 + 1;
13975                     
13976                     fillMonths.cn.push({
13977                         tag: 'td',
13978                         cls: 'cw',
13979                         html: calWeek
13980                     });
13981                 }
13982             }
13983             
13984             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13985                 clsName += ' old';
13986             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13987                 clsName += ' new';
13988             }
13989             if (this.todayHighlight &&
13990                 prevMonth.getUTCFullYear() == today.getFullYear() &&
13991                 prevMonth.getUTCMonth() == today.getMonth() &&
13992                 prevMonth.getUTCDate() == today.getDate()) {
13993                 clsName += ' today';
13994             }
13995             
13996             if (currentDate && prevMonth.valueOf() === currentDate) {
13997                 clsName += ' active';
13998             }
13999             
14000             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14001                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14002                     clsName += ' disabled';
14003             }
14004             
14005             fillMonths.cn.push({
14006                 tag: 'td',
14007                 cls: 'day ' + clsName,
14008                 html: prevMonth.getDate()
14009             })
14010             
14011             prevMonth.setDate(prevMonth.getDate()+1);
14012         }
14013           
14014         var currentYear = this.date && this.date.getUTCFullYear();
14015         var currentMonth = this.date && this.date.getUTCMonth();
14016         
14017         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14018         
14019         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14020             v.removeClass('active');
14021             
14022             if(currentYear === year && k === currentMonth){
14023                 v.addClass('active');
14024             }
14025             
14026             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14027                 v.addClass('disabled');
14028             }
14029             
14030         });
14031         
14032         
14033         year = parseInt(year/10, 10) * 10;
14034         
14035         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14036         
14037         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14038         
14039         year -= 1;
14040         for (var i = -1; i < 11; i++) {
14041             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14042                 tag: 'span',
14043                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14044                 html: year
14045             })
14046             
14047             year += 1;
14048         }
14049     },
14050     
14051     showMode: function(dir) 
14052     {
14053         if (dir) {
14054             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14055         }
14056         Roo.each(this.picker().select('>div',true).elements, function(v){
14057             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14058             v.hide();
14059         });
14060         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14061     },
14062     
14063     place: function()
14064     {
14065         if(this.isInline) return;
14066         
14067         this.picker().removeClass(['bottom', 'top']);
14068         
14069         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14070             /*
14071              * place to the top of element!
14072              *
14073              */
14074             
14075             this.picker().addClass('top');
14076             this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14077             
14078             return;
14079         }
14080         
14081         this.picker().addClass('bottom');
14082         
14083         this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14084     },
14085     
14086     parseDate : function(value)
14087     {
14088         if(!value || value instanceof Date){
14089             return value;
14090         }
14091         var v = Date.parseDate(value, this.format);
14092         if (!v && this.useIso) {
14093             v = Date.parseDate(value, 'Y-m-d');
14094         }
14095         if(!v && this.altFormats){
14096             if(!this.altFormatsArray){
14097                 this.altFormatsArray = this.altFormats.split("|");
14098             }
14099             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14100                 v = Date.parseDate(value, this.altFormatsArray[i]);
14101             }
14102         }
14103         return v;
14104     },
14105     
14106     formatDate : function(date, fmt)
14107     {
14108         return (!date || !(date instanceof Date)) ?
14109         date : date.dateFormat(fmt || this.format);
14110     },
14111     
14112     onFocus : function()
14113     {
14114         Roo.bootstrap.DateField.superclass.onFocus.call(this);
14115         this.show();
14116     },
14117     
14118     onBlur : function()
14119     {
14120         Roo.bootstrap.DateField.superclass.onBlur.call(this);
14121         
14122         var d = this.inputEl().getValue();
14123         
14124         if(d && d.length){
14125             this.setValue(d);
14126         }
14127                 
14128         this.hide();
14129     },
14130     
14131     show : function()
14132     {
14133         this.picker().show();
14134         this.update();
14135         this.place();
14136         
14137         this.fireEvent('show', this, this.date);
14138     },
14139     
14140     hide : function()
14141     {
14142         if(this.isInline) return;
14143         this.picker().hide();
14144         this.viewMode = this.startViewMode;
14145         this.showMode();
14146         
14147         this.fireEvent('hide', this, this.date);
14148         
14149     },
14150     
14151     onMousedown: function(e)
14152     {
14153         e.stopPropagation();
14154         e.preventDefault();
14155     },
14156     
14157     keyup: function(e)
14158     {
14159         Roo.bootstrap.DateField.superclass.keyup.call(this);
14160         this.update();
14161     },
14162
14163     setValue: function(v)
14164     {
14165         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14166         
14167         var d = new Date(v);
14168         
14169         if(isNaN(d.getTime())){
14170             return;
14171         }
14172         
14173         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14174
14175         this.update();
14176
14177         this.fireEvent('select', this, this.date);
14178         
14179     },
14180     
14181     getValue: function()
14182     {
14183         return this.formatDate(this.date);
14184     },
14185     
14186     fireKey: function(e)
14187     {
14188         if (!this.picker().isVisible()){
14189             if (e.keyCode == 27) // allow escape to hide and re-show picker
14190                 this.show();
14191             return;
14192         }
14193         var dateChanged = false,
14194         dir, day, month,
14195         newDate, newViewDate;
14196         
14197         switch(e.keyCode){
14198             case 27: // escape
14199                 this.hide();
14200                 e.preventDefault();
14201                 break;
14202             case 37: // left
14203             case 39: // right
14204                 if (!this.keyboardNavigation) break;
14205                 dir = e.keyCode == 37 ? -1 : 1;
14206                 
14207                 if (e.ctrlKey){
14208                     newDate = this.moveYear(this.date, dir);
14209                     newViewDate = this.moveYear(this.viewDate, dir);
14210                 } else if (e.shiftKey){
14211                     newDate = this.moveMonth(this.date, dir);
14212                     newViewDate = this.moveMonth(this.viewDate, dir);
14213                 } else {
14214                     newDate = new Date(this.date);
14215                     newDate.setUTCDate(this.date.getUTCDate() + dir);
14216                     newViewDate = new Date(this.viewDate);
14217                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14218                 }
14219                 if (this.dateWithinRange(newDate)){
14220                     this.date = newDate;
14221                     this.viewDate = newViewDate;
14222                     this.setValue(this.formatDate(this.date));
14223 //                    this.update();
14224                     e.preventDefault();
14225                     dateChanged = true;
14226                 }
14227                 break;
14228             case 38: // up
14229             case 40: // down
14230                 if (!this.keyboardNavigation) break;
14231                 dir = e.keyCode == 38 ? -1 : 1;
14232                 if (e.ctrlKey){
14233                     newDate = this.moveYear(this.date, dir);
14234                     newViewDate = this.moveYear(this.viewDate, dir);
14235                 } else if (e.shiftKey){
14236                     newDate = this.moveMonth(this.date, dir);
14237                     newViewDate = this.moveMonth(this.viewDate, dir);
14238                 } else {
14239                     newDate = new Date(this.date);
14240                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14241                     newViewDate = new Date(this.viewDate);
14242                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14243                 }
14244                 if (this.dateWithinRange(newDate)){
14245                     this.date = newDate;
14246                     this.viewDate = newViewDate;
14247                     this.setValue(this.formatDate(this.date));
14248 //                    this.update();
14249                     e.preventDefault();
14250                     dateChanged = true;
14251                 }
14252                 break;
14253             case 13: // enter
14254                 this.setValue(this.formatDate(this.date));
14255                 this.hide();
14256                 e.preventDefault();
14257                 break;
14258             case 9: // tab
14259                 this.setValue(this.formatDate(this.date));
14260                 this.hide();
14261                 break;
14262                 
14263         }
14264     },
14265     
14266     
14267     onClick: function(e) 
14268     {
14269         e.stopPropagation();
14270         e.preventDefault();
14271         
14272         var target = e.getTarget();
14273         
14274         if(target.nodeName.toLowerCase() === 'i'){
14275             target = Roo.get(target).dom.parentNode;
14276         }
14277         
14278         var nodeName = target.nodeName;
14279         var className = target.className;
14280         var html = target.innerHTML;
14281         
14282         switch(nodeName.toLowerCase()) {
14283             case 'th':
14284                 switch(className) {
14285                     case 'switch':
14286                         this.showMode(1);
14287                         break;
14288                     case 'prev':
14289                     case 'next':
14290                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14291                         switch(this.viewMode){
14292                                 case 0:
14293                                         this.viewDate = this.moveMonth(this.viewDate, dir);
14294                                         break;
14295                                 case 1:
14296                                 case 2:
14297                                         this.viewDate = this.moveYear(this.viewDate, dir);
14298                                         break;
14299                         }
14300                         this.fill();
14301                         break;
14302                     case 'today':
14303                         var date = new Date();
14304                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14305 //                        this.fill()
14306                         this.setValue(this.formatDate(this.date));
14307                         
14308                         this.hide();
14309                         break;
14310                 }
14311                 break;
14312             case 'span':
14313                 if (className.indexOf('disabled') === -1) {
14314                     this.viewDate.setUTCDate(1);
14315                     if (className.indexOf('month') !== -1) {
14316                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14317                     } else {
14318                         var year = parseInt(html, 10) || 0;
14319                         this.viewDate.setUTCFullYear(year);
14320                         
14321                     }
14322                     this.showMode(-1);
14323                     this.fill();
14324                 }
14325                 break;
14326                 
14327             case 'td':
14328                 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14329                     var day = parseInt(html, 10) || 1;
14330                     var year = this.viewDate.getUTCFullYear(),
14331                         month = this.viewDate.getUTCMonth();
14332
14333                     if (className.indexOf('old') !== -1) {
14334                         if(month === 0 ){
14335                             month = 11;
14336                             year -= 1;
14337                         }else{
14338                             month -= 1;
14339                         }
14340                     } else if (className.indexOf('new') !== -1) {
14341                         if (month == 11) {
14342                             month = 0;
14343                             year += 1;
14344                         } else {
14345                             month += 1;
14346                         }
14347                     }
14348                     this.date = this.UTCDate(year, month, day,0,0,0,0);
14349                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14350 //                    this.fill();
14351                     this.setValue(this.formatDate(this.date));
14352                     this.hide();
14353                 }
14354                 break;
14355         }
14356     },
14357     
14358     setStartDate: function(startDate)
14359     {
14360         this.startDate = startDate || -Infinity;
14361         if (this.startDate !== -Infinity) {
14362             this.startDate = this.parseDate(this.startDate);
14363         }
14364         this.update();
14365         this.updateNavArrows();
14366     },
14367
14368     setEndDate: function(endDate)
14369     {
14370         this.endDate = endDate || Infinity;
14371         if (this.endDate !== Infinity) {
14372             this.endDate = this.parseDate(this.endDate);
14373         }
14374         this.update();
14375         this.updateNavArrows();
14376     },
14377     
14378     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14379     {
14380         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14381         if (typeof(this.daysOfWeekDisabled) !== 'object') {
14382             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14383         }
14384         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14385             return parseInt(d, 10);
14386         });
14387         this.update();
14388         this.updateNavArrows();
14389     },
14390     
14391     updateNavArrows: function() 
14392     {
14393         var d = new Date(this.viewDate),
14394         year = d.getUTCFullYear(),
14395         month = d.getUTCMonth();
14396         
14397         Roo.each(this.picker().select('.prev', true).elements, function(v){
14398             v.show();
14399             switch (this.viewMode) {
14400                 case 0:
14401
14402                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14403                         v.hide();
14404                     }
14405                     break;
14406                 case 1:
14407                 case 2:
14408                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14409                         v.hide();
14410                     }
14411                     break;
14412             }
14413         });
14414         
14415         Roo.each(this.picker().select('.next', true).elements, function(v){
14416             v.show();
14417             switch (this.viewMode) {
14418                 case 0:
14419
14420                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14421                         v.hide();
14422                     }
14423                     break;
14424                 case 1:
14425                 case 2:
14426                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14427                         v.hide();
14428                     }
14429                     break;
14430             }
14431         })
14432     },
14433     
14434     moveMonth: function(date, dir)
14435     {
14436         if (!dir) return date;
14437         var new_date = new Date(date.valueOf()),
14438         day = new_date.getUTCDate(),
14439         month = new_date.getUTCMonth(),
14440         mag = Math.abs(dir),
14441         new_month, test;
14442         dir = dir > 0 ? 1 : -1;
14443         if (mag == 1){
14444             test = dir == -1
14445             // If going back one month, make sure month is not current month
14446             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14447             ? function(){
14448                 return new_date.getUTCMonth() == month;
14449             }
14450             // If going forward one month, make sure month is as expected
14451             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14452             : function(){
14453                 return new_date.getUTCMonth() != new_month;
14454             };
14455             new_month = month + dir;
14456             new_date.setUTCMonth(new_month);
14457             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14458             if (new_month < 0 || new_month > 11)
14459                 new_month = (new_month + 12) % 12;
14460         } else {
14461             // For magnitudes >1, move one month at a time...
14462             for (var i=0; i<mag; i++)
14463                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14464                 new_date = this.moveMonth(new_date, dir);
14465             // ...then reset the day, keeping it in the new month
14466             new_month = new_date.getUTCMonth();
14467             new_date.setUTCDate(day);
14468             test = function(){
14469                 return new_month != new_date.getUTCMonth();
14470             };
14471         }
14472         // Common date-resetting loop -- if date is beyond end of month, make it
14473         // end of month
14474         while (test()){
14475             new_date.setUTCDate(--day);
14476             new_date.setUTCMonth(new_month);
14477         }
14478         return new_date;
14479     },
14480
14481     moveYear: function(date, dir)
14482     {
14483         return this.moveMonth(date, dir*12);
14484     },
14485
14486     dateWithinRange: function(date)
14487     {
14488         return date >= this.startDate && date <= this.endDate;
14489     },
14490
14491     
14492     remove: function() 
14493     {
14494         this.picker().remove();
14495     }
14496    
14497 });
14498
14499 Roo.apply(Roo.bootstrap.DateField,  {
14500     
14501     head : {
14502         tag: 'thead',
14503         cn: [
14504         {
14505             tag: 'tr',
14506             cn: [
14507             {
14508                 tag: 'th',
14509                 cls: 'prev',
14510                 html: '<i class="fa fa-arrow-left"/>'
14511             },
14512             {
14513                 tag: 'th',
14514                 cls: 'switch',
14515                 colspan: '5'
14516             },
14517             {
14518                 tag: 'th',
14519                 cls: 'next',
14520                 html: '<i class="fa fa-arrow-right"/>'
14521             }
14522
14523             ]
14524         }
14525         ]
14526     },
14527     
14528     content : {
14529         tag: 'tbody',
14530         cn: [
14531         {
14532             tag: 'tr',
14533             cn: [
14534             {
14535                 tag: 'td',
14536                 colspan: '7'
14537             }
14538             ]
14539         }
14540         ]
14541     },
14542     
14543     footer : {
14544         tag: 'tfoot',
14545         cn: [
14546         {
14547             tag: 'tr',
14548             cn: [
14549             {
14550                 tag: 'th',
14551                 colspan: '7',
14552                 cls: 'today'
14553             }
14554                     
14555             ]
14556         }
14557         ]
14558     },
14559     
14560     dates:{
14561         en: {
14562             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14563             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14564             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14565             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14566             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14567             today: "Today"
14568         }
14569     },
14570     
14571     modes: [
14572     {
14573         clsName: 'days',
14574         navFnc: 'Month',
14575         navStep: 1
14576     },
14577     {
14578         clsName: 'months',
14579         navFnc: 'FullYear',
14580         navStep: 1
14581     },
14582     {
14583         clsName: 'years',
14584         navFnc: 'FullYear',
14585         navStep: 10
14586     }]
14587 });
14588
14589 Roo.apply(Roo.bootstrap.DateField,  {
14590   
14591     template : {
14592         tag: 'div',
14593         cls: 'datepicker dropdown-menu',
14594         cn: [
14595         {
14596             tag: 'div',
14597             cls: 'datepicker-days',
14598             cn: [
14599             {
14600                 tag: 'table',
14601                 cls: 'table-condensed',
14602                 cn:[
14603                 Roo.bootstrap.DateField.head,
14604                 {
14605                     tag: 'tbody'
14606                 },
14607                 Roo.bootstrap.DateField.footer
14608                 ]
14609             }
14610             ]
14611         },
14612         {
14613             tag: 'div',
14614             cls: 'datepicker-months',
14615             cn: [
14616             {
14617                 tag: 'table',
14618                 cls: 'table-condensed',
14619                 cn:[
14620                 Roo.bootstrap.DateField.head,
14621                 Roo.bootstrap.DateField.content,
14622                 Roo.bootstrap.DateField.footer
14623                 ]
14624             }
14625             ]
14626         },
14627         {
14628             tag: 'div',
14629             cls: 'datepicker-years',
14630             cn: [
14631             {
14632                 tag: 'table',
14633                 cls: 'table-condensed',
14634                 cn:[
14635                 Roo.bootstrap.DateField.head,
14636                 Roo.bootstrap.DateField.content,
14637                 Roo.bootstrap.DateField.footer
14638                 ]
14639             }
14640             ]
14641         }
14642         ]
14643     }
14644 });
14645
14646  
14647
14648  /*
14649  * - LGPL
14650  *
14651  * TimeField
14652  * 
14653  */
14654
14655 /**
14656  * @class Roo.bootstrap.TimeField
14657  * @extends Roo.bootstrap.Input
14658  * Bootstrap DateField class
14659  * 
14660  * 
14661  * @constructor
14662  * Create a new TimeField
14663  * @param {Object} config The config object
14664  */
14665
14666 Roo.bootstrap.TimeField = function(config){
14667     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14668     this.addEvents({
14669             /**
14670              * @event show
14671              * Fires when this field show.
14672              * @param {Roo.bootstrap.DateField} this
14673              * @param {Mixed} date The date value
14674              */
14675             show : true,
14676             /**
14677              * @event show
14678              * Fires when this field hide.
14679              * @param {Roo.bootstrap.DateField} this
14680              * @param {Mixed} date The date value
14681              */
14682             hide : true,
14683             /**
14684              * @event select
14685              * Fires when select a date.
14686              * @param {Roo.bootstrap.DateField} this
14687              * @param {Mixed} date The date value
14688              */
14689             select : true
14690         });
14691 };
14692
14693 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
14694     
14695     /**
14696      * @cfg {String} format
14697      * The default time format string which can be overriden for localization support.  The format must be
14698      * valid according to {@link Date#parseDate} (defaults to 'H:i').
14699      */
14700     format : "H:i",
14701        
14702     onRender: function(ct, position)
14703     {
14704         
14705         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14706                 
14707         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14708         
14709         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14710         
14711         this.pop = this.picker().select('>.datepicker-time',true).first();
14712         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block' 
14713         
14714         this.picker().on('mousedown', this.onMousedown, this);
14715         this.picker().on('click', this.onClick, this);
14716         
14717         this.picker().addClass('datepicker-dropdown');
14718     
14719         this.fillTime();
14720         this.update();
14721             
14722         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14723         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14724         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14725         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14726         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14727         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14728
14729     },
14730     
14731     fireKey: function(e){
14732         if (!this.picker().isVisible()){
14733             if (e.keyCode == 27) // allow escape to hide and re-show picker
14734                 this.show();
14735             return;
14736         }
14737
14738         e.preventDefault();
14739         
14740         switch(e.keyCode){
14741             case 27: // escape
14742                 this.hide();
14743                 break;
14744             case 37: // left
14745             case 39: // right
14746                 this.onTogglePeriod();
14747                 break;
14748             case 38: // up
14749                 this.onIncrementMinutes();
14750                 break;
14751             case 40: // down
14752                 this.onDecrementMinutes();
14753                 break;
14754             case 13: // enter
14755             case 9: // tab
14756                 this.setTime();
14757                 break;
14758         }
14759     },
14760     
14761     onClick: function(e) {
14762         e.stopPropagation();
14763         e.preventDefault();
14764     },
14765     
14766     picker : function()
14767     {
14768         return this.el.select('.datepicker', true).first();
14769     },
14770     
14771     fillTime: function()
14772     {    
14773         var time = this.pop.select('tbody', true).first();
14774         
14775         time.dom.innerHTML = '';
14776         
14777         time.createChild({
14778             tag: 'tr',
14779             cn: [
14780                 {
14781                     tag: 'td',
14782                     cn: [
14783                         {
14784                             tag: 'a',
14785                             href: '#',
14786                             cls: 'btn',
14787                             cn: [
14788                                 {
14789                                     tag: 'span',
14790                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
14791                                 }
14792                             ]
14793                         } 
14794                     ]
14795                 },
14796                 {
14797                     tag: 'td',
14798                     cls: 'separator'
14799                 },
14800                 {
14801                     tag: 'td',
14802                     cn: [
14803                         {
14804                             tag: 'a',
14805                             href: '#',
14806                             cls: 'btn',
14807                             cn: [
14808                                 {
14809                                     tag: 'span',
14810                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
14811                                 }
14812                             ]
14813                         }
14814                     ]
14815                 },
14816                 {
14817                     tag: 'td',
14818                     cls: 'separator'
14819                 }
14820             ]
14821         });
14822         
14823         time.createChild({
14824             tag: 'tr',
14825             cn: [
14826                 {
14827                     tag: 'td',
14828                     cn: [
14829                         {
14830                             tag: 'span',
14831                             cls: 'timepicker-hour',
14832                             html: '00'
14833                         }  
14834                     ]
14835                 },
14836                 {
14837                     tag: 'td',
14838                     cls: 'separator',
14839                     html: ':'
14840                 },
14841                 {
14842                     tag: 'td',
14843                     cn: [
14844                         {
14845                             tag: 'span',
14846                             cls: 'timepicker-minute',
14847                             html: '00'
14848                         }  
14849                     ]
14850                 },
14851                 {
14852                     tag: 'td',
14853                     cls: 'separator'
14854                 },
14855                 {
14856                     tag: 'td',
14857                     cn: [
14858                         {
14859                             tag: 'button',
14860                             type: 'button',
14861                             cls: 'btn btn-primary period',
14862                             html: 'AM'
14863                             
14864                         }
14865                     ]
14866                 }
14867             ]
14868         });
14869         
14870         time.createChild({
14871             tag: 'tr',
14872             cn: [
14873                 {
14874                     tag: 'td',
14875                     cn: [
14876                         {
14877                             tag: 'a',
14878                             href: '#',
14879                             cls: 'btn',
14880                             cn: [
14881                                 {
14882                                     tag: 'span',
14883                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
14884                                 }
14885                             ]
14886                         }
14887                     ]
14888                 },
14889                 {
14890                     tag: 'td',
14891                     cls: 'separator'
14892                 },
14893                 {
14894                     tag: 'td',
14895                     cn: [
14896                         {
14897                             tag: 'a',
14898                             href: '#',
14899                             cls: 'btn',
14900                             cn: [
14901                                 {
14902                                     tag: 'span',
14903                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
14904                                 }
14905                             ]
14906                         }
14907                     ]
14908                 },
14909                 {
14910                     tag: 'td',
14911                     cls: 'separator'
14912                 }
14913             ]
14914         });
14915         
14916     },
14917     
14918     update: function()
14919     {
14920         
14921         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14922         
14923         this.fill();
14924     },
14925     
14926     fill: function() 
14927     {
14928         var hours = this.time.getHours();
14929         var minutes = this.time.getMinutes();
14930         var period = 'AM';
14931         
14932         if(hours > 11){
14933             period = 'PM';
14934         }
14935         
14936         if(hours == 0){
14937             hours = 12;
14938         }
14939         
14940         
14941         if(hours > 12){
14942             hours = hours - 12;
14943         }
14944         
14945         if(hours < 10){
14946             hours = '0' + hours;
14947         }
14948         
14949         if(minutes < 10){
14950             minutes = '0' + minutes;
14951         }
14952         
14953         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14954         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14955         this.pop.select('button', true).first().dom.innerHTML = period;
14956         
14957     },
14958     
14959     place: function()
14960     {   
14961         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14962         
14963         var cls = ['bottom'];
14964         
14965         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14966             cls.pop();
14967             cls.push('top');
14968         }
14969         
14970         cls.push('right');
14971         
14972         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14973             cls.pop();
14974             cls.push('left');
14975         }
14976         
14977         this.picker().addClass(cls.join('-'));
14978         
14979         var _this = this;
14980         
14981         Roo.each(cls, function(c){
14982             if(c == 'bottom'){
14983                 _this.picker().setTop(_this.inputEl().getHeight());
14984                 return;
14985             }
14986             if(c == 'top'){
14987                 _this.picker().setTop(0 - _this.picker().getHeight());
14988                 return;
14989             }
14990             
14991             if(c == 'left'){
14992                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14993                 return;
14994             }
14995             if(c == 'right'){
14996                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
14997                 return;
14998             }
14999         });
15000         
15001     },
15002   
15003     onFocus : function()
15004     {
15005         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15006         this.show();
15007     },
15008     
15009     onBlur : function()
15010     {
15011         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15012         this.hide();
15013     },
15014     
15015     show : function()
15016     {
15017         this.picker().show();
15018         this.pop.show();
15019         this.update();
15020         this.place();
15021         
15022         this.fireEvent('show', this, this.date);
15023     },
15024     
15025     hide : function()
15026     {
15027         this.picker().hide();
15028         this.pop.hide();
15029         
15030         this.fireEvent('hide', this, this.date);
15031     },
15032     
15033     setTime : function()
15034     {
15035         this.hide();
15036         this.setValue(this.time.format(this.format));
15037         
15038         this.fireEvent('select', this, this.date);
15039         
15040         
15041     },
15042     
15043     onMousedown: function(e){
15044         e.stopPropagation();
15045         e.preventDefault();
15046     },
15047     
15048     onIncrementHours: function()
15049     {
15050         Roo.log('onIncrementHours');
15051         this.time = this.time.add(Date.HOUR, 1);
15052         this.update();
15053         
15054     },
15055     
15056     onDecrementHours: function()
15057     {
15058         Roo.log('onDecrementHours');
15059         this.time = this.time.add(Date.HOUR, -1);
15060         this.update();
15061     },
15062     
15063     onIncrementMinutes: function()
15064     {
15065         Roo.log('onIncrementMinutes');
15066         this.time = this.time.add(Date.MINUTE, 1);
15067         this.update();
15068     },
15069     
15070     onDecrementMinutes: function()
15071     {
15072         Roo.log('onDecrementMinutes');
15073         this.time = this.time.add(Date.MINUTE, -1);
15074         this.update();
15075     },
15076     
15077     onTogglePeriod: function()
15078     {
15079         Roo.log('onTogglePeriod');
15080         this.time = this.time.add(Date.HOUR, 12);
15081         this.update();
15082     }
15083     
15084    
15085 });
15086
15087 Roo.apply(Roo.bootstrap.TimeField,  {
15088     
15089     content : {
15090         tag: 'tbody',
15091         cn: [
15092             {
15093                 tag: 'tr',
15094                 cn: [
15095                 {
15096                     tag: 'td',
15097                     colspan: '7'
15098                 }
15099                 ]
15100             }
15101         ]
15102     },
15103     
15104     footer : {
15105         tag: 'tfoot',
15106         cn: [
15107             {
15108                 tag: 'tr',
15109                 cn: [
15110                 {
15111                     tag: 'th',
15112                     colspan: '7',
15113                     cls: '',
15114                     cn: [
15115                         {
15116                             tag: 'button',
15117                             cls: 'btn btn-info ok',
15118                             html: 'OK'
15119                         }
15120                     ]
15121                 }
15122
15123                 ]
15124             }
15125         ]
15126     }
15127 });
15128
15129 Roo.apply(Roo.bootstrap.TimeField,  {
15130   
15131     template : {
15132         tag: 'div',
15133         cls: 'datepicker dropdown-menu',
15134         cn: [
15135             {
15136                 tag: 'div',
15137                 cls: 'datepicker-time',
15138                 cn: [
15139                 {
15140                     tag: 'table',
15141                     cls: 'table-condensed',
15142                     cn:[
15143                     Roo.bootstrap.TimeField.content,
15144                     Roo.bootstrap.TimeField.footer
15145                     ]
15146                 }
15147                 ]
15148             }
15149         ]
15150     }
15151 });
15152
15153  
15154
15155  /*
15156  * - LGPL
15157  *
15158  * CheckBox
15159  * 
15160  */
15161
15162 /**
15163  * @class Roo.bootstrap.CheckBox
15164  * @extends Roo.bootstrap.Input
15165  * Bootstrap CheckBox class
15166  * 
15167  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15168  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15169  * @cfg {String} boxLabel The text that appears beside the checkbox
15170  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15171  * @cfg {Boolean} checked initnal the element
15172  * 
15173  * 
15174  * @constructor
15175  * Create a new CheckBox
15176  * @param {Object} config The config object
15177  */
15178
15179 Roo.bootstrap.CheckBox = function(config){
15180     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15181    
15182         this.addEvents({
15183             /**
15184             * @event check
15185             * Fires when the element is checked or unchecked.
15186             * @param {Roo.bootstrap.CheckBox} this This input
15187             * @param {Boolean} checked The new checked value
15188             */
15189            check : true
15190         });
15191 };
15192
15193 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
15194     
15195     inputType: 'checkbox',
15196     inputValue: 1,
15197     valueOff: 0,
15198     boxLabel: false,
15199     checked: false,
15200     weight : false,
15201     
15202     getAutoCreate : function()
15203     {
15204         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15205         
15206         var id = Roo.id();
15207         
15208         var cfg = {};
15209         
15210         cfg.cls = 'form-group checkbox' //input-group
15211         
15212         
15213         
15214         
15215         var input =  {
15216             tag: 'input',
15217             id : id,
15218             type : this.inputType,
15219             value : (!this.checked) ? this.valueOff : this.inputValue,
15220             cls : 'roo-checkbox', //'form-box',
15221             placeholder : this.placeholder || ''
15222             
15223         };
15224         
15225         if (this.weight) { // Validity check?
15226             cfg.cls += " checkbox-" + this.weight;
15227         }
15228         
15229         if (this.disabled) {
15230             input.disabled=true;
15231         }
15232         
15233         if(this.checked){
15234             input.checked = this.checked;
15235         }
15236         
15237         if (this.name) {
15238             input.name = this.name;
15239         }
15240         
15241         if (this.size) {
15242             input.cls += ' input-' + this.size;
15243         }
15244         
15245         var settings=this;
15246         ['xs','sm','md','lg'].map(function(size){
15247             if (settings[size]) {
15248                 cfg.cls += ' col-' + size + '-' + settings[size];
15249             }
15250         });
15251         
15252        
15253         
15254         var inputblock = input;
15255         
15256         
15257         
15258         
15259         if (this.before || this.after) {
15260             
15261             inputblock = {
15262                 cls : 'input-group',
15263                 cn :  [] 
15264             };
15265             if (this.before) {
15266                 inputblock.cn.push({
15267                     tag :'span',
15268                     cls : 'input-group-addon',
15269                     html : this.before
15270                 });
15271             }
15272             inputblock.cn.push(input);
15273             if (this.after) {
15274                 inputblock.cn.push({
15275                     tag :'span',
15276                     cls : 'input-group-addon',
15277                     html : this.after
15278                 });
15279             }
15280             
15281         };
15282         
15283         if (align ==='left' && this.fieldLabel.length) {
15284                 Roo.log("left and has label");
15285                 cfg.cn = [
15286                     
15287                     {
15288                         tag: 'label',
15289                         'for' :  id,
15290                         cls : 'control-label col-md-' + this.labelWidth,
15291                         html : this.fieldLabel
15292                         
15293                     },
15294                     {
15295                         cls : "col-md-" + (12 - this.labelWidth), 
15296                         cn: [
15297                             inputblock
15298                         ]
15299                     }
15300                     
15301                 ];
15302         } else if ( this.fieldLabel.length) {
15303                 Roo.log(" label");
15304                 cfg.cn = [
15305                    
15306                     {
15307                         tag: this.boxLabel ? 'span' : 'label',
15308                         'for': id,
15309                         cls: 'control-label box-input-label',
15310                         //cls : 'input-group-addon',
15311                         html : this.fieldLabel
15312                         
15313                     },
15314                     
15315                     inputblock
15316                     
15317                 ];
15318
15319         } else {
15320             
15321                 Roo.log(" no label && no align");
15322                 cfg.cn = [  inputblock ] ;
15323                 
15324                 
15325         };
15326          if(this.boxLabel){
15327             cfg.cn.push( {
15328                 tag: 'label',
15329                 'for': id,
15330                 cls: 'box-label',
15331                 html: this.boxLabel
15332                 
15333             });
15334         }
15335         
15336         
15337        
15338         return cfg;
15339         
15340     },
15341     
15342     /**
15343      * return the real input element.
15344      */
15345     inputEl: function ()
15346     {
15347         return this.el.select('input.roo-checkbox',true).first();
15348     },
15349     
15350     label: function()
15351     {
15352         return this.el.select('label.control-label',true).first();
15353     },
15354     
15355     initEvents : function()
15356     {
15357 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15358         
15359         this.inputEl().on('click', this.onClick,  this);
15360         
15361     },
15362     
15363     onClick : function()
15364     {   
15365         this.setChecked(!this.checked);
15366     },
15367     
15368     setChecked : function(state,suppressEvent)
15369     {
15370         this.checked = state;
15371         
15372         this.inputEl().dom.checked = state;
15373         
15374         if(suppressEvent !== true){
15375             this.fireEvent('check', this, state);
15376         }
15377         
15378         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15379         
15380     },
15381     
15382     setValue : function(v,suppressEvent)
15383     {
15384         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15385     }
15386     
15387 });
15388
15389  
15390 /*
15391  * - LGPL
15392  *
15393  * Radio
15394  * 
15395  */
15396
15397 /**
15398  * @class Roo.bootstrap.Radio
15399  * @extends Roo.bootstrap.CheckBox
15400  * Bootstrap Radio class
15401
15402  * @constructor
15403  * Create a new Radio
15404  * @param {Object} config The config object
15405  */
15406
15407 Roo.bootstrap.Radio = function(config){
15408     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15409    
15410 };
15411
15412 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
15413     
15414     inputType: 'radio',
15415     inputValue: '',
15416     valueOff: '',
15417     
15418     getAutoCreate : function()
15419     {
15420         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15421         
15422         var id = Roo.id();
15423         
15424         var cfg = {};
15425         
15426         cfg.cls = 'form-group radio' //input-group
15427         
15428         var input =  {
15429             tag: 'input',
15430             id : id,
15431             type : this.inputType,
15432             value : (!this.checked) ? this.valueOff : this.inputValue,
15433             cls : 'roo-radio',
15434             placeholder : this.placeholder || ''
15435             
15436         };
15437           if (this.weight) { // Validity check?
15438             cfg.cls += " radio-" + this.weight;
15439         }
15440         if (this.disabled) {
15441             input.disabled=true;
15442         }
15443         
15444         if(this.checked){
15445             input.checked = this.checked;
15446         }
15447         
15448         if (this.name) {
15449             input.name = this.name;
15450         }
15451         
15452         if (this.size) {
15453             input.cls += ' input-' + this.size;
15454         }
15455         
15456         var settings=this;
15457         ['xs','sm','md','lg'].map(function(size){
15458             if (settings[size]) {
15459                 cfg.cls += ' col-' + size + '-' + settings[size];
15460             }
15461         });
15462         
15463         var inputblock = input;
15464         
15465         if (this.before || this.after) {
15466             
15467             inputblock = {
15468                 cls : 'input-group',
15469                 cn :  [] 
15470             };
15471             if (this.before) {
15472                 inputblock.cn.push({
15473                     tag :'span',
15474                     cls : 'input-group-addon',
15475                     html : this.before
15476                 });
15477             }
15478             inputblock.cn.push(input);
15479             if (this.after) {
15480                 inputblock.cn.push({
15481                     tag :'span',
15482                     cls : 'input-group-addon',
15483                     html : this.after
15484                 });
15485             }
15486             
15487         };
15488         
15489         if (align ==='left' && this.fieldLabel.length) {
15490                 Roo.log("left and has label");
15491                 cfg.cn = [
15492                     
15493                     {
15494                         tag: 'label',
15495                         'for' :  id,
15496                         cls : 'control-label col-md-' + this.labelWidth,
15497                         html : this.fieldLabel
15498                         
15499                     },
15500                     {
15501                         cls : "col-md-" + (12 - this.labelWidth), 
15502                         cn: [
15503                             inputblock
15504                         ]
15505                     }
15506                     
15507                 ];
15508         } else if ( this.fieldLabel.length) {
15509                 Roo.log(" label");
15510                  cfg.cn = [
15511                    
15512                     {
15513                         tag: 'label',
15514                         'for': id,
15515                         cls: 'control-label box-input-label',
15516                         //cls : 'input-group-addon',
15517                         html : this.fieldLabel
15518                         
15519                     },
15520                     
15521                     inputblock
15522                     
15523                 ];
15524
15525         } else {
15526             
15527                    Roo.log(" no label && no align");
15528                 cfg.cn = [
15529                     
15530                         inputblock
15531                     
15532                 ];
15533                 
15534                 
15535         };
15536         
15537         if(this.boxLabel){
15538             cfg.cn.push({
15539                 tag: 'label',
15540                 'for': id,
15541                 cls: 'box-label',
15542                 html: this.boxLabel
15543             })
15544         }
15545         
15546         return cfg;
15547         
15548     },
15549     inputEl: function ()
15550     {
15551         return this.el.select('input.roo-radio',true).first();
15552     },
15553     onClick : function()
15554     {   
15555         this.setChecked(true);
15556     },
15557     
15558     setChecked : function(state,suppressEvent)
15559     {
15560         if(state){
15561             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15562                 v.dom.checked = false;
15563             });
15564         }
15565         
15566         this.checked = state;
15567         this.inputEl().dom.checked = state;
15568         
15569         if(suppressEvent !== true){
15570             this.fireEvent('check', this, state);
15571         }
15572         
15573         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15574         
15575     },
15576     
15577     getGroupValue : function()
15578     {
15579         var value = ''
15580         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15581             if(v.dom.checked == true){
15582                 value = v.dom.value;
15583             }
15584         });
15585         
15586         return value;
15587     },
15588     
15589     /**
15590      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
15591      * @return {Mixed} value The field value
15592      */
15593     getValue : function(){
15594         return this.getGroupValue();
15595     }
15596     
15597 });
15598
15599  
15600 //<script type="text/javascript">
15601
15602 /*
15603  * Based  Ext JS Library 1.1.1
15604  * Copyright(c) 2006-2007, Ext JS, LLC.
15605  * LGPL
15606  *
15607  */
15608  
15609 /**
15610  * @class Roo.HtmlEditorCore
15611  * @extends Roo.Component
15612  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15613  *
15614  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15615  */
15616
15617 Roo.HtmlEditorCore = function(config){
15618     
15619     
15620     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15621     this.addEvents({
15622         /**
15623          * @event initialize
15624          * Fires when the editor is fully initialized (including the iframe)
15625          * @param {Roo.HtmlEditorCore} this
15626          */
15627         initialize: true,
15628         /**
15629          * @event activate
15630          * Fires when the editor is first receives the focus. Any insertion must wait
15631          * until after this event.
15632          * @param {Roo.HtmlEditorCore} this
15633          */
15634         activate: true,
15635          /**
15636          * @event beforesync
15637          * Fires before the textarea is updated with content from the editor iframe. Return false
15638          * to cancel the sync.
15639          * @param {Roo.HtmlEditorCore} this
15640          * @param {String} html
15641          */
15642         beforesync: true,
15643          /**
15644          * @event beforepush
15645          * Fires before the iframe editor is updated with content from the textarea. Return false
15646          * to cancel the push.
15647          * @param {Roo.HtmlEditorCore} this
15648          * @param {String} html
15649          */
15650         beforepush: true,
15651          /**
15652          * @event sync
15653          * Fires when the textarea is updated with content from the editor iframe.
15654          * @param {Roo.HtmlEditorCore} this
15655          * @param {String} html
15656          */
15657         sync: true,
15658          /**
15659          * @event push
15660          * Fires when the iframe editor is updated with content from the textarea.
15661          * @param {Roo.HtmlEditorCore} this
15662          * @param {String} html
15663          */
15664         push: true,
15665         
15666         /**
15667          * @event editorevent
15668          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15669          * @param {Roo.HtmlEditorCore} this
15670          */
15671         editorevent: true
15672     });
15673      
15674 };
15675
15676
15677 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
15678
15679
15680      /**
15681      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
15682      */
15683     
15684     owner : false,
15685     
15686      /**
15687      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
15688      *                        Roo.resizable.
15689      */
15690     resizable : false,
15691      /**
15692      * @cfg {Number} height (in pixels)
15693      */   
15694     height: 300,
15695    /**
15696      * @cfg {Number} width (in pixels)
15697      */   
15698     width: 500,
15699     
15700     /**
15701      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15702      * 
15703      */
15704     stylesheets: false,
15705     
15706     // id of frame..
15707     frameId: false,
15708     
15709     // private properties
15710     validationEvent : false,
15711     deferHeight: true,
15712     initialized : false,
15713     activated : false,
15714     sourceEditMode : false,
15715     onFocus : Roo.emptyFn,
15716     iframePad:3,
15717     hideMode:'offsets',
15718     
15719     clearUp: true,
15720     
15721      
15722     
15723
15724     /**
15725      * Protected method that will not generally be called directly. It
15726      * is called when the editor initializes the iframe with HTML contents. Override this method if you
15727      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15728      */
15729     getDocMarkup : function(){
15730         // body styles..
15731         var st = '';
15732         Roo.log(this.stylesheets);
15733         
15734         // inherit styels from page...?? 
15735         if (this.stylesheets === false) {
15736             
15737             Roo.get(document.head).select('style').each(function(node) {
15738                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15739             });
15740             
15741             Roo.get(document.head).select('link').each(function(node) { 
15742                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15743             });
15744             
15745         } else if (!this.stylesheets.length) {
15746                 // simple..
15747                 st = '<style type="text/css">' +
15748                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15749                    '</style>';
15750         } else {
15751             Roo.each(this.stylesheets, function(s) {
15752                 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15753             });
15754             
15755         }
15756         
15757         st +=  '<style type="text/css">' +
15758             'IMG { cursor: pointer } ' +
15759         '</style>';
15760
15761         
15762         return '<html><head>' + st  +
15763             //<style type="text/css">' +
15764             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15765             //'</style>' +
15766             ' </head><body class="roo-htmleditor-body"></body></html>';
15767     },
15768
15769     // private
15770     onRender : function(ct, position)
15771     {
15772         var _t = this;
15773         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15774         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15775         
15776         
15777         this.el.dom.style.border = '0 none';
15778         this.el.dom.setAttribute('tabIndex', -1);
15779         this.el.addClass('x-hidden hide');
15780         
15781         
15782         
15783         if(Roo.isIE){ // fix IE 1px bogus margin
15784             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15785         }
15786        
15787         
15788         this.frameId = Roo.id();
15789         
15790          
15791         
15792         var iframe = this.owner.wrap.createChild({
15793             tag: 'iframe',
15794             cls: 'form-control', // bootstrap..
15795             id: this.frameId,
15796             name: this.frameId,
15797             frameBorder : 'no',
15798             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
15799         }, this.el
15800         );
15801         
15802         
15803         this.iframe = iframe.dom;
15804
15805          this.assignDocWin();
15806         
15807         this.doc.designMode = 'on';
15808        
15809         this.doc.open();
15810         this.doc.write(this.getDocMarkup());
15811         this.doc.close();
15812
15813         
15814         var task = { // must defer to wait for browser to be ready
15815             run : function(){
15816                 //console.log("run task?" + this.doc.readyState);
15817                 this.assignDocWin();
15818                 if(this.doc.body || this.doc.readyState == 'complete'){
15819                     try {
15820                         this.doc.designMode="on";
15821                     } catch (e) {
15822                         return;
15823                     }
15824                     Roo.TaskMgr.stop(task);
15825                     this.initEditor.defer(10, this);
15826                 }
15827             },
15828             interval : 10,
15829             duration: 10000,
15830             scope: this
15831         };
15832         Roo.TaskMgr.start(task);
15833
15834         
15835          
15836     },
15837
15838     // private
15839     onResize : function(w, h)
15840     {
15841          Roo.log('resize: ' +w + ',' + h );
15842         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15843         if(!this.iframe){
15844             return;
15845         }
15846         if(typeof w == 'number'){
15847             
15848             this.iframe.style.width = w + 'px';
15849         }
15850         if(typeof h == 'number'){
15851             
15852             this.iframe.style.height = h + 'px';
15853             if(this.doc){
15854                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15855             }
15856         }
15857         
15858     },
15859
15860     /**
15861      * Toggles the editor between standard and source edit mode.
15862      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15863      */
15864     toggleSourceEdit : function(sourceEditMode){
15865         
15866         this.sourceEditMode = sourceEditMode === true;
15867         
15868         if(this.sourceEditMode){
15869  
15870             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
15871             
15872         }else{
15873             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15874             //this.iframe.className = '';
15875             this.deferFocus();
15876         }
15877         //this.setSize(this.owner.wrap.getSize());
15878         //this.fireEvent('editmodechange', this, this.sourceEditMode);
15879     },
15880
15881     
15882   
15883
15884     /**
15885      * Protected method that will not generally be called directly. If you need/want
15886      * custom HTML cleanup, this is the method you should override.
15887      * @param {String} html The HTML to be cleaned
15888      * return {String} The cleaned HTML
15889      */
15890     cleanHtml : function(html){
15891         html = String(html);
15892         if(html.length > 5){
15893             if(Roo.isSafari){ // strip safari nonsense
15894                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15895             }
15896         }
15897         if(html == '&nbsp;'){
15898             html = '';
15899         }
15900         return html;
15901     },
15902
15903     /**
15904      * HTML Editor -> Textarea
15905      * Protected method that will not generally be called directly. Syncs the contents
15906      * of the editor iframe with the textarea.
15907      */
15908     syncValue : function(){
15909         if(this.initialized){
15910             var bd = (this.doc.body || this.doc.documentElement);
15911             //this.cleanUpPaste(); -- this is done else where and causes havoc..
15912             var html = bd.innerHTML;
15913             if(Roo.isSafari){
15914                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15915                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15916                 if(m && m[1]){
15917                     html = '<div style="'+m[0]+'">' + html + '</div>';
15918                 }
15919             }
15920             html = this.cleanHtml(html);
15921             // fix up the special chars.. normaly like back quotes in word...
15922             // however we do not want to do this with chinese..
15923             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15924                 var cc = b.charCodeAt();
15925                 if (
15926                     (cc >= 0x4E00 && cc < 0xA000 ) ||
15927                     (cc >= 0x3400 && cc < 0x4E00 ) ||
15928                     (cc >= 0xf900 && cc < 0xfb00 )
15929                 ) {
15930                         return b;
15931                 }
15932                 return "&#"+cc+";" 
15933             });
15934             if(this.owner.fireEvent('beforesync', this, html) !== false){
15935                 this.el.dom.value = html;
15936                 this.owner.fireEvent('sync', this, html);
15937             }
15938         }
15939     },
15940
15941     /**
15942      * Protected method that will not generally be called directly. Pushes the value of the textarea
15943      * into the iframe editor.
15944      */
15945     pushValue : function(){
15946         if(this.initialized){
15947             var v = this.el.dom.value.trim();
15948             
15949 //            if(v.length < 1){
15950 //                v = '&#160;';
15951 //            }
15952             
15953             if(this.owner.fireEvent('beforepush', this, v) !== false){
15954                 var d = (this.doc.body || this.doc.documentElement);
15955                 d.innerHTML = v;
15956                 this.cleanUpPaste();
15957                 this.el.dom.value = d.innerHTML;
15958                 this.owner.fireEvent('push', this, v);
15959             }
15960         }
15961     },
15962
15963     // private
15964     deferFocus : function(){
15965         this.focus.defer(10, this);
15966     },
15967
15968     // doc'ed in Field
15969     focus : function(){
15970         if(this.win && !this.sourceEditMode){
15971             this.win.focus();
15972         }else{
15973             this.el.focus();
15974         }
15975     },
15976     
15977     assignDocWin: function()
15978     {
15979         var iframe = this.iframe;
15980         
15981          if(Roo.isIE){
15982             this.doc = iframe.contentWindow.document;
15983             this.win = iframe.contentWindow;
15984         } else {
15985             if (!Roo.get(this.frameId)) {
15986                 return;
15987             }
15988             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15989             this.win = Roo.get(this.frameId).dom.contentWindow;
15990         }
15991     },
15992     
15993     // private
15994     initEditor : function(){
15995         //console.log("INIT EDITOR");
15996         this.assignDocWin();
15997         
15998         
15999         
16000         this.doc.designMode="on";
16001         this.doc.open();
16002         this.doc.write(this.getDocMarkup());
16003         this.doc.close();
16004         
16005         var dbody = (this.doc.body || this.doc.documentElement);
16006         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16007         // this copies styles from the containing element into thsi one..
16008         // not sure why we need all of this..
16009         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16010         
16011         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16012         //ss['background-attachment'] = 'fixed'; // w3c
16013         dbody.bgProperties = 'fixed'; // ie
16014         //Roo.DomHelper.applyStyles(dbody, ss);
16015         Roo.EventManager.on(this.doc, {
16016             //'mousedown': this.onEditorEvent,
16017             'mouseup': this.onEditorEvent,
16018             'dblclick': this.onEditorEvent,
16019             'click': this.onEditorEvent,
16020             'keyup': this.onEditorEvent,
16021             buffer:100,
16022             scope: this
16023         });
16024         if(Roo.isGecko){
16025             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16026         }
16027         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16028             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16029         }
16030         this.initialized = true;
16031
16032         this.owner.fireEvent('initialize', this);
16033         this.pushValue();
16034     },
16035
16036     // private
16037     onDestroy : function(){
16038         
16039         
16040         
16041         if(this.rendered){
16042             
16043             //for (var i =0; i < this.toolbars.length;i++) {
16044             //    // fixme - ask toolbars for heights?
16045             //    this.toolbars[i].onDestroy();
16046            // }
16047             
16048             //this.wrap.dom.innerHTML = '';
16049             //this.wrap.remove();
16050         }
16051     },
16052
16053     // private
16054     onFirstFocus : function(){
16055         
16056         this.assignDocWin();
16057         
16058         
16059         this.activated = true;
16060          
16061     
16062         if(Roo.isGecko){ // prevent silly gecko errors
16063             this.win.focus();
16064             var s = this.win.getSelection();
16065             if(!s.focusNode || s.focusNode.nodeType != 3){
16066                 var r = s.getRangeAt(0);
16067                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16068                 r.collapse(true);
16069                 this.deferFocus();
16070             }
16071             try{
16072                 this.execCmd('useCSS', true);
16073                 this.execCmd('styleWithCSS', false);
16074             }catch(e){}
16075         }
16076         this.owner.fireEvent('activate', this);
16077     },
16078
16079     // private
16080     adjustFont: function(btn){
16081         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16082         //if(Roo.isSafari){ // safari
16083         //    adjust *= 2;
16084        // }
16085         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16086         if(Roo.isSafari){ // safari
16087             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16088             v =  (v < 10) ? 10 : v;
16089             v =  (v > 48) ? 48 : v;
16090             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16091             
16092         }
16093         
16094         
16095         v = Math.max(1, v+adjust);
16096         
16097         this.execCmd('FontSize', v  );
16098     },
16099
16100     onEditorEvent : function(e){
16101         this.owner.fireEvent('editorevent', this, e);
16102       //  this.updateToolbar();
16103         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16104     },
16105
16106     insertTag : function(tg)
16107     {
16108         // could be a bit smarter... -> wrap the current selected tRoo..
16109         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16110             
16111             range = this.createRange(this.getSelection());
16112             var wrappingNode = this.doc.createElement(tg.toLowerCase());
16113             wrappingNode.appendChild(range.extractContents());
16114             range.insertNode(wrappingNode);
16115
16116             return;
16117             
16118             
16119             
16120         }
16121         this.execCmd("formatblock",   tg);
16122         
16123     },
16124     
16125     insertText : function(txt)
16126     {
16127         
16128         
16129         var range = this.createRange();
16130         range.deleteContents();
16131                //alert(Sender.getAttribute('label'));
16132                
16133         range.insertNode(this.doc.createTextNode(txt));
16134     } ,
16135     
16136      
16137
16138     /**
16139      * Executes a Midas editor command on the editor document and performs necessary focus and
16140      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16141      * @param {String} cmd The Midas command
16142      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16143      */
16144     relayCmd : function(cmd, value){
16145         this.win.focus();
16146         this.execCmd(cmd, value);
16147         this.owner.fireEvent('editorevent', this);
16148         //this.updateToolbar();
16149         this.owner.deferFocus();
16150     },
16151
16152     /**
16153      * Executes a Midas editor command directly on the editor document.
16154      * For visual commands, you should use {@link #relayCmd} instead.
16155      * <b>This should only be called after the editor is initialized.</b>
16156      * @param {String} cmd The Midas command
16157      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16158      */
16159     execCmd : function(cmd, value){
16160         this.doc.execCommand(cmd, false, value === undefined ? null : value);
16161         this.syncValue();
16162     },
16163  
16164  
16165    
16166     /**
16167      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16168      * to insert tRoo.
16169      * @param {String} text | dom node.. 
16170      */
16171     insertAtCursor : function(text)
16172     {
16173         
16174         
16175         
16176         if(!this.activated){
16177             return;
16178         }
16179         /*
16180         if(Roo.isIE){
16181             this.win.focus();
16182             var r = this.doc.selection.createRange();
16183             if(r){
16184                 r.collapse(true);
16185                 r.pasteHTML(text);
16186                 this.syncValue();
16187                 this.deferFocus();
16188             
16189             }
16190             return;
16191         }
16192         */
16193         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16194             this.win.focus();
16195             
16196             
16197             // from jquery ui (MIT licenced)
16198             var range, node;
16199             var win = this.win;
16200             
16201             if (win.getSelection && win.getSelection().getRangeAt) {
16202                 range = win.getSelection().getRangeAt(0);
16203                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16204                 range.insertNode(node);
16205             } else if (win.document.selection && win.document.selection.createRange) {
16206                 // no firefox support
16207                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16208                 win.document.selection.createRange().pasteHTML(txt);
16209             } else {
16210                 // no firefox support
16211                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16212                 this.execCmd('InsertHTML', txt);
16213             } 
16214             
16215             this.syncValue();
16216             
16217             this.deferFocus();
16218         }
16219     },
16220  // private
16221     mozKeyPress : function(e){
16222         if(e.ctrlKey){
16223             var c = e.getCharCode(), cmd;
16224           
16225             if(c > 0){
16226                 c = String.fromCharCode(c).toLowerCase();
16227                 switch(c){
16228                     case 'b':
16229                         cmd = 'bold';
16230                         break;
16231                     case 'i':
16232                         cmd = 'italic';
16233                         break;
16234                     
16235                     case 'u':
16236                         cmd = 'underline';
16237                         break;
16238                     
16239                     case 'v':
16240                         this.cleanUpPaste.defer(100, this);
16241                         return;
16242                         
16243                 }
16244                 if(cmd){
16245                     this.win.focus();
16246                     this.execCmd(cmd);
16247                     this.deferFocus();
16248                     e.preventDefault();
16249                 }
16250                 
16251             }
16252         }
16253     },
16254
16255     // private
16256     fixKeys : function(){ // load time branching for fastest keydown performance
16257         if(Roo.isIE){
16258             return function(e){
16259                 var k = e.getKey(), r;
16260                 if(k == e.TAB){
16261                     e.stopEvent();
16262                     r = this.doc.selection.createRange();
16263                     if(r){
16264                         r.collapse(true);
16265                         r.pasteHTML('&#160;&#160;&#160;&#160;');
16266                         this.deferFocus();
16267                     }
16268                     return;
16269                 }
16270                 
16271                 if(k == e.ENTER){
16272                     r = this.doc.selection.createRange();
16273                     if(r){
16274                         var target = r.parentElement();
16275                         if(!target || target.tagName.toLowerCase() != 'li'){
16276                             e.stopEvent();
16277                             r.pasteHTML('<br />');
16278                             r.collapse(false);
16279                             r.select();
16280                         }
16281                     }
16282                 }
16283                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16284                     this.cleanUpPaste.defer(100, this);
16285                     return;
16286                 }
16287                 
16288                 
16289             };
16290         }else if(Roo.isOpera){
16291             return function(e){
16292                 var k = e.getKey();
16293                 if(k == e.TAB){
16294                     e.stopEvent();
16295                     this.win.focus();
16296                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
16297                     this.deferFocus();
16298                 }
16299                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16300                     this.cleanUpPaste.defer(100, this);
16301                     return;
16302                 }
16303                 
16304             };
16305         }else if(Roo.isSafari){
16306             return function(e){
16307                 var k = e.getKey();
16308                 
16309                 if(k == e.TAB){
16310                     e.stopEvent();
16311                     this.execCmd('InsertText','\t');
16312                     this.deferFocus();
16313                     return;
16314                 }
16315                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16316                     this.cleanUpPaste.defer(100, this);
16317                     return;
16318                 }
16319                 
16320              };
16321         }
16322     }(),
16323     
16324     getAllAncestors: function()
16325     {
16326         var p = this.getSelectedNode();
16327         var a = [];
16328         if (!p) {
16329             a.push(p); // push blank onto stack..
16330             p = this.getParentElement();
16331         }
16332         
16333         
16334         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16335             a.push(p);
16336             p = p.parentNode;
16337         }
16338         a.push(this.doc.body);
16339         return a;
16340     },
16341     lastSel : false,
16342     lastSelNode : false,
16343     
16344     
16345     getSelection : function() 
16346     {
16347         this.assignDocWin();
16348         return Roo.isIE ? this.doc.selection : this.win.getSelection();
16349     },
16350     
16351     getSelectedNode: function() 
16352     {
16353         // this may only work on Gecko!!!
16354         
16355         // should we cache this!!!!
16356         
16357         
16358         
16359          
16360         var range = this.createRange(this.getSelection()).cloneRange();
16361         
16362         if (Roo.isIE) {
16363             var parent = range.parentElement();
16364             while (true) {
16365                 var testRange = range.duplicate();
16366                 testRange.moveToElementText(parent);
16367                 if (testRange.inRange(range)) {
16368                     break;
16369                 }
16370                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16371                     break;
16372                 }
16373                 parent = parent.parentElement;
16374             }
16375             return parent;
16376         }
16377         
16378         // is ancestor a text element.
16379         var ac =  range.commonAncestorContainer;
16380         if (ac.nodeType == 3) {
16381             ac = ac.parentNode;
16382         }
16383         
16384         var ar = ac.childNodes;
16385          
16386         var nodes = [];
16387         var other_nodes = [];
16388         var has_other_nodes = false;
16389         for (var i=0;i<ar.length;i++) {
16390             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
16391                 continue;
16392             }
16393             // fullly contained node.
16394             
16395             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16396                 nodes.push(ar[i]);
16397                 continue;
16398             }
16399             
16400             // probably selected..
16401             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16402                 other_nodes.push(ar[i]);
16403                 continue;
16404             }
16405             // outer..
16406             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
16407                 continue;
16408             }
16409             
16410             
16411             has_other_nodes = true;
16412         }
16413         if (!nodes.length && other_nodes.length) {
16414             nodes= other_nodes;
16415         }
16416         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16417             return false;
16418         }
16419         
16420         return nodes[0];
16421     },
16422     createRange: function(sel)
16423     {
16424         // this has strange effects when using with 
16425         // top toolbar - not sure if it's a great idea.
16426         //this.editor.contentWindow.focus();
16427         if (typeof sel != "undefined") {
16428             try {
16429                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16430             } catch(e) {
16431                 return this.doc.createRange();
16432             }
16433         } else {
16434             return this.doc.createRange();
16435         }
16436     },
16437     getParentElement: function()
16438     {
16439         
16440         this.assignDocWin();
16441         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16442         
16443         var range = this.createRange(sel);
16444          
16445         try {
16446             var p = range.commonAncestorContainer;
16447             while (p.nodeType == 3) { // text node
16448                 p = p.parentNode;
16449             }
16450             return p;
16451         } catch (e) {
16452             return null;
16453         }
16454     
16455     },
16456     /***
16457      *
16458      * Range intersection.. the hard stuff...
16459      *  '-1' = before
16460      *  '0' = hits..
16461      *  '1' = after.
16462      *         [ -- selected range --- ]
16463      *   [fail]                        [fail]
16464      *
16465      *    basically..
16466      *      if end is before start or  hits it. fail.
16467      *      if start is after end or hits it fail.
16468      *
16469      *   if either hits (but other is outside. - then it's not 
16470      *   
16471      *    
16472      **/
16473     
16474     
16475     // @see http://www.thismuchiknow.co.uk/?p=64.
16476     rangeIntersectsNode : function(range, node)
16477     {
16478         var nodeRange = node.ownerDocument.createRange();
16479         try {
16480             nodeRange.selectNode(node);
16481         } catch (e) {
16482             nodeRange.selectNodeContents(node);
16483         }
16484     
16485         var rangeStartRange = range.cloneRange();
16486         rangeStartRange.collapse(true);
16487     
16488         var rangeEndRange = range.cloneRange();
16489         rangeEndRange.collapse(false);
16490     
16491         var nodeStartRange = nodeRange.cloneRange();
16492         nodeStartRange.collapse(true);
16493     
16494         var nodeEndRange = nodeRange.cloneRange();
16495         nodeEndRange.collapse(false);
16496     
16497         return rangeStartRange.compareBoundaryPoints(
16498                  Range.START_TO_START, nodeEndRange) == -1 &&
16499                rangeEndRange.compareBoundaryPoints(
16500                  Range.START_TO_START, nodeStartRange) == 1;
16501         
16502          
16503     },
16504     rangeCompareNode : function(range, node)
16505     {
16506         var nodeRange = node.ownerDocument.createRange();
16507         try {
16508             nodeRange.selectNode(node);
16509         } catch (e) {
16510             nodeRange.selectNodeContents(node);
16511         }
16512         
16513         
16514         range.collapse(true);
16515     
16516         nodeRange.collapse(true);
16517      
16518         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16519         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
16520          
16521         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16522         
16523         var nodeIsBefore   =  ss == 1;
16524         var nodeIsAfter    = ee == -1;
16525         
16526         if (nodeIsBefore && nodeIsAfter)
16527             return 0; // outer
16528         if (!nodeIsBefore && nodeIsAfter)
16529             return 1; //right trailed.
16530         
16531         if (nodeIsBefore && !nodeIsAfter)
16532             return 2;  // left trailed.
16533         // fully contined.
16534         return 3;
16535     },
16536
16537     // private? - in a new class?
16538     cleanUpPaste :  function()
16539     {
16540         // cleans up the whole document..
16541         Roo.log('cleanuppaste');
16542         
16543         this.cleanUpChildren(this.doc.body);
16544         var clean = this.cleanWordChars(this.doc.body.innerHTML);
16545         if (clean != this.doc.body.innerHTML) {
16546             this.doc.body.innerHTML = clean;
16547         }
16548         
16549     },
16550     
16551     cleanWordChars : function(input) {// change the chars to hex code
16552         var he = Roo.HtmlEditorCore;
16553         
16554         var output = input;
16555         Roo.each(he.swapCodes, function(sw) { 
16556             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16557             
16558             output = output.replace(swapper, sw[1]);
16559         });
16560         
16561         return output;
16562     },
16563     
16564     
16565     cleanUpChildren : function (n)
16566     {
16567         if (!n.childNodes.length) {
16568             return;
16569         }
16570         for (var i = n.childNodes.length-1; i > -1 ; i--) {
16571            this.cleanUpChild(n.childNodes[i]);
16572         }
16573     },
16574     
16575     
16576         
16577     
16578     cleanUpChild : function (node)
16579     {
16580         var ed = this;
16581         //console.log(node);
16582         if (node.nodeName == "#text") {
16583             // clean up silly Windows -- stuff?
16584             return; 
16585         }
16586         if (node.nodeName == "#comment") {
16587             node.parentNode.removeChild(node);
16588             // clean up silly Windows -- stuff?
16589             return; 
16590         }
16591         
16592         if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16593             // remove node.
16594             node.parentNode.removeChild(node);
16595             return;
16596             
16597         }
16598         
16599         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16600         
16601         // remove <a name=....> as rendering on yahoo mailer is borked with this.
16602         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16603         
16604         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16605         //    remove_keep_children = true;
16606         //}
16607         
16608         if (remove_keep_children) {
16609             this.cleanUpChildren(node);
16610             // inserts everything just before this node...
16611             while (node.childNodes.length) {
16612                 var cn = node.childNodes[0];
16613                 node.removeChild(cn);
16614                 node.parentNode.insertBefore(cn, node);
16615             }
16616             node.parentNode.removeChild(node);
16617             return;
16618         }
16619         
16620         if (!node.attributes || !node.attributes.length) {
16621             this.cleanUpChildren(node);
16622             return;
16623         }
16624         
16625         function cleanAttr(n,v)
16626         {
16627             
16628             if (v.match(/^\./) || v.match(/^\//)) {
16629                 return;
16630             }
16631             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16632                 return;
16633             }
16634             if (v.match(/^#/)) {
16635                 return;
16636             }
16637 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16638             node.removeAttribute(n);
16639             
16640         }
16641         
16642         function cleanStyle(n,v)
16643         {
16644             if (v.match(/expression/)) { //XSS?? should we even bother..
16645                 node.removeAttribute(n);
16646                 return;
16647             }
16648             var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16649             var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16650             
16651             
16652             var parts = v.split(/;/);
16653             var clean = [];
16654             
16655             Roo.each(parts, function(p) {
16656                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16657                 if (!p.length) {
16658                     return true;
16659                 }
16660                 var l = p.split(':').shift().replace(/\s+/g,'');
16661                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16662                 
16663                 if ( cblack.indexOf(l) > -1) {
16664 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16665                     //node.removeAttribute(n);
16666                     return true;
16667                 }
16668                 //Roo.log()
16669                 // only allow 'c whitelisted system attributes'
16670                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
16671 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16672                     //node.removeAttribute(n);
16673                     return true;
16674                 }
16675                 
16676                 
16677                  
16678                 
16679                 clean.push(p);
16680                 return true;
16681             });
16682             if (clean.length) { 
16683                 node.setAttribute(n, clean.join(';'));
16684             } else {
16685                 node.removeAttribute(n);
16686             }
16687             
16688         }
16689         
16690         
16691         for (var i = node.attributes.length-1; i > -1 ; i--) {
16692             var a = node.attributes[i];
16693             //console.log(a);
16694             
16695             if (a.name.toLowerCase().substr(0,2)=='on')  {
16696                 node.removeAttribute(a.name);
16697                 continue;
16698             }
16699             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16700                 node.removeAttribute(a.name);
16701                 continue;
16702             }
16703             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16704                 cleanAttr(a.name,a.value); // fixme..
16705                 continue;
16706             }
16707             if (a.name == 'style') {
16708                 cleanStyle(a.name,a.value);
16709                 continue;
16710             }
16711             /// clean up MS crap..
16712             // tecnically this should be a list of valid class'es..
16713             
16714             
16715             if (a.name == 'class') {
16716                 if (a.value.match(/^Mso/)) {
16717                     node.className = '';
16718                 }
16719                 
16720                 if (a.value.match(/body/)) {
16721                     node.className = '';
16722                 }
16723                 continue;
16724             }
16725             
16726             // style cleanup!?
16727             // class cleanup?
16728             
16729         }
16730         
16731         
16732         this.cleanUpChildren(node);
16733         
16734         
16735     },
16736     /**
16737      * Clean up MS wordisms...
16738      */
16739     cleanWord : function(node)
16740     {
16741         var _t = this;
16742         var cleanWordChildren = function()
16743         {
16744             if (!node.childNodes.length) {
16745                 return;
16746             }
16747             for (var i = node.childNodes.length-1; i > -1 ; i--) {
16748                _t.cleanWord(node.childNodes[i]);
16749             }
16750         }
16751         
16752         
16753         if (!node) {
16754             this.cleanWord(this.doc.body);
16755             return;
16756         }
16757         if (node.nodeName == "#text") {
16758             // clean up silly Windows -- stuff?
16759             return; 
16760         }
16761         if (node.nodeName == "#comment") {
16762             node.parentNode.removeChild(node);
16763             // clean up silly Windows -- stuff?
16764             return; 
16765         }
16766         
16767         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16768             node.parentNode.removeChild(node);
16769             return;
16770         }
16771         
16772         // remove - but keep children..
16773         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16774             while (node.childNodes.length) {
16775                 var cn = node.childNodes[0];
16776                 node.removeChild(cn);
16777                 node.parentNode.insertBefore(cn, node);
16778             }
16779             node.parentNode.removeChild(node);
16780             cleanWordChildren();
16781             return;
16782         }
16783         // clean styles
16784         if (node.className.length) {
16785             
16786             var cn = node.className.split(/\W+/);
16787             var cna = [];
16788             Roo.each(cn, function(cls) {
16789                 if (cls.match(/Mso[a-zA-Z]+/)) {
16790                     return;
16791                 }
16792                 cna.push(cls);
16793             });
16794             node.className = cna.length ? cna.join(' ') : '';
16795             if (!cna.length) {
16796                 node.removeAttribute("class");
16797             }
16798         }
16799         
16800         if (node.hasAttribute("lang")) {
16801             node.removeAttribute("lang");
16802         }
16803         
16804         if (node.hasAttribute("style")) {
16805             
16806             var styles = node.getAttribute("style").split(";");
16807             var nstyle = [];
16808             Roo.each(styles, function(s) {
16809                 if (!s.match(/:/)) {
16810                     return;
16811                 }
16812                 var kv = s.split(":");
16813                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16814                     return;
16815                 }
16816                 // what ever is left... we allow.
16817                 nstyle.push(s);
16818             });
16819             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16820             if (!nstyle.length) {
16821                 node.removeAttribute('style');
16822             }
16823         }
16824         
16825         cleanWordChildren();
16826         
16827         
16828     },
16829     domToHTML : function(currentElement, depth, nopadtext) {
16830         
16831             depth = depth || 0;
16832             nopadtext = nopadtext || false;
16833         
16834             if (!currentElement) {
16835                 return this.domToHTML(this.doc.body);
16836             }
16837             
16838             //Roo.log(currentElement);
16839             var j;
16840             var allText = false;
16841             var nodeName = currentElement.nodeName;
16842             var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16843             
16844             if  (nodeName == '#text') {
16845                 return currentElement.nodeValue;
16846             }
16847             
16848             
16849             var ret = '';
16850             if (nodeName != 'BODY') {
16851                  
16852                 var i = 0;
16853                 // Prints the node tagName, such as <A>, <IMG>, etc
16854                 if (tagName) {
16855                     var attr = [];
16856                     for(i = 0; i < currentElement.attributes.length;i++) {
16857                         // quoting?
16858                         var aname = currentElement.attributes.item(i).name;
16859                         if (!currentElement.attributes.item(i).value.length) {
16860                             continue;
16861                         }
16862                         attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16863                     }
16864                     
16865                     ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16866                 } 
16867                 else {
16868                     
16869                     // eack
16870                 }
16871             } else {
16872                 tagName = false;
16873             }
16874             if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16875                 return ret;
16876             }
16877             if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16878                 nopadtext = true;
16879             }
16880             
16881             
16882             // Traverse the tree
16883             i = 0;
16884             var currentElementChild = currentElement.childNodes.item(i);
16885             var allText = true;
16886             var innerHTML  = '';
16887             lastnode = '';
16888             while (currentElementChild) {
16889                 // Formatting code (indent the tree so it looks nice on the screen)
16890                 var nopad = nopadtext;
16891                 if (lastnode == 'SPAN') {
16892                     nopad  = true;
16893                 }
16894                 // text
16895                 if  (currentElementChild.nodeName == '#text') {
16896                     var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16897                     if (!nopad && toadd.length > 80) {
16898                         innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
16899                     }
16900                     innerHTML  += toadd;
16901                     
16902                     i++;
16903                     currentElementChild = currentElement.childNodes.item(i);
16904                     lastNode = '';
16905                     continue;
16906                 }
16907                 allText = false;
16908                 
16909                 innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
16910                     
16911                 // Recursively traverse the tree structure of the child node
16912                 innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
16913                 lastnode = currentElementChild.nodeName;
16914                 i++;
16915                 currentElementChild=currentElement.childNodes.item(i);
16916             }
16917             
16918             ret += innerHTML;
16919             
16920             if (!allText) {
16921                     // The remaining code is mostly for formatting the tree
16922                 ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
16923             }
16924             
16925             
16926             if (tagName) {
16927                 ret+= "</"+tagName+">";
16928             }
16929             return ret;
16930             
16931         }
16932     
16933     // hide stuff that is not compatible
16934     /**
16935      * @event blur
16936      * @hide
16937      */
16938     /**
16939      * @event change
16940      * @hide
16941      */
16942     /**
16943      * @event focus
16944      * @hide
16945      */
16946     /**
16947      * @event specialkey
16948      * @hide
16949      */
16950     /**
16951      * @cfg {String} fieldClass @hide
16952      */
16953     /**
16954      * @cfg {String} focusClass @hide
16955      */
16956     /**
16957      * @cfg {String} autoCreate @hide
16958      */
16959     /**
16960      * @cfg {String} inputType @hide
16961      */
16962     /**
16963      * @cfg {String} invalidClass @hide
16964      */
16965     /**
16966      * @cfg {String} invalidText @hide
16967      */
16968     /**
16969      * @cfg {String} msgFx @hide
16970      */
16971     /**
16972      * @cfg {String} validateOnBlur @hide
16973      */
16974 });
16975
16976 Roo.HtmlEditorCore.white = [
16977         'area', 'br', 'img', 'input', 'hr', 'wbr',
16978         
16979        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
16980        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
16981        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
16982        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
16983        'table',   'ul',         'xmp', 
16984        
16985        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
16986       'thead',   'tr', 
16987      
16988       'dir', 'menu', 'ol', 'ul', 'dl',
16989        
16990       'embed',  'object'
16991 ];
16992
16993
16994 Roo.HtmlEditorCore.black = [
16995     //    'embed',  'object', // enable - backend responsiblity to clean thiese
16996         'applet', // 
16997         'base',   'basefont', 'bgsound', 'blink',  'body', 
16998         'frame',  'frameset', 'head',    'html',   'ilayer', 
16999         'iframe', 'layer',  'link',     'meta',    'object',   
17000         'script', 'style' ,'title',  'xml' // clean later..
17001 ];
17002 Roo.HtmlEditorCore.clean = [
17003     'script', 'style', 'title', 'xml'
17004 ];
17005 Roo.HtmlEditorCore.remove = [
17006     'font'
17007 ];
17008 // attributes..
17009
17010 Roo.HtmlEditorCore.ablack = [
17011     'on'
17012 ];
17013     
17014 Roo.HtmlEditorCore.aclean = [ 
17015     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
17016 ];
17017
17018 // protocols..
17019 Roo.HtmlEditorCore.pwhite= [
17020         'http',  'https',  'mailto'
17021 ];
17022
17023 // white listed style attributes.
17024 Roo.HtmlEditorCore.cwhite= [
17025       //  'text-align', /// default is to allow most things..
17026       
17027          
17028 //        'font-size'//??
17029 ];
17030
17031 // black listed style attributes.
17032 Roo.HtmlEditorCore.cblack= [
17033       //  'font-size' -- this can be set by the project 
17034 ];
17035
17036
17037 Roo.HtmlEditorCore.swapCodes   =[ 
17038     [    8211, "--" ], 
17039     [    8212, "--" ], 
17040     [    8216,  "'" ],  
17041     [    8217, "'" ],  
17042     [    8220, '"' ],  
17043     [    8221, '"' ],  
17044     [    8226, "*" ],  
17045     [    8230, "..." ]
17046 ]; 
17047
17048     /*
17049  * - LGPL
17050  *
17051  * HtmlEditor
17052  * 
17053  */
17054
17055 /**
17056  * @class Roo.bootstrap.HtmlEditor
17057  * @extends Roo.bootstrap.TextArea
17058  * Bootstrap HtmlEditor class
17059
17060  * @constructor
17061  * Create a new HtmlEditor
17062  * @param {Object} config The config object
17063  */
17064
17065 Roo.bootstrap.HtmlEditor = function(config){
17066     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17067     if (!this.toolbars) {
17068         this.toolbars = [];
17069     }
17070     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17071     this.addEvents({
17072             /**
17073              * @event initialize
17074              * Fires when the editor is fully initialized (including the iframe)
17075              * @param {HtmlEditor} this
17076              */
17077             initialize: true,
17078             /**
17079              * @event activate
17080              * Fires when the editor is first receives the focus. Any insertion must wait
17081              * until after this event.
17082              * @param {HtmlEditor} this
17083              */
17084             activate: true,
17085              /**
17086              * @event beforesync
17087              * Fires before the textarea is updated with content from the editor iframe. Return false
17088              * to cancel the sync.
17089              * @param {HtmlEditor} this
17090              * @param {String} html
17091              */
17092             beforesync: true,
17093              /**
17094              * @event beforepush
17095              * Fires before the iframe editor is updated with content from the textarea. Return false
17096              * to cancel the push.
17097              * @param {HtmlEditor} this
17098              * @param {String} html
17099              */
17100             beforepush: true,
17101              /**
17102              * @event sync
17103              * Fires when the textarea is updated with content from the editor iframe.
17104              * @param {HtmlEditor} this
17105              * @param {String} html
17106              */
17107             sync: true,
17108              /**
17109              * @event push
17110              * Fires when the iframe editor is updated with content from the textarea.
17111              * @param {HtmlEditor} this
17112              * @param {String} html
17113              */
17114             push: true,
17115              /**
17116              * @event editmodechange
17117              * Fires when the editor switches edit modes
17118              * @param {HtmlEditor} this
17119              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17120              */
17121             editmodechange: true,
17122             /**
17123              * @event editorevent
17124              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17125              * @param {HtmlEditor} this
17126              */
17127             editorevent: true,
17128             /**
17129              * @event firstfocus
17130              * Fires when on first focus - needed by toolbars..
17131              * @param {HtmlEditor} this
17132              */
17133             firstfocus: true,
17134             /**
17135              * @event autosave
17136              * Auto save the htmlEditor value as a file into Events
17137              * @param {HtmlEditor} this
17138              */
17139             autosave: true,
17140             /**
17141              * @event savedpreview
17142              * preview the saved version of htmlEditor
17143              * @param {HtmlEditor} this
17144              */
17145             savedpreview: true
17146         });
17147 };
17148
17149
17150 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
17151     
17152     
17153       /**
17154      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17155      */
17156     toolbars : false,
17157    
17158      /**
17159      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17160      *                        Roo.resizable.
17161      */
17162     resizable : false,
17163      /**
17164      * @cfg {Number} height (in pixels)
17165      */   
17166     height: 300,
17167    /**
17168      * @cfg {Number} width (in pixels)
17169      */   
17170     width: false,
17171     
17172     /**
17173      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17174      * 
17175      */
17176     stylesheets: false,
17177     
17178     // id of frame..
17179     frameId: false,
17180     
17181     // private properties
17182     validationEvent : false,
17183     deferHeight: true,
17184     initialized : false,
17185     activated : false,
17186     
17187     onFocus : Roo.emptyFn,
17188     iframePad:3,
17189     hideMode:'offsets',
17190     
17191     
17192     tbContainer : false,
17193     
17194     toolbarContainer :function() {
17195         return this.wrap.select('.x-html-editor-tb',true).first();
17196     },
17197
17198     /**
17199      * Protected method that will not generally be called directly. It
17200      * is called when the editor creates its toolbar. Override this method if you need to
17201      * add custom toolbar buttons.
17202      * @param {HtmlEditor} editor
17203      */
17204     createToolbar : function(){
17205         
17206         Roo.log("create toolbars");
17207         
17208         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17209         this.toolbars[0].render(this.toolbarContainer());
17210         
17211         return;
17212         
17213 //        if (!editor.toolbars || !editor.toolbars.length) {
17214 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17215 //        }
17216 //        
17217 //        for (var i =0 ; i < editor.toolbars.length;i++) {
17218 //            editor.toolbars[i] = Roo.factory(
17219 //                    typeof(editor.toolbars[i]) == 'string' ?
17220 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
17221 //                Roo.bootstrap.HtmlEditor);
17222 //            editor.toolbars[i].init(editor);
17223 //        }
17224     },
17225
17226      
17227     // private
17228     onRender : function(ct, position)
17229     {
17230        // Roo.log("Call onRender: " + this.xtype);
17231         var _t = this;
17232         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17233       
17234         this.wrap = this.inputEl().wrap({
17235             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17236         });
17237         
17238         this.editorcore.onRender(ct, position);
17239          
17240         if (this.resizable) {
17241             this.resizeEl = new Roo.Resizable(this.wrap, {
17242                 pinned : true,
17243                 wrap: true,
17244                 dynamic : true,
17245                 minHeight : this.height,
17246                 height: this.height,
17247                 handles : this.resizable,
17248                 width: this.width,
17249                 listeners : {
17250                     resize : function(r, w, h) {
17251                         _t.onResize(w,h); // -something
17252                     }
17253                 }
17254             });
17255             
17256         }
17257         this.createToolbar(this);
17258        
17259         
17260         if(!this.width && this.resizable){
17261             this.setSize(this.wrap.getSize());
17262         }
17263         if (this.resizeEl) {
17264             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17265             // should trigger onReize..
17266         }
17267         
17268     },
17269
17270     // private
17271     onResize : function(w, h)
17272     {
17273         Roo.log('resize: ' +w + ',' + h );
17274         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17275         var ew = false;
17276         var eh = false;
17277         
17278         if(this.inputEl() ){
17279             if(typeof w == 'number'){
17280                 var aw = w - this.wrap.getFrameWidth('lr');
17281                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17282                 ew = aw;
17283             }
17284             if(typeof h == 'number'){
17285                  var tbh = -11;  // fixme it needs to tool bar size!
17286                 for (var i =0; i < this.toolbars.length;i++) {
17287                     // fixme - ask toolbars for heights?
17288                     tbh += this.toolbars[i].el.getHeight();
17289                     //if (this.toolbars[i].footer) {
17290                     //    tbh += this.toolbars[i].footer.el.getHeight();
17291                     //}
17292                 }
17293               
17294                 
17295                 
17296                 
17297                 
17298                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17299                 ah -= 5; // knock a few pixes off for look..
17300                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17301                 var eh = ah;
17302             }
17303         }
17304         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17305         this.editorcore.onResize(ew,eh);
17306         
17307     },
17308
17309     /**
17310      * Toggles the editor between standard and source edit mode.
17311      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17312      */
17313     toggleSourceEdit : function(sourceEditMode)
17314     {
17315         this.editorcore.toggleSourceEdit(sourceEditMode);
17316         
17317         if(this.editorcore.sourceEditMode){
17318             Roo.log('editor - showing textarea');
17319             
17320 //            Roo.log('in');
17321 //            Roo.log(this.syncValue());
17322             this.syncValue();
17323             this.inputEl().removeClass(['hide', 'x-hidden']);
17324             this.inputEl().dom.removeAttribute('tabIndex');
17325             this.inputEl().focus();
17326         }else{
17327             Roo.log('editor - hiding textarea');
17328 //            Roo.log('out')
17329 //            Roo.log(this.pushValue()); 
17330             this.pushValue();
17331             
17332             this.inputEl().addClass(['hide', 'x-hidden']);
17333             this.inputEl().dom.setAttribute('tabIndex', -1);
17334             //this.deferFocus();
17335         }
17336          
17337         if(this.resizable){
17338             this.setSize(this.wrap.getSize());
17339         }
17340         
17341         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17342     },
17343  
17344     // private (for BoxComponent)
17345     adjustSize : Roo.BoxComponent.prototype.adjustSize,
17346
17347     // private (for BoxComponent)
17348     getResizeEl : function(){
17349         return this.wrap;
17350     },
17351
17352     // private (for BoxComponent)
17353     getPositionEl : function(){
17354         return this.wrap;
17355     },
17356
17357     // private
17358     initEvents : function(){
17359         this.originalValue = this.getValue();
17360     },
17361
17362 //    /**
17363 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17364 //     * @method
17365 //     */
17366 //    markInvalid : Roo.emptyFn,
17367 //    /**
17368 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17369 //     * @method
17370 //     */
17371 //    clearInvalid : Roo.emptyFn,
17372
17373     setValue : function(v){
17374         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17375         this.editorcore.pushValue();
17376     },
17377
17378      
17379     // private
17380     deferFocus : function(){
17381         this.focus.defer(10, this);
17382     },
17383
17384     // doc'ed in Field
17385     focus : function(){
17386         this.editorcore.focus();
17387         
17388     },
17389       
17390
17391     // private
17392     onDestroy : function(){
17393         
17394         
17395         
17396         if(this.rendered){
17397             
17398             for (var i =0; i < this.toolbars.length;i++) {
17399                 // fixme - ask toolbars for heights?
17400                 this.toolbars[i].onDestroy();
17401             }
17402             
17403             this.wrap.dom.innerHTML = '';
17404             this.wrap.remove();
17405         }
17406     },
17407
17408     // private
17409     onFirstFocus : function(){
17410         //Roo.log("onFirstFocus");
17411         this.editorcore.onFirstFocus();
17412          for (var i =0; i < this.toolbars.length;i++) {
17413             this.toolbars[i].onFirstFocus();
17414         }
17415         
17416     },
17417     
17418     // private
17419     syncValue : function()
17420     {   
17421         this.editorcore.syncValue();
17422     },
17423     
17424     pushValue : function()
17425     {   
17426         this.editorcore.pushValue();
17427     }
17428      
17429     
17430     // hide stuff that is not compatible
17431     /**
17432      * @event blur
17433      * @hide
17434      */
17435     /**
17436      * @event change
17437      * @hide
17438      */
17439     /**
17440      * @event focus
17441      * @hide
17442      */
17443     /**
17444      * @event specialkey
17445      * @hide
17446      */
17447     /**
17448      * @cfg {String} fieldClass @hide
17449      */
17450     /**
17451      * @cfg {String} focusClass @hide
17452      */
17453     /**
17454      * @cfg {String} autoCreate @hide
17455      */
17456     /**
17457      * @cfg {String} inputType @hide
17458      */
17459     /**
17460      * @cfg {String} invalidClass @hide
17461      */
17462     /**
17463      * @cfg {String} invalidText @hide
17464      */
17465     /**
17466      * @cfg {String} msgFx @hide
17467      */
17468     /**
17469      * @cfg {String} validateOnBlur @hide
17470      */
17471 });
17472  
17473     
17474    
17475    
17476    
17477       
17478 Roo.namespace('Roo.bootstrap.htmleditor');
17479 /**
17480  * @class Roo.bootstrap.HtmlEditorToolbar1
17481  * Basic Toolbar
17482  * 
17483  * Usage:
17484  *
17485  new Roo.bootstrap.HtmlEditor({
17486     ....
17487     toolbars : [
17488         new Roo.bootstrap.HtmlEditorToolbar1({
17489             disable : { fonts: 1 , format: 1, ..., ... , ...],
17490             btns : [ .... ]
17491         })
17492     }
17493      
17494  * 
17495  * @cfg {Object} disable List of elements to disable..
17496  * @cfg {Array} btns List of additional buttons.
17497  * 
17498  * 
17499  * NEEDS Extra CSS? 
17500  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17501  */
17502  
17503 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17504 {
17505     
17506     Roo.apply(this, config);
17507     
17508     // default disabled, based on 'good practice'..
17509     this.disable = this.disable || {};
17510     Roo.applyIf(this.disable, {
17511         fontSize : true,
17512         colors : true,
17513         specialElements : true
17514     });
17515     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17516     
17517     this.editor = config.editor;
17518     this.editorcore = config.editor.editorcore;
17519     
17520     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17521     
17522     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17523     // dont call parent... till later.
17524 }
17525 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
17526      
17527     bar : true,
17528     
17529     editor : false,
17530     editorcore : false,
17531     
17532     
17533     formats : [
17534         "p" ,  
17535         "h1","h2","h3","h4","h5","h6", 
17536         "pre", "code", 
17537         "abbr", "acronym", "address", "cite", "samp", "var",
17538         'div','span'
17539     ],
17540     
17541     onRender : function(ct, position)
17542     {
17543        // Roo.log("Call onRender: " + this.xtype);
17544         
17545        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17546        Roo.log(this.el);
17547        this.el.dom.style.marginBottom = '0';
17548        var _this = this;
17549        var editorcore = this.editorcore;
17550        var editor= this.editor;
17551        
17552        var children = [];
17553        var btn = function(id,cmd , toggle, handler){
17554        
17555             var  event = toggle ? 'toggle' : 'click';
17556        
17557             var a = {
17558                 size : 'sm',
17559                 xtype: 'Button',
17560                 xns: Roo.bootstrap,
17561                 glyphicon : id,
17562                 cmd : id || cmd,
17563                 enableToggle:toggle !== false,
17564                 //html : 'submit'
17565                 pressed : toggle ? false : null,
17566                 listeners : {}
17567             }
17568             a.listeners[toggle ? 'toggle' : 'click'] = function() {
17569                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
17570             }
17571             children.push(a);
17572             return a;
17573        }
17574         
17575         var style = {
17576                 xtype: 'Button',
17577                 size : 'sm',
17578                 xns: Roo.bootstrap,
17579                 glyphicon : 'font',
17580                 //html : 'submit'
17581                 menu : {
17582                     xtype: 'Menu',
17583                     xns: Roo.bootstrap,
17584                     items:  []
17585                 }
17586         };
17587         Roo.each(this.formats, function(f) {
17588             style.menu.items.push({
17589                 xtype :'MenuItem',
17590                 xns: Roo.bootstrap,
17591                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17592                 tagname : f,
17593                 listeners : {
17594                     click : function()
17595                     {
17596                         editorcore.insertTag(this.tagname);
17597                         editor.focus();
17598                     }
17599                 }
17600                 
17601             });
17602         });
17603          children.push(style);   
17604             
17605             
17606         btn('bold',false,true);
17607         btn('italic',false,true);
17608         btn('align-left', 'justifyleft',true);
17609         btn('align-center', 'justifycenter',true);
17610         btn('align-right' , 'justifyright',true);
17611         btn('link', false, false, function(btn) {
17612             //Roo.log("create link?");
17613             var url = prompt(this.createLinkText, this.defaultLinkValue);
17614             if(url && url != 'http:/'+'/'){
17615                 this.editorcore.relayCmd('createlink', url);
17616             }
17617         }),
17618         btn('list','insertunorderedlist',true);
17619         btn('pencil', false,true, function(btn){
17620                 Roo.log(this);
17621                 
17622                 this.toggleSourceEdit(btn.pressed);
17623         });
17624         /*
17625         var cog = {
17626                 xtype: 'Button',
17627                 size : 'sm',
17628                 xns: Roo.bootstrap,
17629                 glyphicon : 'cog',
17630                 //html : 'submit'
17631                 menu : {
17632                     xtype: 'Menu',
17633                     xns: Roo.bootstrap,
17634                     items:  []
17635                 }
17636         };
17637         
17638         cog.menu.items.push({
17639             xtype :'MenuItem',
17640             xns: Roo.bootstrap,
17641             html : Clean styles,
17642             tagname : f,
17643             listeners : {
17644                 click : function()
17645                 {
17646                     editorcore.insertTag(this.tagname);
17647                     editor.focus();
17648                 }
17649             }
17650             
17651         });
17652        */
17653         
17654          
17655        this.xtype = 'NavSimplebar';
17656         
17657         for(var i=0;i< children.length;i++) {
17658             
17659             this.buttons.add(this.addxtypeChild(children[i]));
17660             
17661         }
17662         
17663         editor.on('editorevent', this.updateToolbar, this);
17664     },
17665     onBtnClick : function(id)
17666     {
17667        this.editorcore.relayCmd(id);
17668        this.editorcore.focus();
17669     },
17670     
17671     /**
17672      * Protected method that will not generally be called directly. It triggers
17673      * a toolbar update by reading the markup state of the current selection in the editor.
17674      */
17675     updateToolbar: function(){
17676
17677         if(!this.editorcore.activated){
17678             this.editor.onFirstFocus(); // is this neeed?
17679             return;
17680         }
17681
17682         var btns = this.buttons; 
17683         var doc = this.editorcore.doc;
17684         btns.get('bold').setActive(doc.queryCommandState('bold'));
17685         btns.get('italic').setActive(doc.queryCommandState('italic'));
17686         //btns.get('underline').setActive(doc.queryCommandState('underline'));
17687         
17688         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17689         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17690         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17691         
17692         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17693         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17694          /*
17695         
17696         var ans = this.editorcore.getAllAncestors();
17697         if (this.formatCombo) {
17698             
17699             
17700             var store = this.formatCombo.store;
17701             this.formatCombo.setValue("");
17702             for (var i =0; i < ans.length;i++) {
17703                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17704                     // select it..
17705                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17706                     break;
17707                 }
17708             }
17709         }
17710         
17711         
17712         
17713         // hides menus... - so this cant be on a menu...
17714         Roo.bootstrap.MenuMgr.hideAll();
17715         */
17716         Roo.bootstrap.MenuMgr.hideAll();
17717         //this.editorsyncValue();
17718     },
17719     onFirstFocus: function() {
17720         this.buttons.each(function(item){
17721            item.enable();
17722         });
17723     },
17724     toggleSourceEdit : function(sourceEditMode){
17725         
17726           
17727         if(sourceEditMode){
17728             Roo.log("disabling buttons");
17729            this.buttons.each( function(item){
17730                 if(item.cmd != 'pencil'){
17731                     item.disable();
17732                 }
17733             });
17734           
17735         }else{
17736             Roo.log("enabling buttons");
17737             if(this.editorcore.initialized){
17738                 this.buttons.each( function(item){
17739                     item.enable();
17740                 });
17741             }
17742             
17743         }
17744         Roo.log("calling toggole on editor");
17745         // tell the editor that it's been pressed..
17746         this.editor.toggleSourceEdit(sourceEditMode);
17747        
17748     }
17749 });
17750
17751
17752
17753
17754
17755 /**
17756  * @class Roo.bootstrap.Table.AbstractSelectionModel
17757  * @extends Roo.util.Observable
17758  * Abstract base class for grid SelectionModels.  It provides the interface that should be
17759  * implemented by descendant classes.  This class should not be directly instantiated.
17760  * @constructor
17761  */
17762 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17763     this.locked = false;
17764     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17765 };
17766
17767
17768 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
17769     /** @ignore Called by the grid automatically. Do not call directly. */
17770     init : function(grid){
17771         this.grid = grid;
17772         this.initEvents();
17773     },
17774
17775     /**
17776      * Locks the selections.
17777      */
17778     lock : function(){
17779         this.locked = true;
17780     },
17781
17782     /**
17783      * Unlocks the selections.
17784      */
17785     unlock : function(){
17786         this.locked = false;
17787     },
17788
17789     /**
17790      * Returns true if the selections are locked.
17791      * @return {Boolean}
17792      */
17793     isLocked : function(){
17794         return this.locked;
17795     }
17796 });
17797 /**
17798  * @extends Roo.bootstrap.Table.AbstractSelectionModel
17799  * @class Roo.bootstrap.Table.RowSelectionModel
17800  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17801  * It supports multiple selections and keyboard selection/navigation. 
17802  * @constructor
17803  * @param {Object} config
17804  */
17805
17806 Roo.bootstrap.Table.RowSelectionModel = function(config){
17807     Roo.apply(this, config);
17808     this.selections = new Roo.util.MixedCollection(false, function(o){
17809         return o.id;
17810     });
17811
17812     this.last = false;
17813     this.lastActive = false;
17814
17815     this.addEvents({
17816         /**
17817              * @event selectionchange
17818              * Fires when the selection changes
17819              * @param {SelectionModel} this
17820              */
17821             "selectionchange" : true,
17822         /**
17823              * @event afterselectionchange
17824              * Fires after the selection changes (eg. by key press or clicking)
17825              * @param {SelectionModel} this
17826              */
17827             "afterselectionchange" : true,
17828         /**
17829              * @event beforerowselect
17830              * Fires when a row is selected being selected, return false to cancel.
17831              * @param {SelectionModel} this
17832              * @param {Number} rowIndex The selected index
17833              * @param {Boolean} keepExisting False if other selections will be cleared
17834              */
17835             "beforerowselect" : true,
17836         /**
17837              * @event rowselect
17838              * Fires when a row is selected.
17839              * @param {SelectionModel} this
17840              * @param {Number} rowIndex The selected index
17841              * @param {Roo.data.Record} r The record
17842              */
17843             "rowselect" : true,
17844         /**
17845              * @event rowdeselect
17846              * Fires when a row is deselected.
17847              * @param {SelectionModel} this
17848              * @param {Number} rowIndex The selected index
17849              */
17850         "rowdeselect" : true
17851     });
17852     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17853     this.locked = false;
17854 };
17855
17856 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
17857     /**
17858      * @cfg {Boolean} singleSelect
17859      * True to allow selection of only one row at a time (defaults to false)
17860      */
17861     singleSelect : false,
17862
17863     // private
17864     initEvents : function(){
17865
17866         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17867             this.grid.on("mousedown", this.handleMouseDown, this);
17868         }else{ // allow click to work like normal
17869             this.grid.on("rowclick", this.handleDragableRowClick, this);
17870         }
17871
17872         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17873             "up" : function(e){
17874                 if(!e.shiftKey){
17875                     this.selectPrevious(e.shiftKey);
17876                 }else if(this.last !== false && this.lastActive !== false){
17877                     var last = this.last;
17878                     this.selectRange(this.last,  this.lastActive-1);
17879                     this.grid.getView().focusRow(this.lastActive);
17880                     if(last !== false){
17881                         this.last = last;
17882                     }
17883                 }else{
17884                     this.selectFirstRow();
17885                 }
17886                 this.fireEvent("afterselectionchange", this);
17887             },
17888             "down" : function(e){
17889                 if(!e.shiftKey){
17890                     this.selectNext(e.shiftKey);
17891                 }else if(this.last !== false && this.lastActive !== false){
17892                     var last = this.last;
17893                     this.selectRange(this.last,  this.lastActive+1);
17894                     this.grid.getView().focusRow(this.lastActive);
17895                     if(last !== false){
17896                         this.last = last;
17897                     }
17898                 }else{
17899                     this.selectFirstRow();
17900                 }
17901                 this.fireEvent("afterselectionchange", this);
17902             },
17903             scope: this
17904         });
17905
17906         var view = this.grid.view;
17907         view.on("refresh", this.onRefresh, this);
17908         view.on("rowupdated", this.onRowUpdated, this);
17909         view.on("rowremoved", this.onRemove, this);
17910     },
17911
17912     // private
17913     onRefresh : function(){
17914         var ds = this.grid.dataSource, i, v = this.grid.view;
17915         var s = this.selections;
17916         s.each(function(r){
17917             if((i = ds.indexOfId(r.id)) != -1){
17918                 v.onRowSelect(i);
17919             }else{
17920                 s.remove(r);
17921             }
17922         });
17923     },
17924
17925     // private
17926     onRemove : function(v, index, r){
17927         this.selections.remove(r);
17928     },
17929
17930     // private
17931     onRowUpdated : function(v, index, r){
17932         if(this.isSelected(r)){
17933             v.onRowSelect(index);
17934         }
17935     },
17936
17937     /**
17938      * Select records.
17939      * @param {Array} records The records to select
17940      * @param {Boolean} keepExisting (optional) True to keep existing selections
17941      */
17942     selectRecords : function(records, keepExisting){
17943         if(!keepExisting){
17944             this.clearSelections();
17945         }
17946         var ds = this.grid.dataSource;
17947         for(var i = 0, len = records.length; i < len; i++){
17948             this.selectRow(ds.indexOf(records[i]), true);
17949         }
17950     },
17951
17952     /**
17953      * Gets the number of selected rows.
17954      * @return {Number}
17955      */
17956     getCount : function(){
17957         return this.selections.length;
17958     },
17959
17960     /**
17961      * Selects the first row in the grid.
17962      */
17963     selectFirstRow : function(){
17964         this.selectRow(0);
17965     },
17966
17967     /**
17968      * Select the last row.
17969      * @param {Boolean} keepExisting (optional) True to keep existing selections
17970      */
17971     selectLastRow : function(keepExisting){
17972         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17973     },
17974
17975     /**
17976      * Selects the row immediately following the last selected row.
17977      * @param {Boolean} keepExisting (optional) True to keep existing selections
17978      */
17979     selectNext : function(keepExisting){
17980         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17981             this.selectRow(this.last+1, keepExisting);
17982             this.grid.getView().focusRow(this.last);
17983         }
17984     },
17985
17986     /**
17987      * Selects the row that precedes the last selected row.
17988      * @param {Boolean} keepExisting (optional) True to keep existing selections
17989      */
17990     selectPrevious : function(keepExisting){
17991         if(this.last){
17992             this.selectRow(this.last-1, keepExisting);
17993             this.grid.getView().focusRow(this.last);
17994         }
17995     },
17996
17997     /**
17998      * Returns the selected records
17999      * @return {Array} Array of selected records
18000      */
18001     getSelections : function(){
18002         return [].concat(this.selections.items);
18003     },
18004
18005     /**
18006      * Returns the first selected record.
18007      * @return {Record}
18008      */
18009     getSelected : function(){
18010         return this.selections.itemAt(0);
18011     },
18012
18013
18014     /**
18015      * Clears all selections.
18016      */
18017     clearSelections : function(fast){
18018         if(this.locked) return;
18019         if(fast !== true){
18020             var ds = this.grid.dataSource;
18021             var s = this.selections;
18022             s.each(function(r){
18023                 this.deselectRow(ds.indexOfId(r.id));
18024             }, this);
18025             s.clear();
18026         }else{
18027             this.selections.clear();
18028         }
18029         this.last = false;
18030     },
18031
18032
18033     /**
18034      * Selects all rows.
18035      */
18036     selectAll : function(){
18037         if(this.locked) return;
18038         this.selections.clear();
18039         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18040             this.selectRow(i, true);
18041         }
18042     },
18043
18044     /**
18045      * Returns True if there is a selection.
18046      * @return {Boolean}
18047      */
18048     hasSelection : function(){
18049         return this.selections.length > 0;
18050     },
18051
18052     /**
18053      * Returns True if the specified row is selected.
18054      * @param {Number/Record} record The record or index of the record to check
18055      * @return {Boolean}
18056      */
18057     isSelected : function(index){
18058         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18059         return (r && this.selections.key(r.id) ? true : false);
18060     },
18061
18062     /**
18063      * Returns True if the specified record id is selected.
18064      * @param {String} id The id of record to check
18065      * @return {Boolean}
18066      */
18067     isIdSelected : function(id){
18068         return (this.selections.key(id) ? true : false);
18069     },
18070
18071     // private
18072     handleMouseDown : function(e, t){
18073         var view = this.grid.getView(), rowIndex;
18074         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18075             return;
18076         };
18077         if(e.shiftKey && this.last !== false){
18078             var last = this.last;
18079             this.selectRange(last, rowIndex, e.ctrlKey);
18080             this.last = last; // reset the last
18081             view.focusRow(rowIndex);
18082         }else{
18083             var isSelected = this.isSelected(rowIndex);
18084             if(e.button !== 0 && isSelected){
18085                 view.focusRow(rowIndex);
18086             }else if(e.ctrlKey && isSelected){
18087                 this.deselectRow(rowIndex);
18088             }else if(!isSelected){
18089                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18090                 view.focusRow(rowIndex);
18091             }
18092         }
18093         this.fireEvent("afterselectionchange", this);
18094     },
18095     // private
18096     handleDragableRowClick :  function(grid, rowIndex, e) 
18097     {
18098         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18099             this.selectRow(rowIndex, false);
18100             grid.view.focusRow(rowIndex);
18101              this.fireEvent("afterselectionchange", this);
18102         }
18103     },
18104     
18105     /**
18106      * Selects multiple rows.
18107      * @param {Array} rows Array of the indexes of the row to select
18108      * @param {Boolean} keepExisting (optional) True to keep existing selections
18109      */
18110     selectRows : function(rows, keepExisting){
18111         if(!keepExisting){
18112             this.clearSelections();
18113         }
18114         for(var i = 0, len = rows.length; i < len; i++){
18115             this.selectRow(rows[i], true);
18116         }
18117     },
18118
18119     /**
18120      * Selects a range of rows. All rows in between startRow and endRow are also selected.
18121      * @param {Number} startRow The index of the first row in the range
18122      * @param {Number} endRow The index of the last row in the range
18123      * @param {Boolean} keepExisting (optional) True to retain existing selections
18124      */
18125     selectRange : function(startRow, endRow, keepExisting){
18126         if(this.locked) return;
18127         if(!keepExisting){
18128             this.clearSelections();
18129         }
18130         if(startRow <= endRow){
18131             for(var i = startRow; i <= endRow; i++){
18132                 this.selectRow(i, true);
18133             }
18134         }else{
18135             for(var i = startRow; i >= endRow; i--){
18136                 this.selectRow(i, true);
18137             }
18138         }
18139     },
18140
18141     /**
18142      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18143      * @param {Number} startRow The index of the first row in the range
18144      * @param {Number} endRow The index of the last row in the range
18145      */
18146     deselectRange : function(startRow, endRow, preventViewNotify){
18147         if(this.locked) return;
18148         for(var i = startRow; i <= endRow; i++){
18149             this.deselectRow(i, preventViewNotify);
18150         }
18151     },
18152
18153     /**
18154      * Selects a row.
18155      * @param {Number} row The index of the row to select
18156      * @param {Boolean} keepExisting (optional) True to keep existing selections
18157      */
18158     selectRow : function(index, keepExisting, preventViewNotify){
18159         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18160         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18161             if(!keepExisting || this.singleSelect){
18162                 this.clearSelections();
18163             }
18164             var r = this.grid.dataSource.getAt(index);
18165             this.selections.add(r);
18166             this.last = this.lastActive = index;
18167             if(!preventViewNotify){
18168                 this.grid.getView().onRowSelect(index);
18169             }
18170             this.fireEvent("rowselect", this, index, r);
18171             this.fireEvent("selectionchange", this);
18172         }
18173     },
18174
18175     /**
18176      * Deselects a row.
18177      * @param {Number} row The index of the row to deselect
18178      */
18179     deselectRow : function(index, preventViewNotify){
18180         if(this.locked) return;
18181         if(this.last == index){
18182             this.last = false;
18183         }
18184         if(this.lastActive == index){
18185             this.lastActive = false;
18186         }
18187         var r = this.grid.dataSource.getAt(index);
18188         this.selections.remove(r);
18189         if(!preventViewNotify){
18190             this.grid.getView().onRowDeselect(index);
18191         }
18192         this.fireEvent("rowdeselect", this, index);
18193         this.fireEvent("selectionchange", this);
18194     },
18195
18196     // private
18197     restoreLast : function(){
18198         if(this._last){
18199             this.last = this._last;
18200         }
18201     },
18202
18203     // private
18204     acceptsNav : function(row, col, cm){
18205         return !cm.isHidden(col) && cm.isCellEditable(col, row);
18206     },
18207
18208     // private
18209     onEditorKey : function(field, e){
18210         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18211         if(k == e.TAB){
18212             e.stopEvent();
18213             ed.completeEdit();
18214             if(e.shiftKey){
18215                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18216             }else{
18217                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18218             }
18219         }else if(k == e.ENTER && !e.ctrlKey){
18220             e.stopEvent();
18221             ed.completeEdit();
18222             if(e.shiftKey){
18223                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18224             }else{
18225                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18226             }
18227         }else if(k == e.ESC){
18228             ed.cancelEdit();
18229         }
18230         if(newCell){
18231             g.startEditing(newCell[0], newCell[1]);
18232         }
18233     }
18234 });/*
18235  * Based on:
18236  * Ext JS Library 1.1.1
18237  * Copyright(c) 2006-2007, Ext JS, LLC.
18238  *
18239  * Originally Released Under LGPL - original licence link has changed is not relivant.
18240  *
18241  * Fork - LGPL
18242  * <script type="text/javascript">
18243  */
18244  
18245 /**
18246  * @class Roo.bootstrap.PagingToolbar
18247  * @extends Roo.Row
18248  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18249  * @constructor
18250  * Create a new PagingToolbar
18251  * @param {Object} config The config object
18252  */
18253 Roo.bootstrap.PagingToolbar = function(config)
18254 {
18255     // old args format still supported... - xtype is prefered..
18256         // created from xtype...
18257     var ds = config.dataSource;
18258     this.toolbarItems = [];
18259     if (config.items) {
18260         this.toolbarItems = config.items;
18261 //        config.items = [];
18262     }
18263     
18264     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18265     this.ds = ds;
18266     this.cursor = 0;
18267     if (ds) { 
18268         this.bind(ds);
18269     }
18270     
18271     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18272     
18273 };
18274
18275 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18276     /**
18277      * @cfg {Roo.data.Store} dataSource
18278      * The underlying data store providing the paged data
18279      */
18280     /**
18281      * @cfg {String/HTMLElement/Element} container
18282      * container The id or element that will contain the toolbar
18283      */
18284     /**
18285      * @cfg {Boolean} displayInfo
18286      * True to display the displayMsg (defaults to false)
18287      */
18288     /**
18289      * @cfg {Number} pageSize
18290      * The number of records to display per page (defaults to 20)
18291      */
18292     pageSize: 20,
18293     /**
18294      * @cfg {String} displayMsg
18295      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18296      */
18297     displayMsg : 'Displaying {0} - {1} of {2}',
18298     /**
18299      * @cfg {String} emptyMsg
18300      * The message to display when no records are found (defaults to "No data to display")
18301      */
18302     emptyMsg : 'No data to display',
18303     /**
18304      * Customizable piece of the default paging text (defaults to "Page")
18305      * @type String
18306      */
18307     beforePageText : "Page",
18308     /**
18309      * Customizable piece of the default paging text (defaults to "of %0")
18310      * @type String
18311      */
18312     afterPageText : "of {0}",
18313     /**
18314      * Customizable piece of the default paging text (defaults to "First Page")
18315      * @type String
18316      */
18317     firstText : "First Page",
18318     /**
18319      * Customizable piece of the default paging text (defaults to "Previous Page")
18320      * @type String
18321      */
18322     prevText : "Previous Page",
18323     /**
18324      * Customizable piece of the default paging text (defaults to "Next Page")
18325      * @type String
18326      */
18327     nextText : "Next Page",
18328     /**
18329      * Customizable piece of the default paging text (defaults to "Last Page")
18330      * @type String
18331      */
18332     lastText : "Last Page",
18333     /**
18334      * Customizable piece of the default paging text (defaults to "Refresh")
18335      * @type String
18336      */
18337     refreshText : "Refresh",
18338
18339     buttons : false,
18340     // private
18341     onRender : function(ct, position) 
18342     {
18343         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18344         this.navgroup.parentId = this.id;
18345         this.navgroup.onRender(this.el, null);
18346         // add the buttons to the navgroup
18347         
18348         if(this.displayInfo){
18349             Roo.log(this.el.select('ul.navbar-nav',true).first());
18350             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18351             this.displayEl = this.el.select('.x-paging-info', true).first();
18352 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18353 //            this.displayEl = navel.el.select('span',true).first();
18354         }
18355         
18356         var _this = this;
18357         
18358         if(this.buttons){
18359             Roo.each(_this.buttons, function(e){
18360                Roo.factory(e).onRender(_this.el, null);
18361             });
18362         }
18363             
18364         Roo.each(_this.toolbarItems, function(e) {
18365             _this.navgroup.addItem(e);
18366         });
18367         
18368         this.first = this.navgroup.addItem({
18369             tooltip: this.firstText,
18370             cls: "prev",
18371             icon : 'fa fa-backward',
18372             disabled: true,
18373             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18374         });
18375         
18376         this.prev =  this.navgroup.addItem({
18377             tooltip: this.prevText,
18378             cls: "prev",
18379             icon : 'fa fa-step-backward',
18380             disabled: true,
18381             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
18382         });
18383     //this.addSeparator();
18384         
18385         
18386         var field = this.navgroup.addItem( {
18387             tagtype : 'span',
18388             cls : 'x-paging-position',
18389             
18390             html : this.beforePageText  +
18391                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18392                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
18393          } ); //?? escaped?
18394         
18395         this.field = field.el.select('input', true).first();
18396         this.field.on("keydown", this.onPagingKeydown, this);
18397         this.field.on("focus", function(){this.dom.select();});
18398     
18399     
18400         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
18401         //this.field.setHeight(18);
18402         //this.addSeparator();
18403         this.next = this.navgroup.addItem({
18404             tooltip: this.nextText,
18405             cls: "next",
18406             html : ' <i class="fa fa-step-forward">',
18407             disabled: true,
18408             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
18409         });
18410         this.last = this.navgroup.addItem({
18411             tooltip: this.lastText,
18412             icon : 'fa fa-forward',
18413             cls: "next",
18414             disabled: true,
18415             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
18416         });
18417     //this.addSeparator();
18418         this.loading = this.navgroup.addItem({
18419             tooltip: this.refreshText,
18420             icon: 'fa fa-refresh',
18421             
18422             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18423         });
18424
18425     },
18426
18427     // private
18428     updateInfo : function(){
18429         if(this.displayEl){
18430             var count = this.ds.getCount();
18431             var msg = count == 0 ?
18432                 this.emptyMsg :
18433                 String.format(
18434                     this.displayMsg,
18435                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
18436                 );
18437             this.displayEl.update(msg);
18438         }
18439     },
18440
18441     // private
18442     onLoad : function(ds, r, o){
18443        this.cursor = o.params ? o.params.start : 0;
18444        var d = this.getPageData(),
18445             ap = d.activePage,
18446             ps = d.pages;
18447         
18448        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18449        this.field.dom.value = ap;
18450        this.first.setDisabled(ap == 1);
18451        this.prev.setDisabled(ap == 1);
18452        this.next.setDisabled(ap == ps);
18453        this.last.setDisabled(ap == ps);
18454        this.loading.enable();
18455        this.updateInfo();
18456     },
18457
18458     // private
18459     getPageData : function(){
18460         var total = this.ds.getTotalCount();
18461         return {
18462             total : total,
18463             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18464             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18465         };
18466     },
18467
18468     // private
18469     onLoadError : function(){
18470         this.loading.enable();
18471     },
18472
18473     // private
18474     onPagingKeydown : function(e){
18475         var k = e.getKey();
18476         var d = this.getPageData();
18477         if(k == e.RETURN){
18478             var v = this.field.dom.value, pageNum;
18479             if(!v || isNaN(pageNum = parseInt(v, 10))){
18480                 this.field.dom.value = d.activePage;
18481                 return;
18482             }
18483             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18484             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18485             e.stopEvent();
18486         }
18487         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))
18488         {
18489           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18490           this.field.dom.value = pageNum;
18491           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18492           e.stopEvent();
18493         }
18494         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18495         {
18496           var v = this.field.dom.value, pageNum; 
18497           var increment = (e.shiftKey) ? 10 : 1;
18498           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18499             increment *= -1;
18500           if(!v || isNaN(pageNum = parseInt(v, 10))) {
18501             this.field.dom.value = d.activePage;
18502             return;
18503           }
18504           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18505           {
18506             this.field.dom.value = parseInt(v, 10) + increment;
18507             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18508             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18509           }
18510           e.stopEvent();
18511         }
18512     },
18513
18514     // private
18515     beforeLoad : function(){
18516         if(this.loading){
18517             this.loading.disable();
18518         }
18519     },
18520
18521     // private
18522     onClick : function(which){
18523         var ds = this.ds;
18524         if (!ds) {
18525             return;
18526         }
18527         switch(which){
18528             case "first":
18529                 ds.load({params:{start: 0, limit: this.pageSize}});
18530             break;
18531             case "prev":
18532                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18533             break;
18534             case "next":
18535                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18536             break;
18537             case "last":
18538                 var total = ds.getTotalCount();
18539                 var extra = total % this.pageSize;
18540                 var lastStart = extra ? (total - extra) : total-this.pageSize;
18541                 ds.load({params:{start: lastStart, limit: this.pageSize}});
18542             break;
18543             case "refresh":
18544                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18545             break;
18546         }
18547     },
18548
18549     /**
18550      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18551      * @param {Roo.data.Store} store The data store to unbind
18552      */
18553     unbind : function(ds){
18554         ds.un("beforeload", this.beforeLoad, this);
18555         ds.un("load", this.onLoad, this);
18556         ds.un("loadexception", this.onLoadError, this);
18557         ds.un("remove", this.updateInfo, this);
18558         ds.un("add", this.updateInfo, this);
18559         this.ds = undefined;
18560     },
18561
18562     /**
18563      * Binds the paging toolbar to the specified {@link Roo.data.Store}
18564      * @param {Roo.data.Store} store The data store to bind
18565      */
18566     bind : function(ds){
18567         ds.on("beforeload", this.beforeLoad, this);
18568         ds.on("load", this.onLoad, this);
18569         ds.on("loadexception", this.onLoadError, this);
18570         ds.on("remove", this.updateInfo, this);
18571         ds.on("add", this.updateInfo, this);
18572         this.ds = ds;
18573     }
18574 });/*
18575  * - LGPL
18576  *
18577  * element
18578  * 
18579  */
18580
18581 /**
18582  * @class Roo.bootstrap.MessageBar
18583  * @extends Roo.bootstrap.Component
18584  * Bootstrap MessageBar class
18585  * @cfg {String} html contents of the MessageBar
18586  * @cfg {String} weight (info | success | warning | danger) default info
18587  * @cfg {String} beforeClass insert the bar before the given class
18588  * @cfg {Boolean} closable (true | false) default false
18589  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18590  * 
18591  * @constructor
18592  * Create a new Element
18593  * @param {Object} config The config object
18594  */
18595
18596 Roo.bootstrap.MessageBar = function(config){
18597     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18598 };
18599
18600 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
18601     
18602     html: '',
18603     weight: 'info',
18604     closable: false,
18605     fixed: false,
18606     beforeClass: 'bootstrap-sticky-wrap',
18607     
18608     getAutoCreate : function(){
18609         
18610         var cfg = {
18611             tag: 'div',
18612             cls: 'alert alert-dismissable alert-' + this.weight,
18613             cn: [
18614                 {
18615                     tag: 'span',
18616                     cls: 'message',
18617                     html: this.html || ''
18618                 }
18619             ]
18620         }
18621         
18622         if(this.fixed){
18623             cfg.cls += ' alert-messages-fixed';
18624         }
18625         
18626         if(this.closable){
18627             cfg.cn.push({
18628                 tag: 'button',
18629                 cls: 'close',
18630                 html: 'x'
18631             });
18632         }
18633         
18634         return cfg;
18635     },
18636     
18637     onRender : function(ct, position)
18638     {
18639         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18640         
18641         if(!this.el){
18642             var cfg = Roo.apply({},  this.getAutoCreate());
18643             cfg.id = Roo.id();
18644             
18645             if (this.cls) {
18646                 cfg.cls += ' ' + this.cls;
18647             }
18648             if (this.style) {
18649                 cfg.style = this.style;
18650             }
18651             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18652             
18653             this.el.setVisibilityMode(Roo.Element.DISPLAY);
18654         }
18655         
18656         this.el.select('>button.close').on('click', this.hide, this);
18657         
18658     },
18659     
18660     show : function()
18661     {
18662         if (!this.rendered) {
18663             this.render();
18664         }
18665         
18666         this.el.show();
18667         
18668         this.fireEvent('show', this);
18669         
18670     },
18671     
18672     hide : function()
18673     {
18674         if (!this.rendered) {
18675             this.render();
18676         }
18677         
18678         this.el.hide();
18679         
18680         this.fireEvent('hide', this);
18681     },
18682     
18683     update : function()
18684     {
18685 //        var e = this.el.dom.firstChild;
18686 //        
18687 //        if(this.closable){
18688 //            e = e.nextSibling;
18689 //        }
18690 //        
18691 //        e.data = this.html || '';
18692
18693         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18694     }
18695    
18696 });
18697
18698  
18699
18700      /*
18701  * - LGPL
18702  *
18703  * Graph
18704  * 
18705  */
18706
18707
18708 /**
18709  * @class Roo.bootstrap.Graph
18710  * @extends Roo.bootstrap.Component
18711  * Bootstrap Graph class
18712 > Prameters
18713  -sm {number} sm 4
18714  -md {number} md 5
18715  @cfg {String} graphtype  bar | vbar | pie
18716  @cfg {number} g_x coodinator | centre x (pie)
18717  @cfg {number} g_y coodinator | centre y (pie)
18718  @cfg {number} g_r radius (pie)
18719  @cfg {number} g_height height of the chart (respected by all elements in the set)
18720  @cfg {number} g_width width of the chart (respected by all elements in the set)
18721  @cfg {Object} title The title of the chart
18722     
18723  -{Array}  values
18724  -opts (object) options for the chart 
18725      o {
18726      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18727      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18728      o vgutter (number)
18729      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.
18730      o stacked (boolean) whether or not to tread values as in a stacked bar chart
18731      o to
18732      o stretch (boolean)
18733      o }
18734  -opts (object) options for the pie
18735      o{
18736      o cut
18737      o startAngle (number)
18738      o endAngle (number)
18739      } 
18740  *
18741  * @constructor
18742  * Create a new Input
18743  * @param {Object} config The config object
18744  */
18745
18746 Roo.bootstrap.Graph = function(config){
18747     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18748     
18749     this.addEvents({
18750         // img events
18751         /**
18752          * @event click
18753          * The img click event for the img.
18754          * @param {Roo.EventObject} e
18755          */
18756         "click" : true
18757     });
18758 };
18759
18760 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
18761     
18762     sm: 4,
18763     md: 5,
18764     graphtype: 'bar',
18765     g_height: 250,
18766     g_width: 400,
18767     g_x: 50,
18768     g_y: 50,
18769     g_r: 30,
18770     opts:{
18771         //g_colors: this.colors,
18772         g_type: 'soft',
18773         g_gutter: '20%'
18774
18775     },
18776     title : false,
18777
18778     getAutoCreate : function(){
18779         
18780         var cfg = {
18781             tag: 'div',
18782             html : null
18783         }
18784         
18785         
18786         return  cfg;
18787     },
18788
18789     onRender : function(ct,position){
18790         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18791         this.raphael = Raphael(this.el.dom);
18792         
18793                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18794                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18795                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18796                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18797                 /*
18798                 r.text(160, 10, "Single Series Chart").attr(txtattr);
18799                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18800                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18801                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18802                 
18803                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18804                 r.barchart(330, 10, 300, 220, data1);
18805                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18806                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18807                 */
18808                 
18809                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18810                 // r.barchart(30, 30, 560, 250,  xdata, {
18811                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18812                 //     axis : "0 0 1 1",
18813                 //     axisxlabels :  xdata
18814                 //     //yvalues : cols,
18815                    
18816                 // });
18817 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18818 //        
18819 //        this.load(null,xdata,{
18820 //                axis : "0 0 1 1",
18821 //                axisxlabels :  xdata
18822 //                });
18823
18824     },
18825
18826     load : function(graphtype,xdata,opts){
18827         this.raphael.clear();
18828         if(!graphtype) {
18829             graphtype = this.graphtype;
18830         }
18831         if(!opts){
18832             opts = this.opts;
18833         }
18834         var r = this.raphael,
18835             fin = function () {
18836                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18837             },
18838             fout = function () {
18839                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18840             },
18841             pfin = function() {
18842                 this.sector.stop();
18843                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18844
18845                 if (this.label) {
18846                     this.label[0].stop();
18847                     this.label[0].attr({ r: 7.5 });
18848                     this.label[1].attr({ "font-weight": 800 });
18849                 }
18850             },
18851             pfout = function() {
18852                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18853
18854                 if (this.label) {
18855                     this.label[0].animate({ r: 5 }, 500, "bounce");
18856                     this.label[1].attr({ "font-weight": 400 });
18857                 }
18858             };
18859
18860         switch(graphtype){
18861             case 'bar':
18862                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18863                 break;
18864             case 'hbar':
18865                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18866                 break;
18867             case 'pie':
18868 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
18869 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18870 //            
18871                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18872                 
18873                 break;
18874
18875         }
18876         
18877         if(this.title){
18878             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18879         }
18880         
18881     },
18882     
18883     setTitle: function(o)
18884     {
18885         this.title = o;
18886     },
18887     
18888     initEvents: function() {
18889         
18890         if(!this.href){
18891             this.el.on('click', this.onClick, this);
18892         }
18893     },
18894     
18895     onClick : function(e)
18896     {
18897         Roo.log('img onclick');
18898         this.fireEvent('click', this, e);
18899     }
18900    
18901 });
18902
18903  
18904 /*
18905  * - LGPL
18906  *
18907  * numberBox
18908  * 
18909  */
18910 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18911
18912 /**
18913  * @class Roo.bootstrap.dash.NumberBox
18914  * @extends Roo.bootstrap.Component
18915  * Bootstrap NumberBox class
18916  * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18917  * @cfg {String} headline Box headline
18918  * @cfg {String} content Box content
18919  * @cfg {String} icon Box icon
18920  * @cfg {String} footer Footer text
18921  * @cfg {String} fhref Footer href
18922  * 
18923  * @constructor
18924  * Create a new NumberBox
18925  * @param {Object} config The config object
18926  */
18927
18928
18929 Roo.bootstrap.dash.NumberBox = function(config){
18930     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18931     
18932 };
18933
18934 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
18935     
18936     bgcolor : 'aqua',
18937     headline : '',
18938     content : '',
18939     icon : '',
18940     footer : '',
18941     fhref : '',
18942     ficon : '',
18943     
18944     getAutoCreate : function(){
18945         
18946         var cfg = {
18947             tag : 'div',
18948             cls : 'small-box bg-' + this.bgcolor,
18949             cn : [
18950                 {
18951                     tag : 'div',
18952                     cls : 'inner',
18953                     cn :[
18954                         {
18955                             tag : 'h3',
18956                             cls : 'roo-headline',
18957                             html : this.headline
18958                         },
18959                         {
18960                             tag : 'p',
18961                             cls : 'roo-content',
18962                             html : this.content
18963                         }
18964                     ]
18965                 }
18966             ]
18967         }
18968         
18969         if(this.icon){
18970             cfg.cn.push({
18971                 tag : 'div',
18972                 cls : 'icon',
18973                 cn :[
18974                     {
18975                         tag : 'i',
18976                         cls : 'ion ' + this.icon
18977                     }
18978                 ]
18979             });
18980         }
18981         
18982         if(this.footer){
18983             var footer = {
18984                 tag : 'a',
18985                 cls : 'small-box-footer',
18986                 href : this.fhref || '#',
18987                 html : this.footer
18988             };
18989             
18990             cfg.cn.push(footer);
18991             
18992         }
18993         
18994         return  cfg;
18995     },
18996
18997     onRender : function(ct,position){
18998         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
18999
19000
19001        
19002                 
19003     },
19004
19005     setHeadline: function (value)
19006     {
19007         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19008     },
19009     
19010     setFooter: function (value, href)
19011     {
19012         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19013         
19014         if(href){
19015             this.el.select('a.small-box-footer',true).first().attr('href', href);
19016         }
19017         
19018     },
19019
19020     setContent: function (value)
19021     {
19022         this.el.select('.roo-content',true).first().dom.innerHTML = value;
19023     },
19024
19025     initEvents: function() 
19026     {   
19027         
19028     }
19029     
19030 });
19031
19032  
19033 /*
19034  * - LGPL
19035  *
19036  * TabBox
19037  * 
19038  */
19039 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19040
19041 /**
19042  * @class Roo.bootstrap.dash.TabBox
19043  * @extends Roo.bootstrap.Component
19044  * Bootstrap TabBox class
19045  * @cfg {String} title Title of the TabBox
19046  * @cfg {String} icon Icon of the TabBox
19047  * 
19048  * @constructor
19049  * Create a new TabBox
19050  * @param {Object} config The config object
19051  */
19052
19053
19054 Roo.bootstrap.dash.TabBox = function(config){
19055     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19056     
19057 };
19058
19059 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
19060
19061     title : '',
19062     icon : false,
19063     
19064     getChildContainer : function()
19065     {
19066         return this.el.select('.tab-content', true).first();
19067     },
19068     
19069     getAutoCreate : function(){
19070         
19071         var header = {
19072             tag: 'li',
19073             cls: 'pull-left header',
19074             html: this.title,
19075             cn : []
19076         };
19077         
19078         if(this.icon){
19079             header.cn.push({
19080                 tag: 'i',
19081                 cls: 'fa ' + this.icon
19082             });
19083         }
19084         
19085         
19086         var cfg = {
19087             tag: 'div',
19088             cls: 'nav-tabs-custom',
19089             cn: [
19090                 {
19091                     tag: 'ul',
19092                     cls: 'nav nav-tabs pull-right',
19093                     cn: [
19094                         header
19095                     ]
19096                 },
19097                 {
19098                     tag: 'div',
19099                     cls: 'tab-content no-padding',
19100                     cn: []
19101                 }
19102             ]
19103         }
19104
19105         return  cfg;
19106     },
19107     
19108     setTitle : function(value)
19109     {
19110         this.el.select('.header', true).first().dom.innerHTML = value;
19111     }
19112     
19113 });
19114
19115  
19116 /*
19117  * - LGPL
19118  *
19119  * Tab pane
19120  * 
19121  */
19122 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19123 /**
19124  * @class Roo.bootstrap.TabPane
19125  * @extends Roo.bootstrap.Component
19126  * Bootstrap TabPane class
19127  * @cfg {Boolean} active (false | true) Default false
19128
19129  * 
19130  * @constructor
19131  * Create a new TabPane
19132  * @param {Object} config The config object
19133  */
19134
19135 Roo.bootstrap.dash.TabPane = function(config){
19136     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19137     
19138 };
19139
19140 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
19141     
19142     active : false,
19143 //    
19144 //    getBox : function()
19145 //    {
19146 //        return this.el.findParent('.nav-tabs-custom', false, true);
19147 //    },
19148     
19149     getAutoCreate : function() 
19150     {
19151         var cfg = {
19152             tag: 'div',
19153             cls: 'tab-pane'
19154         }
19155         
19156         if(this.active){
19157             cfg.cls += ' active';
19158         }
19159         
19160         return cfg;
19161     }
19162     
19163     
19164 });
19165
19166  
19167
19168
19169  /*
19170  * - LGPL
19171  *
19172  * menu
19173  * 
19174  */
19175 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19176
19177 /**
19178  * @class Roo.bootstrap.menu.Menu
19179  * @extends Roo.bootstrap.Component
19180  * Bootstrap Menu class - container for Menu
19181  * @cfg {String} html Text of the menu
19182  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19183  * @cfg {String} icon Font awesome icon
19184  * @cfg {String} pos Menu align to (top | bottom) default bottom
19185  * 
19186  * 
19187  * @constructor
19188  * Create a new Menu
19189  * @param {Object} config The config object
19190  */
19191
19192
19193 Roo.bootstrap.menu.Menu = function(config){
19194     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19195     
19196     this.addEvents({
19197         /**
19198          * @event beforeshow
19199          * Fires before this menu is displayed
19200          * @param {Roo.bootstrap.menu.Menu} this
19201          */
19202         beforeshow : true,
19203         /**
19204          * @event beforehide
19205          * Fires before this menu is hidden
19206          * @param {Roo.bootstrap.menu.Menu} this
19207          */
19208         beforehide : true,
19209         /**
19210          * @event show
19211          * Fires after this menu is displayed
19212          * @param {Roo.bootstrap.menu.Menu} this
19213          */
19214         show : true,
19215         /**
19216          * @event hide
19217          * Fires after this menu is hidden
19218          * @param {Roo.bootstrap.menu.Menu} this
19219          */
19220         hide : true,
19221         /**
19222          * @event click
19223          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19224          * @param {Roo.bootstrap.menu.Menu} this
19225          * @param {Roo.EventObject} e
19226          */
19227         click : true
19228     });
19229     
19230 };
19231
19232 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
19233     
19234     submenu : false,
19235     html : '',
19236     weight : 'default',
19237     icon : false,
19238     pos : 'bottom',
19239     
19240     
19241     getChildContainer : function() {
19242         if(this.isSubMenu){
19243             return this.el;
19244         }
19245         
19246         return this.el.select('ul.dropdown-menu', true).first();  
19247     },
19248     
19249     getAutoCreate : function()
19250     {
19251         var text = [
19252             {
19253                 tag : 'span',
19254                 cls : 'roo-menu-text',
19255                 html : this.html
19256             }
19257         ];
19258         
19259         if(this.icon){
19260             text.unshift({
19261                 tag : 'i',
19262                 cls : 'fa ' + this.icon
19263             })
19264         }
19265         
19266         
19267         var cfg = {
19268             tag : 'div',
19269             cls : 'btn-group',
19270             cn : [
19271                 {
19272                     tag : 'button',
19273                     cls : 'dropdown-button btn btn-' + this.weight,
19274                     cn : text
19275                 },
19276                 {
19277                     tag : 'button',
19278                     cls : 'dropdown-toggle btn btn-' + this.weight,
19279                     cn : [
19280                         {
19281                             tag : 'span',
19282                             cls : 'caret'
19283                         }
19284                     ]
19285                 },
19286                 {
19287                     tag : 'ul',
19288                     cls : 'dropdown-menu'
19289                 }
19290             ]
19291             
19292         };
19293         
19294         if(this.pos == 'top'){
19295             cfg.cls += ' dropup';
19296         }
19297         
19298         if(this.isSubMenu){
19299             cfg = {
19300                 tag : 'ul',
19301                 cls : 'dropdown-menu'
19302             }
19303         }
19304         
19305         return cfg;
19306     },
19307     
19308     onRender : function(ct, position)
19309     {
19310         this.isSubMenu = ct.hasClass('dropdown-submenu');
19311         
19312         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19313     },
19314     
19315     initEvents : function() 
19316     {
19317         if(this.isSubMenu){
19318             return;
19319         }
19320         
19321         this.hidden = true;
19322         
19323         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19324         this.triggerEl.on('click', this.onTriggerPress, this);
19325         
19326         this.buttonEl = this.el.select('button.dropdown-button', true).first();
19327         this.buttonEl.on('click', this.onClick, this);
19328         
19329     },
19330     
19331     list : function()
19332     {
19333         if(this.isSubMenu){
19334             return this.el;
19335         }
19336         
19337         return this.el.select('ul.dropdown-menu', true).first();
19338     },
19339     
19340     onClick : function(e)
19341     {
19342         this.fireEvent("click", this, e);
19343     },
19344     
19345     onTriggerPress  : function(e)
19346     {   
19347         if (this.isVisible()) {
19348             this.hide();
19349         } else {
19350             this.show();
19351         }
19352     },
19353     
19354     isVisible : function(){
19355         return !this.hidden;
19356     },
19357     
19358     show : function()
19359     {
19360         this.fireEvent("beforeshow", this);
19361         
19362         this.hidden = false;
19363         this.el.addClass('open');
19364         
19365         Roo.get(document).on("mouseup", this.onMouseUp, this);
19366         
19367         this.fireEvent("show", this);
19368         
19369         
19370     },
19371     
19372     hide : function()
19373     {
19374         this.fireEvent("beforehide", this);
19375         
19376         this.hidden = true;
19377         this.el.removeClass('open');
19378         
19379         Roo.get(document).un("mouseup", this.onMouseUp);
19380         
19381         this.fireEvent("hide", this);
19382     },
19383     
19384     onMouseUp : function()
19385     {
19386         this.hide();
19387     }
19388     
19389 });
19390
19391  
19392  /*
19393  * - LGPL
19394  *
19395  * menu item
19396  * 
19397  */
19398 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19399
19400 /**
19401  * @class Roo.bootstrap.menu.Item
19402  * @extends Roo.bootstrap.Component
19403  * Bootstrap MenuItem class
19404  * @cfg {Boolean} submenu (true | false) default false
19405  * @cfg {String} html text of the item
19406  * @cfg {String} href the link
19407  * @cfg {Boolean} disable (true | false) default false
19408  * @cfg {Boolean} preventDefault (true | false) default true
19409  * @cfg {String} icon Font awesome icon
19410  * @cfg {String} pos Submenu align to (left | right) default right 
19411  * 
19412  * 
19413  * @constructor
19414  * Create a new Item
19415  * @param {Object} config The config object
19416  */
19417
19418
19419 Roo.bootstrap.menu.Item = function(config){
19420     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19421     this.addEvents({
19422         /**
19423          * @event mouseover
19424          * Fires when the mouse is hovering over this menu
19425          * @param {Roo.bootstrap.menu.Item} this
19426          * @param {Roo.EventObject} e
19427          */
19428         mouseover : true,
19429         /**
19430          * @event mouseout
19431          * Fires when the mouse exits this menu
19432          * @param {Roo.bootstrap.menu.Item} this
19433          * @param {Roo.EventObject} e
19434          */
19435         mouseout : true,
19436         // raw events
19437         /**
19438          * @event click
19439          * The raw click event for the entire grid.
19440          * @param {Roo.EventObject} e
19441          */
19442         click : true
19443     });
19444 };
19445
19446 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
19447     
19448     submenu : false,
19449     href : '',
19450     html : '',
19451     preventDefault: true,
19452     disable : false,
19453     icon : false,
19454     pos : 'right',
19455     
19456     getAutoCreate : function()
19457     {
19458         var text = [
19459             {
19460                 tag : 'span',
19461                 cls : 'roo-menu-item-text',
19462                 html : this.html
19463             }
19464         ];
19465         
19466         if(this.icon){
19467             text.unshift({
19468                 tag : 'i',
19469                 cls : 'fa ' + this.icon
19470             })
19471         }
19472         
19473         var cfg = {
19474             tag : 'li',
19475             cn : [
19476                 {
19477                     tag : 'a',
19478                     href : this.href || '#',
19479                     cn : text
19480                 }
19481             ]
19482         };
19483         
19484         if(this.disable){
19485             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19486         }
19487         
19488         if(this.submenu){
19489             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19490             
19491             if(this.pos == 'left'){
19492                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19493             }
19494         }
19495         
19496         return cfg;
19497     },
19498     
19499     initEvents : function() 
19500     {
19501         this.el.on('mouseover', this.onMouseOver, this);
19502         this.el.on('mouseout', this.onMouseOut, this);
19503         
19504         this.el.select('a', true).first().on('click', this.onClick, this);
19505         
19506     },
19507     
19508     onClick : function(e)
19509     {
19510         if(this.preventDefault){
19511             e.preventDefault();
19512         }
19513         
19514         this.fireEvent("click", this, e);
19515     },
19516     
19517     onMouseOver : function(e)
19518     {
19519         if(this.submenu && this.pos == 'left'){
19520             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19521         }
19522         
19523         this.fireEvent("mouseover", this, e);
19524     },
19525     
19526     onMouseOut : function(e)
19527     {
19528         this.fireEvent("mouseout", this, e);
19529     }
19530 });
19531
19532  
19533
19534  /*
19535  * - LGPL
19536  *
19537  * menu separator
19538  * 
19539  */
19540 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19541
19542 /**
19543  * @class Roo.bootstrap.menu.Separator
19544  * @extends Roo.bootstrap.Component
19545  * Bootstrap Separator class
19546  * 
19547  * @constructor
19548  * Create a new Separator
19549  * @param {Object} config The config object
19550  */
19551
19552
19553 Roo.bootstrap.menu.Separator = function(config){
19554     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19555 };
19556
19557 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
19558     
19559     getAutoCreate : function(){
19560         var cfg = {
19561             tag : 'li',
19562             cls: 'divider'
19563         };
19564         
19565         return cfg;
19566     }
19567    
19568 });
19569
19570  
19571
19572