docs/default.css
[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     });
4651 };
4652
4653 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
4654     
4655     cls: false,
4656     align: false,
4657     bgcolor: false,
4658     border: false,
4659     cellpadding: false,
4660     cellspacing: false,
4661     frame: false,
4662     rules: false,
4663     sortable: false,
4664     summary: false,
4665     width: false,
4666     striped : false,
4667     bordered: false,
4668     hover:  false,
4669     condensed : false,
4670     responsive : false,
4671     sm : false,
4672     cm : false,
4673     store : false,
4674     loadMask : false,
4675     tfoot : true,
4676     thead : true,
4677     RowSelection : false,
4678     CellSelection : false,
4679     layout : false,
4680     
4681     
4682     getAutoCreate : function(){
4683         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4684         
4685         cfg = {
4686             tag: 'table',
4687             cls : 'table',
4688             cn : []
4689         }
4690             
4691         if (this.striped) {
4692             cfg.cls += ' table-striped';
4693         }
4694         
4695         if (this.hover) {
4696             cfg.cls += ' table-hover';
4697         }
4698         if (this.bordered) {
4699             cfg.cls += ' table-bordered';
4700         }
4701         if (this.condensed) {
4702             cfg.cls += ' table-condensed';
4703         }
4704         if (this.responsive) {
4705             cfg.cls += ' table-responsive';
4706         }
4707         
4708         if (this.cls) {
4709             cfg.cls+=  ' ' +this.cls;
4710         }
4711         
4712         // this lot should be simplifed...
4713         
4714         if (this.align) {
4715             cfg.align=this.align;
4716         }
4717         if (this.bgcolor) {
4718             cfg.bgcolor=this.bgcolor;
4719         }
4720         if (this.border) {
4721             cfg.border=this.border;
4722         }
4723         if (this.cellpadding) {
4724             cfg.cellpadding=this.cellpadding;
4725         }
4726         if (this.cellspacing) {
4727             cfg.cellspacing=this.cellspacing;
4728         }
4729         if (this.frame) {
4730             cfg.frame=this.frame;
4731         }
4732         if (this.rules) {
4733             cfg.rules=this.rules;
4734         }
4735         if (this.sortable) {
4736             cfg.sortable=this.sortable;
4737         }
4738         if (this.summary) {
4739             cfg.summary=this.summary;
4740         }
4741         if (this.width) {
4742             cfg.width=this.width;
4743         }
4744         if (this.layout) {
4745             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4746         }
4747         
4748         if(this.store || this.cm){
4749             if(this.thead){
4750                 cfg.cn.push(this.renderHeader());
4751             }
4752             
4753             cfg.cn.push(this.renderBody());
4754             
4755             if(this.tfoot){
4756                 cfg.cn.push(this.renderFooter());
4757             }
4758             
4759             cfg.cls+=  ' TableGrid';
4760         }
4761         
4762         return { cn : [ cfg ] };
4763     },
4764     
4765     initEvents : function()
4766     {   
4767         if(!this.store || !this.cm){
4768             return;
4769         }
4770         
4771         Roo.log('initEvents with ds!!!!');
4772         
4773         var _this = this;
4774         
4775         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4776             e.on('click', _this.sort, _this);
4777         });
4778         
4779         this.el.on("click", this.onClick, this);
4780         this.el.on("dblclick", this.onDblClick, this);
4781         
4782         this.parent().el.setStyle('position', 'relative');
4783         if (this.footer) {
4784             this.footer.parentId = this.id;
4785             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
4786         }
4787         
4788         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4789         
4790         this.store.on('load', this.onLoad, this);
4791         this.store.on('beforeload', this.onBeforeLoad, this);
4792         
4793     },
4794     
4795     onMouseover : function(e, el)
4796     {
4797         var cell = Roo.get(el);
4798         
4799         if(!cell){
4800             return;
4801         }
4802         
4803         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4804             cell = cell.findParent('td', false, true);
4805         }
4806         
4807         var row = cell.findParent('tr', false, true);
4808         var cellIndex = cell.dom.cellIndex;
4809         var rowIndex = row.dom.rowIndex - 1; // start from 0
4810         
4811         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
4812         
4813     },
4814     
4815     onMouseout : function(e, el)
4816     {
4817         var cell = Roo.get(el);
4818         
4819         if(!cell){
4820             return;
4821         }
4822         
4823         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4824             cell = cell.findParent('td', false, true);
4825         }
4826         
4827         var row = cell.findParent('tr', false, true);
4828         var cellIndex = cell.dom.cellIndex;
4829         var rowIndex = row.dom.rowIndex - 1; // start from 0
4830         
4831         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
4832         
4833     },
4834     
4835     onClick : function(e, el)
4836     {
4837         var cell = Roo.get(el);
4838         
4839         if(!cell || !this.CellSelection || !this.RowSelection){
4840             return;
4841         }
4842         
4843         
4844         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4845             cell = cell.findParent('td', false, true);
4846         }
4847         
4848         var row = cell.findParent('tr', false, true);
4849         var cellIndex = cell.dom.cellIndex;
4850         var rowIndex = row.dom.rowIndex - 1;
4851         
4852         if(this.CellSelection){
4853             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4854         }
4855         
4856         if(this.RowSelection){
4857             this.fireEvent('rowclick', this, row, rowIndex, e);
4858         }
4859         
4860         
4861     },
4862     
4863     onDblClick : function(e,el)
4864     {
4865         var cell = Roo.get(el);
4866         
4867         if(!cell || !this.CellSelection || !this.RowSelection){
4868             return;
4869         }
4870         
4871         if(e.getTarget().nodeName.toLowerCase() != 'td'){
4872             cell = cell.findParent('td', false, true);
4873         }
4874         
4875         var row = cell.findParent('tr', false, true);
4876         var cellIndex = cell.dom.cellIndex;
4877         var rowIndex = row.dom.rowIndex - 1;
4878         
4879         if(this.CellSelection){
4880             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4881         }
4882         
4883         if(this.RowSelection){
4884             this.fireEvent('rowdblclick', this, row, rowIndex, e);
4885         }
4886     },
4887     
4888     sort : function(e,el)
4889     {
4890         var col = Roo.get(el)
4891         
4892         if(!col.hasClass('sortable')){
4893             return;
4894         }
4895         
4896         var sort = col.attr('sort');
4897         var dir = 'ASC';
4898         
4899         if(col.hasClass('glyphicon-arrow-up')){
4900             dir = 'DESC';
4901         }
4902         
4903         this.store.sortInfo = {field : sort, direction : dir};
4904         
4905         if (this.footer) {
4906             Roo.log("calling footer first");
4907             this.footer.onClick('first');
4908         } else {
4909         
4910             this.store.load({ params : { start : 0 } });
4911         }
4912     },
4913     
4914     renderHeader : function()
4915     {
4916         var header = {
4917             tag: 'thead',
4918             cn : []
4919         };
4920         
4921         var cm = this.cm;
4922         
4923         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4924             
4925             var config = cm.config[i];
4926                     
4927             var c = {
4928                 tag: 'th',
4929                 style : '',
4930                 html: cm.getColumnHeader(i)
4931             };
4932             
4933             if(typeof(config.hidden) != 'undefined' && config.hidden){
4934                 c.style += ' display:none;';
4935             }
4936             
4937             if(typeof(config.dataIndex) != 'undefined'){
4938                 c.sort = config.dataIndex;
4939             }
4940             
4941             if(typeof(config.sortable) != 'undefined' && config.sortable){
4942                 c.cls = 'sortable';
4943             }
4944             
4945 //            if(typeof(config.align) != 'undefined' && config.align.length){
4946 //                c.style += ' text-align:' + config.align + ';';
4947 //            }
4948             
4949             if(typeof(config.width) != 'undefined'){
4950                 c.style += ' width:' + config.width + 'px;';
4951             }
4952             
4953             header.cn.push(c)
4954         }
4955         
4956         return header;
4957     },
4958     
4959     renderBody : function()
4960     {
4961         var body = {
4962             tag: 'tbody',
4963             cn : [
4964                 {
4965                     tag: 'tr',
4966                     cn : [
4967                         {
4968                             tag : 'td',
4969                             colspan :  this.cm.getColumnCount()
4970                         }
4971                     ]
4972                 }
4973             ]
4974         };
4975         
4976         return body;
4977     },
4978     
4979     renderFooter : function()
4980     {
4981         var footer = {
4982             tag: 'tfoot',
4983             cn : [
4984                 {
4985                     tag: 'tr',
4986                     cn : [
4987                         {
4988                             tag : 'td',
4989                             colspan :  this.cm.getColumnCount()
4990                         }
4991                     ]
4992                 }
4993             ]
4994         };
4995         
4996         return footer;
4997     },
4998     
4999     onLoad : function()
5000     {
5001         Roo.log('ds onload');
5002         this.clear();
5003         
5004         var _this = this;
5005         var cm = this.cm;
5006         
5007         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5008             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5009             
5010             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5011                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5012             }
5013             
5014             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5015                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5016             }
5017         });
5018         
5019         var tbody = this.el.select('tbody', true).first();
5020         
5021         var renders = [];
5022                     
5023         if(this.store.getCount() > 0){
5024             this.store.data.each(function(d,rowIndex){
5025                 var row = {
5026                     tag : 'tr',
5027                     cn : []
5028                 };
5029                 
5030                 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5031                     var config = cm.config[i];
5032                     
5033                     var renderer = cm.getRenderer(i);
5034                     var value = '';
5035                     var id = Roo.id();
5036                     
5037                     if(typeof(renderer) !== 'undefined'){
5038                         value = renderer(d.data[cm.getDataIndex(i)], false, d);
5039                     }
5040                     
5041                     if(typeof(value) === 'object'){
5042                         renders.push({
5043                             container : id,
5044                             cfg : value 
5045                         })
5046                     }
5047                     
5048                     var rowcfg = {
5049                         record: d,
5050                         rowIndex : rowIndex,
5051                         colIndex : i,
5052                         rowClass : ''
5053                     }
5054
5055                     _this.fireEvent('rowclass', this, rowcfg);
5056                     
5057                     var td = {
5058                         tag: 'td',
5059                         id: id,
5060                         cls : rowcfg.rowClass,
5061                         style: '',
5062                         html: (typeof(value) === 'object') ? '' : value
5063                     };
5064                     
5065                     if(typeof(config.hidden) != 'undefined' && config.hidden){
5066                         td.style += ' display:none;';
5067                     }
5068                     
5069                     if(typeof(config.align) != 'undefined' && config.align.length){
5070                         td.style += ' text-align:' + config.align + ';';
5071                     }
5072                     
5073                     if(typeof(config.width) != 'undefined'){
5074                         td.style += ' width:' +  config.width + 'px;';
5075                     }
5076                     
5077                     
5078                     row.cn.push(td);
5079                    
5080                 }
5081                 
5082                 tbody.createChild(row);
5083                 
5084             });
5085         }
5086         
5087         
5088         if(renders.length){
5089             var _this = this;
5090             Roo.each(renders, function(r){
5091                 _this.renderColumn(r);
5092             })
5093         }
5094         
5095         Roo.each(this.el.select('tbody td', true).elements, function(e){
5096             e.on('mouseover', _this.onMouseover, _this);
5097         });
5098         
5099         Roo.each(this.el.select('tbody td', true).elements, function(e){
5100             e.on('mouseout', _this.onMouseout, _this);
5101         });
5102
5103         //if(this.loadMask){
5104         //    this.maskEl.hide();
5105         //}
5106     },
5107     
5108     onBeforeLoad : function()
5109     {
5110         //Roo.log('ds onBeforeLoad');
5111         
5112         //this.clear();
5113         
5114         //if(this.loadMask){
5115         //    this.maskEl.show();
5116         //}
5117     },
5118     
5119     clear : function()
5120     {
5121         this.el.select('tbody', true).first().dom.innerHTML = '';
5122     },
5123     
5124     getSelectionModel : function(){
5125         if(!this.selModel){
5126             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5127         }
5128         return this.selModel;
5129     },
5130     
5131     renderColumn : function(r)
5132     {
5133         var _this = this;
5134         
5135         var t = r.cfg.render(r.container);
5136         
5137         if(r.cfg.cn){
5138             Roo.each(r.cfg.cn, function(c){
5139                 var child = {
5140                     container: t.getChildContainer(),
5141                     cfg: c
5142                 }
5143                 _this.renderColumn(child);
5144             })
5145         }
5146     }
5147    
5148 });
5149
5150  
5151
5152  /*
5153  * - LGPL
5154  *
5155  * table cell
5156  * 
5157  */
5158
5159 /**
5160  * @class Roo.bootstrap.TableCell
5161  * @extends Roo.bootstrap.Component
5162  * Bootstrap TableCell class
5163  * @cfg {String} html cell contain text
5164  * @cfg {String} cls cell class
5165  * @cfg {String} tag cell tag (td|th) default td
5166  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5167  * @cfg {String} align Aligns the content in a cell
5168  * @cfg {String} axis Categorizes cells
5169  * @cfg {String} bgcolor Specifies the background color of a cell
5170  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5171  * @cfg {Number} colspan Specifies the number of columns a cell should span
5172  * @cfg {String} headers Specifies one or more header cells a cell is related to
5173  * @cfg {Number} height Sets the height of a cell
5174  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5175  * @cfg {Number} rowspan Sets the number of rows a cell should span
5176  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5177  * @cfg {String} valign Vertical aligns the content in a cell
5178  * @cfg {Number} width Specifies the width of a cell
5179  * 
5180  * @constructor
5181  * Create a new TableCell
5182  * @param {Object} config The config object
5183  */
5184
5185 Roo.bootstrap.TableCell = function(config){
5186     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5187 };
5188
5189 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5190     
5191     html: false,
5192     cls: false,
5193     tag: false,
5194     abbr: false,
5195     align: false,
5196     axis: false,
5197     bgcolor: false,
5198     charoff: false,
5199     colspan: false,
5200     headers: false,
5201     height: false,
5202     nowrap: false,
5203     rowspan: false,
5204     scope: false,
5205     valign: false,
5206     width: false,
5207     
5208     
5209     getAutoCreate : function(){
5210         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5211         
5212         cfg = {
5213             tag: 'td'
5214         }
5215         
5216         if(this.tag){
5217             cfg.tag = this.tag;
5218         }
5219         
5220         if (this.html) {
5221             cfg.html=this.html
5222         }
5223         if (this.cls) {
5224             cfg.cls=this.cls
5225         }
5226         if (this.abbr) {
5227             cfg.abbr=this.abbr
5228         }
5229         if (this.align) {
5230             cfg.align=this.align
5231         }
5232         if (this.axis) {
5233             cfg.axis=this.axis
5234         }
5235         if (this.bgcolor) {
5236             cfg.bgcolor=this.bgcolor
5237         }
5238         if (this.charoff) {
5239             cfg.charoff=this.charoff
5240         }
5241         if (this.colspan) {
5242             cfg.colspan=this.colspan
5243         }
5244         if (this.headers) {
5245             cfg.headers=this.headers
5246         }
5247         if (this.height) {
5248             cfg.height=this.height
5249         }
5250         if (this.nowrap) {
5251             cfg.nowrap=this.nowrap
5252         }
5253         if (this.rowspan) {
5254             cfg.rowspan=this.rowspan
5255         }
5256         if (this.scope) {
5257             cfg.scope=this.scope
5258         }
5259         if (this.valign) {
5260             cfg.valign=this.valign
5261         }
5262         if (this.width) {
5263             cfg.width=this.width
5264         }
5265         
5266         
5267         return cfg;
5268     }
5269    
5270 });
5271
5272  
5273
5274  /*
5275  * - LGPL
5276  *
5277  * table row
5278  * 
5279  */
5280
5281 /**
5282  * @class Roo.bootstrap.TableRow
5283  * @extends Roo.bootstrap.Component
5284  * Bootstrap TableRow class
5285  * @cfg {String} cls row class
5286  * @cfg {String} align Aligns the content in a table row
5287  * @cfg {String} bgcolor Specifies a background color for a table row
5288  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5289  * @cfg {String} valign Vertical aligns the content in a table row
5290  * 
5291  * @constructor
5292  * Create a new TableRow
5293  * @param {Object} config The config object
5294  */
5295
5296 Roo.bootstrap.TableRow = function(config){
5297     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5298 };
5299
5300 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5301     
5302     cls: false,
5303     align: false,
5304     bgcolor: false,
5305     charoff: false,
5306     valign: false,
5307     
5308     getAutoCreate : function(){
5309         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5310         
5311         cfg = {
5312             tag: 'tr'
5313         }
5314             
5315         if(this.cls){
5316             cfg.cls = this.cls;
5317         }
5318         if(this.align){
5319             cfg.align = this.align;
5320         }
5321         if(this.bgcolor){
5322             cfg.bgcolor = this.bgcolor;
5323         }
5324         if(this.charoff){
5325             cfg.charoff = this.charoff;
5326         }
5327         if(this.valign){
5328             cfg.valign = this.valign;
5329         }
5330         
5331         return cfg;
5332     }
5333    
5334 });
5335
5336  
5337
5338  /*
5339  * - LGPL
5340  *
5341  * table body
5342  * 
5343  */
5344
5345 /**
5346  * @class Roo.bootstrap.TableBody
5347  * @extends Roo.bootstrap.Component
5348  * Bootstrap TableBody class
5349  * @cfg {String} cls element class
5350  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5351  * @cfg {String} align Aligns the content inside the element
5352  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5353  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5354  * 
5355  * @constructor
5356  * Create a new TableBody
5357  * @param {Object} config The config object
5358  */
5359
5360 Roo.bootstrap.TableBody = function(config){
5361     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5362 };
5363
5364 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
5365     
5366     cls: false,
5367     tag: false,
5368     align: false,
5369     charoff: false,
5370     valign: false,
5371     
5372     getAutoCreate : function(){
5373         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5374         
5375         cfg = {
5376             tag: 'tbody'
5377         }
5378             
5379         if (this.cls) {
5380             cfg.cls=this.cls
5381         }
5382         if(this.tag){
5383             cfg.tag = this.tag;
5384         }
5385         
5386         if(this.align){
5387             cfg.align = this.align;
5388         }
5389         if(this.charoff){
5390             cfg.charoff = this.charoff;
5391         }
5392         if(this.valign){
5393             cfg.valign = this.valign;
5394         }
5395         
5396         return cfg;
5397     }
5398     
5399     
5400 //    initEvents : function()
5401 //    {
5402 //        
5403 //        if(!this.store){
5404 //            return;
5405 //        }
5406 //        
5407 //        this.store = Roo.factory(this.store, Roo.data);
5408 //        this.store.on('load', this.onLoad, this);
5409 //        
5410 //        this.store.load();
5411 //        
5412 //    },
5413 //    
5414 //    onLoad: function () 
5415 //    {   
5416 //        this.fireEvent('load', this);
5417 //    }
5418 //    
5419 //   
5420 });
5421
5422  
5423
5424  /*
5425  * Based on:
5426  * Ext JS Library 1.1.1
5427  * Copyright(c) 2006-2007, Ext JS, LLC.
5428  *
5429  * Originally Released Under LGPL - original licence link has changed is not relivant.
5430  *
5431  * Fork - LGPL
5432  * <script type="text/javascript">
5433  */
5434
5435 // as we use this in bootstrap.
5436 Roo.namespace('Roo.form');
5437  /**
5438  * @class Roo.form.Action
5439  * Internal Class used to handle form actions
5440  * @constructor
5441  * @param {Roo.form.BasicForm} el The form element or its id
5442  * @param {Object} config Configuration options
5443  */
5444
5445  
5446  
5447 // define the action interface
5448 Roo.form.Action = function(form, options){
5449     this.form = form;
5450     this.options = options || {};
5451 };
5452 /**
5453  * Client Validation Failed
5454  * @const 
5455  */
5456 Roo.form.Action.CLIENT_INVALID = 'client';
5457 /**
5458  * Server Validation Failed
5459  * @const 
5460  */
5461 Roo.form.Action.SERVER_INVALID = 'server';
5462  /**
5463  * Connect to Server Failed
5464  * @const 
5465  */
5466 Roo.form.Action.CONNECT_FAILURE = 'connect';
5467 /**
5468  * Reading Data from Server Failed
5469  * @const 
5470  */
5471 Roo.form.Action.LOAD_FAILURE = 'load';
5472
5473 Roo.form.Action.prototype = {
5474     type : 'default',
5475     failureType : undefined,
5476     response : undefined,
5477     result : undefined,
5478
5479     // interface method
5480     run : function(options){
5481
5482     },
5483
5484     // interface method
5485     success : function(response){
5486
5487     },
5488
5489     // interface method
5490     handleResponse : function(response){
5491
5492     },
5493
5494     // default connection failure
5495     failure : function(response){
5496         
5497         this.response = response;
5498         this.failureType = Roo.form.Action.CONNECT_FAILURE;
5499         this.form.afterAction(this, false);
5500     },
5501
5502     processResponse : function(response){
5503         this.response = response;
5504         if(!response.responseText){
5505             return true;
5506         }
5507         this.result = this.handleResponse(response);
5508         return this.result;
5509     },
5510
5511     // utility functions used internally
5512     getUrl : function(appendParams){
5513         var url = this.options.url || this.form.url || this.form.el.dom.action;
5514         if(appendParams){
5515             var p = this.getParams();
5516             if(p){
5517                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5518             }
5519         }
5520         return url;
5521     },
5522
5523     getMethod : function(){
5524         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5525     },
5526
5527     getParams : function(){
5528         var bp = this.form.baseParams;
5529         var p = this.options.params;
5530         if(p){
5531             if(typeof p == "object"){
5532                 p = Roo.urlEncode(Roo.applyIf(p, bp));
5533             }else if(typeof p == 'string' && bp){
5534                 p += '&' + Roo.urlEncode(bp);
5535             }
5536         }else if(bp){
5537             p = Roo.urlEncode(bp);
5538         }
5539         return p;
5540     },
5541
5542     createCallback : function(){
5543         return {
5544             success: this.success,
5545             failure: this.failure,
5546             scope: this,
5547             timeout: (this.form.timeout*1000),
5548             upload: this.form.fileUpload ? this.success : undefined
5549         };
5550     }
5551 };
5552
5553 Roo.form.Action.Submit = function(form, options){
5554     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5555 };
5556
5557 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5558     type : 'submit',
5559
5560     haveProgress : false,
5561     uploadComplete : false,
5562     
5563     // uploadProgress indicator.
5564     uploadProgress : function()
5565     {
5566         if (!this.form.progressUrl) {
5567             return;
5568         }
5569         
5570         if (!this.haveProgress) {
5571             Roo.MessageBox.progress("Uploading", "Uploading");
5572         }
5573         if (this.uploadComplete) {
5574            Roo.MessageBox.hide();
5575            return;
5576         }
5577         
5578         this.haveProgress = true;
5579    
5580         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5581         
5582         var c = new Roo.data.Connection();
5583         c.request({
5584             url : this.form.progressUrl,
5585             params: {
5586                 id : uid
5587             },
5588             method: 'GET',
5589             success : function(req){
5590                //console.log(data);
5591                 var rdata = false;
5592                 var edata;
5593                 try  {
5594                    rdata = Roo.decode(req.responseText)
5595                 } catch (e) {
5596                     Roo.log("Invalid data from server..");
5597                     Roo.log(edata);
5598                     return;
5599                 }
5600                 if (!rdata || !rdata.success) {
5601                     Roo.log(rdata);
5602                     Roo.MessageBox.alert(Roo.encode(rdata));
5603                     return;
5604                 }
5605                 var data = rdata.data;
5606                 
5607                 if (this.uploadComplete) {
5608                    Roo.MessageBox.hide();
5609                    return;
5610                 }
5611                    
5612                 if (data){
5613                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5614                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5615                     );
5616                 }
5617                 this.uploadProgress.defer(2000,this);
5618             },
5619        
5620             failure: function(data) {
5621                 Roo.log('progress url failed ');
5622                 Roo.log(data);
5623             },
5624             scope : this
5625         });
5626            
5627     },
5628     
5629     
5630     run : function()
5631     {
5632         // run get Values on the form, so it syncs any secondary forms.
5633         this.form.getValues();
5634         
5635         var o = this.options;
5636         var method = this.getMethod();
5637         var isPost = method == 'POST';
5638         if(o.clientValidation === false || this.form.isValid()){
5639             
5640             if (this.form.progressUrl) {
5641                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5642                     (new Date() * 1) + '' + Math.random());
5643                     
5644             } 
5645             
5646             
5647             Roo.Ajax.request(Roo.apply(this.createCallback(), {
5648                 form:this.form.el.dom,
5649                 url:this.getUrl(!isPost),
5650                 method: method,
5651                 params:isPost ? this.getParams() : null,
5652                 isUpload: this.form.fileUpload
5653             }));
5654             
5655             this.uploadProgress();
5656
5657         }else if (o.clientValidation !== false){ // client validation failed
5658             this.failureType = Roo.form.Action.CLIENT_INVALID;
5659             this.form.afterAction(this, false);
5660         }
5661     },
5662
5663     success : function(response)
5664     {
5665         this.uploadComplete= true;
5666         if (this.haveProgress) {
5667             Roo.MessageBox.hide();
5668         }
5669         
5670         
5671         var result = this.processResponse(response);
5672         if(result === true || result.success){
5673             this.form.afterAction(this, true);
5674             return;
5675         }
5676         if(result.errors){
5677             this.form.markInvalid(result.errors);
5678             this.failureType = Roo.form.Action.SERVER_INVALID;
5679         }
5680         this.form.afterAction(this, false);
5681     },
5682     failure : function(response)
5683     {
5684         this.uploadComplete= true;
5685         if (this.haveProgress) {
5686             Roo.MessageBox.hide();
5687         }
5688         
5689         this.response = response;
5690         this.failureType = Roo.form.Action.CONNECT_FAILURE;
5691         this.form.afterAction(this, false);
5692     },
5693     
5694     handleResponse : function(response){
5695         if(this.form.errorReader){
5696             var rs = this.form.errorReader.read(response);
5697             var errors = [];
5698             if(rs.records){
5699                 for(var i = 0, len = rs.records.length; i < len; i++) {
5700                     var r = rs.records[i];
5701                     errors[i] = r.data;
5702                 }
5703             }
5704             if(errors.length < 1){
5705                 errors = null;
5706             }
5707             return {
5708                 success : rs.success,
5709                 errors : errors
5710             };
5711         }
5712         var ret = false;
5713         try {
5714             ret = Roo.decode(response.responseText);
5715         } catch (e) {
5716             ret = {
5717                 success: false,
5718                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5719                 errors : []
5720             };
5721         }
5722         return ret;
5723         
5724     }
5725 });
5726
5727
5728 Roo.form.Action.Load = function(form, options){
5729     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5730     this.reader = this.form.reader;
5731 };
5732
5733 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5734     type : 'load',
5735
5736     run : function(){
5737         
5738         Roo.Ajax.request(Roo.apply(
5739                 this.createCallback(), {
5740                     method:this.getMethod(),
5741                     url:this.getUrl(false),
5742                     params:this.getParams()
5743         }));
5744     },
5745
5746     success : function(response){
5747         
5748         var result = this.processResponse(response);
5749         if(result === true || !result.success || !result.data){
5750             this.failureType = Roo.form.Action.LOAD_FAILURE;
5751             this.form.afterAction(this, false);
5752             return;
5753         }
5754         this.form.clearInvalid();
5755         this.form.setValues(result.data);
5756         this.form.afterAction(this, true);
5757     },
5758
5759     handleResponse : function(response){
5760         if(this.form.reader){
5761             var rs = this.form.reader.read(response);
5762             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5763             return {
5764                 success : rs.success,
5765                 data : data
5766             };
5767         }
5768         return Roo.decode(response.responseText);
5769     }
5770 });
5771
5772 Roo.form.Action.ACTION_TYPES = {
5773     'load' : Roo.form.Action.Load,
5774     'submit' : Roo.form.Action.Submit
5775 };/*
5776  * - LGPL
5777  *
5778  * form
5779  * 
5780  */
5781
5782 /**
5783  * @class Roo.bootstrap.Form
5784  * @extends Roo.bootstrap.Component
5785  * Bootstrap Form class
5786  * @cfg {String} method  GET | POST (default POST)
5787  * @cfg {String} labelAlign top | left (default top)
5788   * @cfg {String} align left  | right - for navbars
5789
5790  * 
5791  * @constructor
5792  * Create a new Form
5793  * @param {Object} config The config object
5794  */
5795
5796
5797 Roo.bootstrap.Form = function(config){
5798     Roo.bootstrap.Form.superclass.constructor.call(this, config);
5799     this.addEvents({
5800         /**
5801          * @event clientvalidation
5802          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5803          * @param {Form} this
5804          * @param {Boolean} valid true if the form has passed client-side validation
5805          */
5806         clientvalidation: true,
5807         /**
5808          * @event beforeaction
5809          * Fires before any action is performed. Return false to cancel the action.
5810          * @param {Form} this
5811          * @param {Action} action The action to be performed
5812          */
5813         beforeaction: true,
5814         /**
5815          * @event actionfailed
5816          * Fires when an action fails.
5817          * @param {Form} this
5818          * @param {Action} action The action that failed
5819          */
5820         actionfailed : true,
5821         /**
5822          * @event actioncomplete
5823          * Fires when an action is completed.
5824          * @param {Form} this
5825          * @param {Action} action The action that completed
5826          */
5827         actioncomplete : true
5828     });
5829     
5830 };
5831
5832 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
5833       
5834      /**
5835      * @cfg {String} method
5836      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5837      */
5838     method : 'POST',
5839     /**
5840      * @cfg {String} url
5841      * The URL to use for form actions if one isn't supplied in the action options.
5842      */
5843     /**
5844      * @cfg {Boolean} fileUpload
5845      * Set to true if this form is a file upload.
5846      */
5847      
5848     /**
5849      * @cfg {Object} baseParams
5850      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5851      */
5852       
5853     /**
5854      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5855      */
5856     timeout: 30,
5857     /**
5858      * @cfg {Sting} align (left|right) for navbar forms
5859      */
5860     align : 'left',
5861
5862     // private
5863     activeAction : null,
5864  
5865     /**
5866      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5867      * element by passing it or its id or mask the form itself by passing in true.
5868      * @type Mixed
5869      */
5870     waitMsgTarget : false,
5871     
5872      
5873     
5874     /**
5875      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5876      * element by passing it or its id or mask the form itself by passing in true.
5877      * @type Mixed
5878      */
5879     
5880     getAutoCreate : function(){
5881         
5882         var cfg = {
5883             tag: 'form',
5884             method : this.method || 'POST',
5885             id : this.id || Roo.id(),
5886             cls : ''
5887         }
5888         if (this.parent().xtype.match(/^Nav/)) {
5889             cfg.cls = 'navbar-form navbar-' + this.align;
5890             
5891         }
5892         
5893         if (this.labelAlign == 'left' ) {
5894             cfg.cls += ' form-horizontal';
5895         }
5896         
5897         
5898         return cfg;
5899     },
5900     initEvents : function()
5901     {
5902         this.el.on('submit', this.onSubmit, this);
5903         // this was added as random key presses on the form where triggering form submit.
5904         this.el.on('keypress', function(e) {
5905             if (e.getCharCode() != 13) {
5906                 return true;
5907             }
5908             // we might need to allow it for textareas.. and some other items.
5909             // check e.getTarget().
5910             
5911             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
5912                 return true;
5913             }
5914         
5915             Roo.log("keypress blocked");
5916             
5917             e.preventDefault();
5918             return false;
5919         });
5920         
5921     },
5922     // private
5923     onSubmit : function(e){
5924         e.stopEvent();
5925     },
5926     
5927      /**
5928      * Returns true if client-side validation on the form is successful.
5929      * @return Boolean
5930      */
5931     isValid : function(){
5932         var items = this.getItems();
5933         var valid = true;
5934         items.each(function(f){
5935            if(!f.validate()){
5936                valid = false;
5937                
5938            }
5939         });
5940         return valid;
5941     },
5942     /**
5943      * Returns true if any fields in this form have changed since their original load.
5944      * @return Boolean
5945      */
5946     isDirty : function(){
5947         var dirty = false;
5948         var items = this.getItems();
5949         items.each(function(f){
5950            if(f.isDirty()){
5951                dirty = true;
5952                return false;
5953            }
5954            return true;
5955         });
5956         return dirty;
5957     },
5958      /**
5959      * Performs a predefined action (submit or load) or custom actions you define on this form.
5960      * @param {String} actionName The name of the action type
5961      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
5962      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5963      * accept other config options):
5964      * <pre>
5965 Property          Type             Description
5966 ----------------  ---------------  ----------------------------------------------------------------------------------
5967 url               String           The url for the action (defaults to the form's url)
5968 method            String           The form method to use (defaults to the form's method, or POST if not defined)
5969 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
5970 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
5971                                    validate the form on the client (defaults to false)
5972      * </pre>
5973      * @return {BasicForm} this
5974      */
5975     doAction : function(action, options){
5976         if(typeof action == 'string'){
5977             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5978         }
5979         if(this.fireEvent('beforeaction', this, action) !== false){
5980             this.beforeAction(action);
5981             action.run.defer(100, action);
5982         }
5983         return this;
5984     },
5985     
5986     // private
5987     beforeAction : function(action){
5988         var o = action.options;
5989         
5990         // not really supported yet.. ??
5991         
5992         //if(this.waitMsgTarget === true){
5993             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5994         //}else if(this.waitMsgTarget){
5995         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5996         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5997         //}else {
5998         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5999        // }
6000          
6001     },
6002
6003     // private
6004     afterAction : function(action, success){
6005         this.activeAction = null;
6006         var o = action.options;
6007         
6008         //if(this.waitMsgTarget === true){
6009             this.el.unmask();
6010         //}else if(this.waitMsgTarget){
6011         //    this.waitMsgTarget.unmask();
6012         //}else{
6013         //    Roo.MessageBox.updateProgress(1);
6014         //    Roo.MessageBox.hide();
6015        // }
6016         // 
6017         if(success){
6018             if(o.reset){
6019                 this.reset();
6020             }
6021             Roo.callback(o.success, o.scope, [this, action]);
6022             this.fireEvent('actioncomplete', this, action);
6023             
6024         }else{
6025             
6026             // failure condition..
6027             // we have a scenario where updates need confirming.
6028             // eg. if a locking scenario exists..
6029             // we look for { errors : { needs_confirm : true }} in the response.
6030             if (
6031                 (typeof(action.result) != 'undefined')  &&
6032                 (typeof(action.result.errors) != 'undefined')  &&
6033                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6034            ){
6035                 var _t = this;
6036                 Roo.log("not supported yet");
6037                  /*
6038                 
6039                 Roo.MessageBox.confirm(
6040                     "Change requires confirmation",
6041                     action.result.errorMsg,
6042                     function(r) {
6043                         if (r != 'yes') {
6044                             return;
6045                         }
6046                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6047                     }
6048                     
6049                 );
6050                 */
6051                 
6052                 
6053                 return;
6054             }
6055             
6056             Roo.callback(o.failure, o.scope, [this, action]);
6057             // show an error message if no failed handler is set..
6058             if (!this.hasListener('actionfailed')) {
6059                 Roo.log("need to add dialog support");
6060                 /*
6061                 Roo.MessageBox.alert("Error",
6062                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6063                         action.result.errorMsg :
6064                         "Saving Failed, please check your entries or try again"
6065                 );
6066                 */
6067             }
6068             
6069             this.fireEvent('actionfailed', this, action);
6070         }
6071         
6072     },
6073     /**
6074      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6075      * @param {String} id The value to search for
6076      * @return Field
6077      */
6078     findField : function(id){
6079         var items = this.getItems();
6080         var field = items.get(id);
6081         if(!field){
6082              items.each(function(f){
6083                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6084                     field = f;
6085                     return false;
6086                 }
6087                 return true;
6088             });
6089         }
6090         return field || null;
6091     },
6092      /**
6093      * Mark fields in this form invalid in bulk.
6094      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6095      * @return {BasicForm} this
6096      */
6097     markInvalid : function(errors){
6098         if(errors instanceof Array){
6099             for(var i = 0, len = errors.length; i < len; i++){
6100                 var fieldError = errors[i];
6101                 var f = this.findField(fieldError.id);
6102                 if(f){
6103                     f.markInvalid(fieldError.msg);
6104                 }
6105             }
6106         }else{
6107             var field, id;
6108             for(id in errors){
6109                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6110                     field.markInvalid(errors[id]);
6111                 }
6112             }
6113         }
6114         //Roo.each(this.childForms || [], function (f) {
6115         //    f.markInvalid(errors);
6116         //});
6117         
6118         return this;
6119     },
6120
6121     /**
6122      * Set values for fields in this form in bulk.
6123      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6124      * @return {BasicForm} this
6125      */
6126     setValues : function(values){
6127         if(values instanceof Array){ // array of objects
6128             for(var i = 0, len = values.length; i < len; i++){
6129                 var v = values[i];
6130                 var f = this.findField(v.id);
6131                 if(f){
6132                     f.setValue(v.value);
6133                     if(this.trackResetOnLoad){
6134                         f.originalValue = f.getValue();
6135                     }
6136                 }
6137             }
6138         }else{ // object hash
6139             var field, id;
6140             for(id in values){
6141                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6142                     
6143                     if (field.setFromData && 
6144                         field.valueField && 
6145                         field.displayField &&
6146                         // combos' with local stores can 
6147                         // be queried via setValue()
6148                         // to set their value..
6149                         (field.store && !field.store.isLocal)
6150                         ) {
6151                         // it's a combo
6152                         var sd = { };
6153                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6154                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6155                         field.setFromData(sd);
6156                         
6157                     } else {
6158                         field.setValue(values[id]);
6159                     }
6160                     
6161                     
6162                     if(this.trackResetOnLoad){
6163                         field.originalValue = field.getValue();
6164                     }
6165                 }
6166             }
6167         }
6168          
6169         //Roo.each(this.childForms || [], function (f) {
6170         //    f.setValues(values);
6171         //});
6172                 
6173         return this;
6174     },
6175
6176     /**
6177      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6178      * they are returned as an array.
6179      * @param {Boolean} asString
6180      * @return {Object}
6181      */
6182     getValues : function(asString){
6183         //if (this.childForms) {
6184             // copy values from the child forms
6185         //    Roo.each(this.childForms, function (f) {
6186         //        this.setValues(f.getValues());
6187         //    }, this);
6188         //}
6189         
6190         
6191         
6192         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6193         if(asString === true){
6194             return fs;
6195         }
6196         return Roo.urlDecode(fs);
6197     },
6198     
6199     /**
6200      * Returns the fields in this form as an object with key/value pairs. 
6201      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6202      * @return {Object}
6203      */
6204     getFieldValues : function(with_hidden)
6205     {
6206         var items = this.getItems();
6207         var ret = {};
6208         items.each(function(f){
6209             if (!f.getName()) {
6210                 return;
6211             }
6212             var v = f.getValue();
6213             if (f.inputType =='radio') {
6214                 if (typeof(ret[f.getName()]) == 'undefined') {
6215                     ret[f.getName()] = ''; // empty..
6216                 }
6217                 
6218                 if (!f.el.dom.checked) {
6219                     return;
6220                     
6221                 }
6222                 v = f.el.dom.value;
6223                 
6224             }
6225             
6226             // not sure if this supported any more..
6227             if ((typeof(v) == 'object') && f.getRawValue) {
6228                 v = f.getRawValue() ; // dates..
6229             }
6230             // combo boxes where name != hiddenName...
6231             if (f.name != f.getName()) {
6232                 ret[f.name] = f.getRawValue();
6233             }
6234             ret[f.getName()] = v;
6235         });
6236         
6237         return ret;
6238     },
6239
6240     /**
6241      * Clears all invalid messages in this form.
6242      * @return {BasicForm} this
6243      */
6244     clearInvalid : function(){
6245         var items = this.getItems();
6246         
6247         items.each(function(f){
6248            f.clearInvalid();
6249         });
6250         
6251         
6252         
6253         return this;
6254     },
6255
6256     /**
6257      * Resets this form.
6258      * @return {BasicForm} this
6259      */
6260     reset : function(){
6261         var items = this.getItems();
6262         items.each(function(f){
6263             f.reset();
6264         });
6265         
6266         Roo.each(this.childForms || [], function (f) {
6267             f.reset();
6268         });
6269        
6270         
6271         return this;
6272     },
6273     getItems : function()
6274     {
6275         var r=new Roo.util.MixedCollection(false, function(o){
6276             return o.id || (o.id = Roo.id());
6277         });
6278         var iter = function(el) {
6279             if (el.inputEl) {
6280                 r.add(el);
6281             }
6282             if (!el.items) {
6283                 return;
6284             }
6285             Roo.each(el.items,function(e) {
6286                 iter(e);
6287             });
6288             
6289             
6290         };
6291         iter(this);
6292         return r;
6293         
6294         
6295         
6296         
6297     }
6298     
6299 });
6300
6301  
6302 /*
6303  * Based on:
6304  * Ext JS Library 1.1.1
6305  * Copyright(c) 2006-2007, Ext JS, LLC.
6306  *
6307  * Originally Released Under LGPL - original licence link has changed is not relivant.
6308  *
6309  * Fork - LGPL
6310  * <script type="text/javascript">
6311  */
6312 /**
6313  * @class Roo.form.VTypes
6314  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6315  * @singleton
6316  */
6317 Roo.form.VTypes = function(){
6318     // closure these in so they are only created once.
6319     var alpha = /^[a-zA-Z_]+$/;
6320     var alphanum = /^[a-zA-Z0-9_]+$/;
6321     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6322     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6323
6324     // All these messages and functions are configurable
6325     return {
6326         /**
6327          * The function used to validate email addresses
6328          * @param {String} value The email address
6329          */
6330         'email' : function(v){
6331             return email.test(v);
6332         },
6333         /**
6334          * The error text to display when the email validation function returns false
6335          * @type String
6336          */
6337         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6338         /**
6339          * The keystroke filter mask to be applied on email input
6340          * @type RegExp
6341          */
6342         'emailMask' : /[a-z0-9_\.\-@]/i,
6343
6344         /**
6345          * The function used to validate URLs
6346          * @param {String} value The URL
6347          */
6348         'url' : function(v){
6349             return url.test(v);
6350         },
6351         /**
6352          * The error text to display when the url validation function returns false
6353          * @type String
6354          */
6355         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6356         
6357         /**
6358          * The function used to validate alpha values
6359          * @param {String} value The value
6360          */
6361         'alpha' : function(v){
6362             return alpha.test(v);
6363         },
6364         /**
6365          * The error text to display when the alpha validation function returns false
6366          * @type String
6367          */
6368         'alphaText' : 'This field should only contain letters and _',
6369         /**
6370          * The keystroke filter mask to be applied on alpha input
6371          * @type RegExp
6372          */
6373         'alphaMask' : /[a-z_]/i,
6374
6375         /**
6376          * The function used to validate alphanumeric values
6377          * @param {String} value The value
6378          */
6379         'alphanum' : function(v){
6380             return alphanum.test(v);
6381         },
6382         /**
6383          * The error text to display when the alphanumeric validation function returns false
6384          * @type String
6385          */
6386         'alphanumText' : 'This field should only contain letters, numbers and _',
6387         /**
6388          * The keystroke filter mask to be applied on alphanumeric input
6389          * @type RegExp
6390          */
6391         'alphanumMask' : /[a-z0-9_]/i
6392     };
6393 }();/*
6394  * - LGPL
6395  *
6396  * Input
6397  * 
6398  */
6399
6400 /**
6401  * @class Roo.bootstrap.Input
6402  * @extends Roo.bootstrap.Component
6403  * Bootstrap Input class
6404  * @cfg {Boolean} disabled is it disabled
6405  * @cfg {String} fieldLabel - the label associated
6406  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6407  * @cfg {String} name name of the input
6408  * @cfg {string} fieldLabel - the label associated
6409  * @cfg {string}  inputType - input / file submit ...
6410  * @cfg {string} placeholder - placeholder to put in text.
6411  * @cfg {string}  before - input group add on before
6412  * @cfg {string} after - input group add on after
6413  * @cfg {string} size - (lg|sm) or leave empty..
6414  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6415  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6416  * @cfg {Number} md colspan out of 12 for computer-sized screens
6417  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6418  * @cfg {string} value default value of the input
6419  * @cfg {Number} labelWidth set the width of label (0-12)
6420  * @cfg {String} labelAlign (top|left)
6421  * @cfg {Boolean} readOnly Specifies that the field should be read-only
6422  * @cfg {String} align (left|center|right) Default left
6423  * @cfg {Boolean} formatedValue (true | false) Default false
6424  * 
6425  * 
6426  * @constructor
6427  * Create a new Input
6428  * @param {Object} config The config object
6429  */
6430
6431 Roo.bootstrap.Input = function(config){
6432     Roo.bootstrap.Input.superclass.constructor.call(this, config);
6433    
6434         this.addEvents({
6435             /**
6436              * @event focus
6437              * Fires when this field receives input focus.
6438              * @param {Roo.form.Field} this
6439              */
6440             focus : true,
6441             /**
6442              * @event blur
6443              * Fires when this field loses input focus.
6444              * @param {Roo.form.Field} this
6445              */
6446             blur : true,
6447             /**
6448              * @event specialkey
6449              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
6450              * {@link Roo.EventObject#getKey} to determine which key was pressed.
6451              * @param {Roo.form.Field} this
6452              * @param {Roo.EventObject} e The event object
6453              */
6454             specialkey : true,
6455             /**
6456              * @event change
6457              * Fires just before the field blurs if the field value has changed.
6458              * @param {Roo.form.Field} this
6459              * @param {Mixed} newValue The new value
6460              * @param {Mixed} oldValue The original value
6461              */
6462             change : true,
6463             /**
6464              * @event invalid
6465              * Fires after the field has been marked as invalid.
6466              * @param {Roo.form.Field} this
6467              * @param {String} msg The validation message
6468              */
6469             invalid : true,
6470             /**
6471              * @event valid
6472              * Fires after the field has been validated with no errors.
6473              * @param {Roo.form.Field} this
6474              */
6475             valid : true,
6476              /**
6477              * @event keyup
6478              * Fires after the key up
6479              * @param {Roo.form.Field} this
6480              * @param {Roo.EventObject}  e The event Object
6481              */
6482             keyup : true,
6483             /**
6484              * @event formatedValue
6485              * Fires when get the value of the formated input
6486              * @param {Roo.bootstrap.Input} this
6487              * @param {String} value
6488              */
6489             formatedValue : true
6490         });
6491 };
6492
6493 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
6494      /**
6495      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6496       automatic validation (defaults to "keyup").
6497      */
6498     validationEvent : "keyup",
6499      /**
6500      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6501      */
6502     validateOnBlur : true,
6503     /**
6504      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6505      */
6506     validationDelay : 250,
6507      /**
6508      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6509      */
6510     focusClass : "x-form-focus",  // not needed???
6511     
6512        
6513     /**
6514      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6515      */
6516     invalidClass : "has-error",
6517     
6518     /**
6519      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6520      */
6521     selectOnFocus : false,
6522     
6523      /**
6524      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6525      */
6526     maskRe : null,
6527        /**
6528      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6529      */
6530     vtype : null,
6531     
6532       /**
6533      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6534      */
6535     disableKeyFilter : false,
6536     
6537        /**
6538      * @cfg {Boolean} disabled True to disable the field (defaults to false).
6539      */
6540     disabled : false,
6541      /**
6542      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6543      */
6544     allowBlank : true,
6545     /**
6546      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6547      */
6548     blankText : "This field is required",
6549     
6550      /**
6551      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6552      */
6553     minLength : 0,
6554     /**
6555      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6556      */
6557     maxLength : Number.MAX_VALUE,
6558     /**
6559      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6560      */
6561     minLengthText : "The minimum length for this field is {0}",
6562     /**
6563      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6564      */
6565     maxLengthText : "The maximum length for this field is {0}",
6566   
6567     
6568     /**
6569      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6570      * If available, this function will be called only after the basic validators all return true, and will be passed the
6571      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6572      */
6573     validator : null,
6574     /**
6575      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6576      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6577      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
6578      */
6579     regex : null,
6580     /**
6581      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6582      */
6583     regexText : "",
6584     
6585     
6586     
6587     fieldLabel : '',
6588     inputType : 'text',
6589     
6590     name : false,
6591     placeholder: false,
6592     before : false,
6593     after : false,
6594     size : false,
6595     // private
6596     hasFocus : false,
6597     preventMark: false,
6598     isFormField : true,
6599     value : '',
6600     labelWidth : 2,
6601     labelAlign : false,
6602     readOnly : false,
6603     align : false,
6604     formatedValue : false,
6605     
6606     parentLabelAlign : function()
6607     {
6608         var parent = this;
6609         while (parent.parent()) {
6610             parent = parent.parent();
6611             if (typeof(parent.labelAlign) !='undefined') {
6612                 return parent.labelAlign;
6613             }
6614         }
6615         return 'left';
6616         
6617     },
6618     
6619     getAutoCreate : function(){
6620         
6621         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6622         
6623         var id = Roo.id();
6624         
6625         var cfg = {};
6626         
6627         if(this.inputType != 'hidden'){
6628             cfg.cls = 'form-group' //input-group
6629         }
6630         
6631         var input =  {
6632             tag: 'input',
6633             id : id,
6634             type : this.inputType,
6635             value : this.value,
6636             cls : 'form-control',
6637             placeholder : this.placeholder || ''
6638             
6639         };
6640         
6641         if(this.align){
6642             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6643         }
6644         
6645         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6646             input.maxLength = this.maxLength;
6647         }
6648         
6649         if (this.disabled) {
6650             input.disabled=true;
6651         }
6652         
6653         if (this.readOnly) {
6654             input.readonly=true;
6655         }
6656         
6657         if (this.name) {
6658             input.name = this.name;
6659         }
6660         if (this.size) {
6661             input.cls += ' input-' + this.size;
6662         }
6663         var settings=this;
6664         ['xs','sm','md','lg'].map(function(size){
6665             if (settings[size]) {
6666                 cfg.cls += ' col-' + size + '-' + settings[size];
6667             }
6668         });
6669         
6670         var inputblock = input;
6671         
6672         if (this.before || this.after) {
6673             
6674             inputblock = {
6675                 cls : 'input-group',
6676                 cn :  [] 
6677             };
6678             if (this.before && typeof(this.before) == 'string') {
6679                 
6680                 inputblock.cn.push({
6681                     tag :'span',
6682                     cls : 'roo-input-before input-group-addon',
6683                     html : this.before
6684                 });
6685             }
6686             if (this.before && typeof(this.before) == 'object') {
6687                 this.before = Roo.factory(this.before);
6688                 Roo.log(this.before);
6689                 inputblock.cn.push({
6690                     tag :'span',
6691                     cls : 'roo-input-before input-group-' +
6692                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
6693                 });
6694             }
6695             
6696             inputblock.cn.push(input);
6697             
6698             if (this.after && typeof(this.after) == 'string') {
6699                 inputblock.cn.push({
6700                     tag :'span',
6701                     cls : 'roo-input-after input-group-addon',
6702                     html : this.after
6703                 });
6704             }
6705             if (this.after && typeof(this.after) == 'object') {
6706                 this.after = Roo.factory(this.after);
6707                 Roo.log(this.after);
6708                 inputblock.cn.push({
6709                     tag :'span',
6710                     cls : 'roo-input-after input-group-' +
6711                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
6712                 });
6713             }
6714         };
6715         
6716         if (align ==='left' && this.fieldLabel.length) {
6717                 Roo.log("left and has label");
6718                 cfg.cn = [
6719                     
6720                     {
6721                         tag: 'label',
6722                         'for' :  id,
6723                         cls : 'control-label col-sm-' + this.labelWidth,
6724                         html : this.fieldLabel
6725                         
6726                     },
6727                     {
6728                         cls : "col-sm-" + (12 - this.labelWidth), 
6729                         cn: [
6730                             inputblock
6731                         ]
6732                     }
6733                     
6734                 ];
6735         } else if ( this.fieldLabel.length) {
6736                 Roo.log(" label");
6737                  cfg.cn = [
6738                    
6739                     {
6740                         tag: 'label',
6741                         //cls : 'input-group-addon',
6742                         html : this.fieldLabel
6743                         
6744                     },
6745                     
6746                     inputblock
6747                     
6748                 ];
6749
6750         } else {
6751             
6752                 Roo.log(" no label && no align");
6753                 cfg.cn = [
6754                     
6755                         inputblock
6756                     
6757                 ];
6758                 
6759                 
6760         };
6761         Roo.log('input-parentType: ' + this.parentType);
6762         
6763         if (this.parentType === 'Navbar' &&  this.parent().bar) {
6764            cfg.cls += ' navbar-form';
6765            Roo.log(cfg);
6766         }
6767         
6768         return cfg;
6769         
6770     },
6771     /**
6772      * return the real input element.
6773      */
6774     inputEl: function ()
6775     {
6776         return this.el.select('input.form-control',true).first();
6777     },
6778     setDisabled : function(v)
6779     {
6780         var i  = this.inputEl().dom;
6781         if (!v) {
6782             i.removeAttribute('disabled');
6783             return;
6784             
6785         }
6786         i.setAttribute('disabled','true');
6787     },
6788     initEvents : function()
6789     {
6790         
6791         this.inputEl().on("keydown" , this.fireKey,  this);
6792         this.inputEl().on("focus", this.onFocus,  this);
6793         this.inputEl().on("blur", this.onBlur,  this);
6794         
6795         this.inputEl().relayEvent('keyup', this);
6796
6797         // reference to original value for reset
6798         this.originalValue = this.getValue();
6799         //Roo.form.TextField.superclass.initEvents.call(this);
6800         if(this.validationEvent == 'keyup'){
6801             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6802             this.inputEl().on('keyup', this.filterValidation, this);
6803         }
6804         else if(this.validationEvent !== false){
6805             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6806         }
6807         
6808         if(this.selectOnFocus){
6809             this.on("focus", this.preFocus, this);
6810             
6811         }
6812         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6813             this.inputEl().on("keypress", this.filterKeys, this);
6814         }
6815        /* if(this.grow){
6816             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
6817             this.el.on("click", this.autoSize,  this);
6818         }
6819         */
6820         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6821             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6822         }
6823         
6824         if (typeof(this.before) == 'object') {
6825             this.before.render(this.el.select('.roo-input-before',true).first());
6826         }
6827         if (typeof(this.after) == 'object') {
6828             this.after.render(this.el.select('.roo-input-after',true).first());
6829         }
6830         
6831         
6832     },
6833     filterValidation : function(e){
6834         if(!e.isNavKeyPress()){
6835             this.validationTask.delay(this.validationDelay);
6836         }
6837     },
6838      /**
6839      * Validates the field value
6840      * @return {Boolean} True if the value is valid, else false
6841      */
6842     validate : function(){
6843         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6844         if(this.disabled || this.validateValue(this.getRawValue())){
6845             this.clearInvalid();
6846             return true;
6847         }
6848         return false;
6849     },
6850     
6851     
6852     /**
6853      * Validates a value according to the field's validation rules and marks the field as invalid
6854      * if the validation fails
6855      * @param {Mixed} value The value to validate
6856      * @return {Boolean} True if the value is valid, else false
6857      */
6858     validateValue : function(value){
6859         if(value.length < 1)  { // if it's blank
6860              if(this.allowBlank){
6861                 this.clearInvalid();
6862                 return true;
6863              }else{
6864                 this.markInvalid(this.blankText);
6865                 return false;
6866              }
6867         }
6868         if(value.length < this.minLength){
6869             this.markInvalid(String.format(this.minLengthText, this.minLength));
6870             return false;
6871         }
6872         if(value.length > this.maxLength){
6873             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6874             return false;
6875         }
6876         if(this.vtype){
6877             var vt = Roo.form.VTypes;
6878             if(!vt[this.vtype](value, this)){
6879                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6880                 return false;
6881             }
6882         }
6883         if(typeof this.validator == "function"){
6884             var msg = this.validator(value);
6885             if(msg !== true){
6886                 this.markInvalid(msg);
6887                 return false;
6888             }
6889         }
6890         if(this.regex && !this.regex.test(value)){
6891             this.markInvalid(this.regexText);
6892             return false;
6893         }
6894         return true;
6895     },
6896
6897     
6898     
6899      // private
6900     fireKey : function(e){
6901         //Roo.log('field ' + e.getKey());
6902         if(e.isNavKeyPress()){
6903             this.fireEvent("specialkey", this, e);
6904         }
6905     },
6906     focus : function (selectText){
6907         if(this.rendered){
6908             this.inputEl().focus();
6909             if(selectText === true){
6910                 this.inputEl().dom.select();
6911             }
6912         }
6913         return this;
6914     } ,
6915     
6916     onFocus : function(){
6917         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6918            // this.el.addClass(this.focusClass);
6919         }
6920         if(!this.hasFocus){
6921             this.hasFocus = true;
6922             this.startValue = this.getValue();
6923             this.fireEvent("focus", this);
6924         }
6925     },
6926     
6927     beforeBlur : Roo.emptyFn,
6928
6929     
6930     // private
6931     onBlur : function(){
6932         this.beforeBlur();
6933         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6934             //this.el.removeClass(this.focusClass);
6935         }
6936         this.hasFocus = false;
6937         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6938             this.validate();
6939         }
6940         var v = this.getValue();
6941         if(String(v) !== String(this.startValue)){
6942             this.fireEvent('change', this, v, this.startValue);
6943         }
6944         this.fireEvent("blur", this);
6945     },
6946     
6947     /**
6948      * Resets the current field value to the originally loaded value and clears any validation messages
6949      */
6950     reset : function(){
6951         this.setValue(this.originalValue);
6952         this.clearInvalid();
6953     },
6954      /**
6955      * Returns the name of the field
6956      * @return {Mixed} name The name field
6957      */
6958     getName: function(){
6959         return this.name;
6960     },
6961      /**
6962      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
6963      * @return {Mixed} value The field value
6964      */
6965     getValue : function(){
6966         
6967         var v = this.inputEl().getValue();
6968         
6969         if(this.formatedValue){
6970             
6971             this.fireEvent("formatedValue", this, v);
6972             
6973             return this.value;
6974         }
6975         
6976         return v;
6977     },
6978     /**
6979      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
6980      * @return {Mixed} value The field value
6981      */
6982     getRawValue : function(){
6983         var v = this.inputEl().getValue();
6984         
6985         return v;
6986     },
6987     
6988     /**
6989      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
6990      * @param {Mixed} value The value to set
6991      */
6992     setRawValue : function(v){
6993         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6994     },
6995     
6996     selectText : function(start, end){
6997         var v = this.getRawValue();
6998         if(v.length > 0){
6999             start = start === undefined ? 0 : start;
7000             end = end === undefined ? v.length : end;
7001             var d = this.inputEl().dom;
7002             if(d.setSelectionRange){
7003                 d.setSelectionRange(start, end);
7004             }else if(d.createTextRange){
7005                 var range = d.createTextRange();
7006                 range.moveStart("character", start);
7007                 range.moveEnd("character", v.length-end);
7008                 range.select();
7009             }
7010         }
7011     },
7012     
7013     /**
7014      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7015      * @param {Mixed} value The value to set
7016      */
7017     setValue : function(v){
7018         this.value = v;
7019         if(this.rendered){
7020             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7021             this.validate();
7022         }
7023     },
7024     
7025     /*
7026     processValue : function(value){
7027         if(this.stripCharsRe){
7028             var newValue = value.replace(this.stripCharsRe, '');
7029             if(newValue !== value){
7030                 this.setRawValue(newValue);
7031                 return newValue;
7032             }
7033         }
7034         return value;
7035     },
7036   */
7037     preFocus : function(){
7038         
7039         if(this.selectOnFocus){
7040             this.inputEl().dom.select();
7041         }
7042     },
7043     filterKeys : function(e){
7044         var k = e.getKey();
7045         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7046             return;
7047         }
7048         var c = e.getCharCode(), cc = String.fromCharCode(c);
7049         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7050             return;
7051         }
7052         if(!this.maskRe.test(cc)){
7053             e.stopEvent();
7054         }
7055     },
7056      /**
7057      * Clear any invalid styles/messages for this field
7058      */
7059     clearInvalid : function(){
7060         
7061         if(!this.el || this.preventMark){ // not rendered
7062             return;
7063         }
7064         this.el.removeClass(this.invalidClass);
7065         /*
7066         switch(this.msgTarget){
7067             case 'qtip':
7068                 this.el.dom.qtip = '';
7069                 break;
7070             case 'title':
7071                 this.el.dom.title = '';
7072                 break;
7073             case 'under':
7074                 if(this.errorEl){
7075                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7076                 }
7077                 break;
7078             case 'side':
7079                 if(this.errorIcon){
7080                     this.errorIcon.dom.qtip = '';
7081                     this.errorIcon.hide();
7082                     this.un('resize', this.alignErrorIcon, this);
7083                 }
7084                 break;
7085             default:
7086                 var t = Roo.getDom(this.msgTarget);
7087                 t.innerHTML = '';
7088                 t.style.display = 'none';
7089                 break;
7090         }
7091         */
7092         this.fireEvent('valid', this);
7093     },
7094      /**
7095      * Mark this field as invalid
7096      * @param {String} msg The validation message
7097      */
7098     markInvalid : function(msg){
7099         if(!this.el  || this.preventMark){ // not rendered
7100             return;
7101         }
7102         this.el.addClass(this.invalidClass);
7103         /*
7104         msg = msg || this.invalidText;
7105         switch(this.msgTarget){
7106             case 'qtip':
7107                 this.el.dom.qtip = msg;
7108                 this.el.dom.qclass = 'x-form-invalid-tip';
7109                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7110                     Roo.QuickTips.enable();
7111                 }
7112                 break;
7113             case 'title':
7114                 this.el.dom.title = msg;
7115                 break;
7116             case 'under':
7117                 if(!this.errorEl){
7118                     var elp = this.el.findParent('.x-form-element', 5, true);
7119                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7120                     this.errorEl.setWidth(elp.getWidth(true)-20);
7121                 }
7122                 this.errorEl.update(msg);
7123                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7124                 break;
7125             case 'side':
7126                 if(!this.errorIcon){
7127                     var elp = this.el.findParent('.x-form-element', 5, true);
7128                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7129                 }
7130                 this.alignErrorIcon();
7131                 this.errorIcon.dom.qtip = msg;
7132                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7133                 this.errorIcon.show();
7134                 this.on('resize', this.alignErrorIcon, this);
7135                 break;
7136             default:
7137                 var t = Roo.getDom(this.msgTarget);
7138                 t.innerHTML = msg;
7139                 t.style.display = this.msgDisplay;
7140                 break;
7141         }
7142         */
7143         this.fireEvent('invalid', this, msg);
7144     },
7145     // private
7146     SafariOnKeyDown : function(event)
7147     {
7148         // this is a workaround for a password hang bug on chrome/ webkit.
7149         
7150         var isSelectAll = false;
7151         
7152         if(this.inputEl().dom.selectionEnd > 0){
7153             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7154         }
7155         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7156             event.preventDefault();
7157             this.setValue('');
7158             return;
7159         }
7160         
7161         if(isSelectAll){ // backspace and delete key
7162             
7163             event.preventDefault();
7164             // this is very hacky as keydown always get's upper case.
7165             //
7166             var cc = String.fromCharCode(event.getCharCode());
7167             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7168             
7169         }
7170     },
7171     adjustWidth : function(tag, w){
7172         tag = tag.toLowerCase();
7173         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7174             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7175                 if(tag == 'input'){
7176                     return w + 2;
7177                 }
7178                 if(tag == 'textarea'){
7179                     return w-2;
7180                 }
7181             }else if(Roo.isOpera){
7182                 if(tag == 'input'){
7183                     return w + 2;
7184                 }
7185                 if(tag == 'textarea'){
7186                     return w-2;
7187                 }
7188             }
7189         }
7190         return w;
7191     }
7192     
7193 });
7194
7195  
7196 /*
7197  * - LGPL
7198  *
7199  * Input
7200  * 
7201  */
7202
7203 /**
7204  * @class Roo.bootstrap.TextArea
7205  * @extends Roo.bootstrap.Input
7206  * Bootstrap TextArea class
7207  * @cfg {Number} cols Specifies the visible width of a text area
7208  * @cfg {Number} rows Specifies the visible number of lines in a text area
7209  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7210  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7211  * @cfg {string} html text
7212  * 
7213  * @constructor
7214  * Create a new TextArea
7215  * @param {Object} config The config object
7216  */
7217
7218 Roo.bootstrap.TextArea = function(config){
7219     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7220    
7221 };
7222
7223 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7224      
7225     cols : false,
7226     rows : 5,
7227     readOnly : false,
7228     warp : 'soft',
7229     resize : false,
7230     value: false,
7231     html: false,
7232     
7233     getAutoCreate : function(){
7234         
7235         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7236         
7237         var id = Roo.id();
7238         
7239         var cfg = {};
7240         
7241         var input =  {
7242             tag: 'textarea',
7243             id : id,
7244             warp : this.warp,
7245             rows : this.rows,
7246             value : this.value || '',
7247             html: this.html || '',
7248             cls : 'form-control',
7249             placeholder : this.placeholder || '' 
7250             
7251         };
7252         
7253         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7254             input.maxLength = this.maxLength;
7255         }
7256         
7257         if(this.resize){
7258             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7259         }
7260         
7261         if(this.cols){
7262             input.cols = this.cols;
7263         }
7264         
7265         if (this.readOnly) {
7266             input.readonly = true;
7267         }
7268         
7269         if (this.name) {
7270             input.name = this.name;
7271         }
7272         
7273         if (this.size) {
7274             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7275         }
7276         
7277         var settings=this;
7278         ['xs','sm','md','lg'].map(function(size){
7279             if (settings[size]) {
7280                 cfg.cls += ' col-' + size + '-' + settings[size];
7281             }
7282         });
7283         
7284         var inputblock = input;
7285         
7286         if (this.before || this.after) {
7287             
7288             inputblock = {
7289                 cls : 'input-group',
7290                 cn :  [] 
7291             };
7292             if (this.before) {
7293                 inputblock.cn.push({
7294                     tag :'span',
7295                     cls : 'input-group-addon',
7296                     html : this.before
7297                 });
7298             }
7299             inputblock.cn.push(input);
7300             if (this.after) {
7301                 inputblock.cn.push({
7302                     tag :'span',
7303                     cls : 'input-group-addon',
7304                     html : this.after
7305                 });
7306             }
7307             
7308         }
7309         
7310         if (align ==='left' && this.fieldLabel.length) {
7311                 Roo.log("left and has label");
7312                 cfg.cn = [
7313                     
7314                     {
7315                         tag: 'label',
7316                         'for' :  id,
7317                         cls : 'control-label col-sm-' + this.labelWidth,
7318                         html : this.fieldLabel
7319                         
7320                     },
7321                     {
7322                         cls : "col-sm-" + (12 - this.labelWidth), 
7323                         cn: [
7324                             inputblock
7325                         ]
7326                     }
7327                     
7328                 ];
7329         } else if ( this.fieldLabel.length) {
7330                 Roo.log(" label");
7331                  cfg.cn = [
7332                    
7333                     {
7334                         tag: 'label',
7335                         //cls : 'input-group-addon',
7336                         html : this.fieldLabel
7337                         
7338                     },
7339                     
7340                     inputblock
7341                     
7342                 ];
7343
7344         } else {
7345             
7346                    Roo.log(" no label && no align");
7347                 cfg.cn = [
7348                     
7349                         inputblock
7350                     
7351                 ];
7352                 
7353                 
7354         }
7355         
7356         if (this.disabled) {
7357             input.disabled=true;
7358         }
7359         
7360         return cfg;
7361         
7362     },
7363     /**
7364      * return the real textarea element.
7365      */
7366     inputEl: function ()
7367     {
7368         return this.el.select('textarea.form-control',true).first();
7369     }
7370 });
7371
7372  
7373 /*
7374  * - LGPL
7375  *
7376  * trigger field - base class for combo..
7377  * 
7378  */
7379  
7380 /**
7381  * @class Roo.bootstrap.TriggerField
7382  * @extends Roo.bootstrap.Input
7383  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7384  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7385  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7386  * for which you can provide a custom implementation.  For example:
7387  * <pre><code>
7388 var trigger = new Roo.bootstrap.TriggerField();
7389 trigger.onTriggerClick = myTriggerFn;
7390 trigger.applyTo('my-field');
7391 </code></pre>
7392  *
7393  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7394  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7395  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
7396  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7397  * @constructor
7398  * Create a new TriggerField.
7399  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7400  * to the base TextField)
7401  */
7402 Roo.bootstrap.TriggerField = function(config){
7403     this.mimicing = false;
7404     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7405 };
7406
7407 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
7408     /**
7409      * @cfg {String} triggerClass A CSS class to apply to the trigger
7410      */
7411      /**
7412      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7413      */
7414     hideTrigger:false,
7415
7416     /** @cfg {Boolean} grow @hide */
7417     /** @cfg {Number} growMin @hide */
7418     /** @cfg {Number} growMax @hide */
7419
7420     /**
7421      * @hide 
7422      * @method
7423      */
7424     autoSize: Roo.emptyFn,
7425     // private
7426     monitorTab : true,
7427     // private
7428     deferHeight : true,
7429
7430     
7431     actionMode : 'wrap',
7432     
7433     
7434     
7435     getAutoCreate : function(){
7436        
7437         var parent = this.parent();
7438         
7439         var align = this.labelAlign || this.parentLabelAlign();
7440         
7441         var id = Roo.id();
7442         
7443         var cfg = {
7444             cls: 'form-group' //input-group
7445         };
7446         
7447         
7448         var input =  {
7449             tag: 'input',
7450             id : id,
7451             type : this.inputType,
7452             cls : 'form-control',
7453             autocomplete: 'off',
7454             placeholder : this.placeholder || '' 
7455             
7456         };
7457         if (this.name) {
7458             input.name = this.name;
7459         }
7460         if (this.size) {
7461             input.cls += ' input-' + this.size;
7462         }
7463         
7464         if (this.disabled) {
7465             input.disabled=true;
7466         }
7467         
7468         var inputblock = input;
7469         
7470         if (this.before || this.after) {
7471             
7472             inputblock = {
7473                 cls : 'input-group',
7474                 cn :  [] 
7475             };
7476             if (this.before) {
7477                 inputblock.cn.push({
7478                     tag :'span',
7479                     cls : 'input-group-addon',
7480                     html : this.before
7481                 });
7482             }
7483             inputblock.cn.push(input);
7484             if (this.after) {
7485                 inputblock.cn.push({
7486                     tag :'span',
7487                     cls : 'input-group-addon',
7488                     html : this.after
7489                 });
7490             }
7491             
7492         };
7493         
7494         var box = {
7495             tag: 'div',
7496             cn: [
7497                 {
7498                     tag: 'input',
7499                     type : 'hidden',
7500                     cls: 'form-hidden-field'
7501                 },
7502                 inputblock
7503             ]
7504             
7505         };
7506         
7507         if(this.multiple){
7508             Roo.log('multiple');
7509             
7510             box = {
7511                 tag: 'div',
7512                 cn: [
7513                     {
7514                         tag: 'input',
7515                         type : 'hidden',
7516                         cls: 'form-hidden-field'
7517                     },
7518                     {
7519                         tag: 'ul',
7520                         cls: 'select2-choices',
7521                         cn:[
7522                             {
7523                                 tag: 'li',
7524                                 cls: 'select2-search-field',
7525                                 cn: [
7526
7527                                     inputblock
7528                                 ]
7529                             }
7530                         ]
7531                     }
7532                 ]
7533             }
7534         };
7535         
7536         var combobox = {
7537             cls: 'select2-container input-group',
7538             cn: [
7539                 box,
7540                 {
7541                     tag: 'ul',
7542                     cls: 'typeahead typeahead-long dropdown-menu',
7543                     style: 'display:none'
7544                 }
7545             ]
7546         };
7547         
7548         if(!this.multiple){
7549             combobox.cn.push({
7550                 tag :'span',
7551                 cls : 'input-group-addon btn dropdown-toggle',
7552                 cn : [
7553                     {
7554                         tag: 'span',
7555                         cls: 'caret'
7556                     },
7557                     {
7558                         tag: 'span',
7559                         cls: 'combobox-clear',
7560                         cn  : [
7561                             {
7562                                 tag : 'i',
7563                                 cls: 'icon-remove'
7564                             }
7565                         ]
7566                     }
7567                 ]
7568
7569             })
7570         }
7571         
7572         if(this.multiple){
7573             combobox.cls += ' select2-container-multi';
7574         }
7575         
7576         if (align ==='left' && this.fieldLabel.length) {
7577             
7578                 Roo.log("left and has label");
7579                 cfg.cn = [
7580                     
7581                     {
7582                         tag: 'label',
7583                         'for' :  id,
7584                         cls : 'control-label col-sm-' + this.labelWidth,
7585                         html : this.fieldLabel
7586                         
7587                     },
7588                     {
7589                         cls : "col-sm-" + (12 - this.labelWidth), 
7590                         cn: [
7591                             combobox
7592                         ]
7593                     }
7594                     
7595                 ];
7596         } else if ( this.fieldLabel.length) {
7597                 Roo.log(" label");
7598                  cfg.cn = [
7599                    
7600                     {
7601                         tag: 'label',
7602                         //cls : 'input-group-addon',
7603                         html : this.fieldLabel
7604                         
7605                     },
7606                     
7607                     combobox
7608                     
7609                 ];
7610
7611         } else {
7612             
7613                 Roo.log(" no label && no align");
7614                 cfg = combobox
7615                      
7616                 
7617         }
7618          
7619         var settings=this;
7620         ['xs','sm','md','lg'].map(function(size){
7621             if (settings[size]) {
7622                 cfg.cls += ' col-' + size + '-' + settings[size];
7623             }
7624         });
7625         
7626         return cfg;
7627         
7628     },
7629     
7630     
7631     
7632     // private
7633     onResize : function(w, h){
7634 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7635 //        if(typeof w == 'number'){
7636 //            var x = w - this.trigger.getWidth();
7637 //            this.inputEl().setWidth(this.adjustWidth('input', x));
7638 //            this.trigger.setStyle('left', x+'px');
7639 //        }
7640     },
7641
7642     // private
7643     adjustSize : Roo.BoxComponent.prototype.adjustSize,
7644
7645     // private
7646     getResizeEl : function(){
7647         return this.inputEl();
7648     },
7649
7650     // private
7651     getPositionEl : function(){
7652         return this.inputEl();
7653     },
7654
7655     // private
7656     alignErrorIcon : function(){
7657         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7658     },
7659
7660     // private
7661     initEvents : function(){
7662         
7663         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7664         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7665         if(!this.multiple){
7666             this.trigger = this.el.select('span.dropdown-toggle',true).first();
7667             if(this.hideTrigger){
7668                 this.trigger.setDisplayed(false);
7669             }
7670             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7671         }
7672         
7673         if(this.multiple){
7674             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7675         }
7676         
7677         //this.trigger.addClassOnOver('x-form-trigger-over');
7678         //this.trigger.addClassOnClick('x-form-trigger-click');
7679         
7680         //if(!this.width){
7681         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7682         //}
7683     },
7684
7685     // private
7686     initTrigger : function(){
7687        
7688     },
7689
7690     // private
7691     onDestroy : function(){
7692         if(this.trigger){
7693             this.trigger.removeAllListeners();
7694           //  this.trigger.remove();
7695         }
7696         //if(this.wrap){
7697         //    this.wrap.remove();
7698         //}
7699         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7700     },
7701
7702     // private
7703     onFocus : function(){
7704         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7705         /*
7706         if(!this.mimicing){
7707             this.wrap.addClass('x-trigger-wrap-focus');
7708             this.mimicing = true;
7709             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7710             if(this.monitorTab){
7711                 this.el.on("keydown", this.checkTab, this);
7712             }
7713         }
7714         */
7715     },
7716
7717     // private
7718     checkTab : function(e){
7719         if(e.getKey() == e.TAB){
7720             this.triggerBlur();
7721         }
7722     },
7723
7724     // private
7725     onBlur : function(){
7726         // do nothing
7727     },
7728
7729     // private
7730     mimicBlur : function(e, t){
7731         /*
7732         if(!this.wrap.contains(t) && this.validateBlur()){
7733             this.triggerBlur();
7734         }
7735         */
7736     },
7737
7738     // private
7739     triggerBlur : function(){
7740         this.mimicing = false;
7741         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7742         if(this.monitorTab){
7743             this.el.un("keydown", this.checkTab, this);
7744         }
7745         //this.wrap.removeClass('x-trigger-wrap-focus');
7746         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7747     },
7748
7749     // private
7750     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7751     validateBlur : function(e, t){
7752         return true;
7753     },
7754
7755     // private
7756     onDisable : function(){
7757         this.inputEl().dom.disabled = true;
7758         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7759         //if(this.wrap){
7760         //    this.wrap.addClass('x-item-disabled');
7761         //}
7762     },
7763
7764     // private
7765     onEnable : function(){
7766         this.inputEl().dom.disabled = false;
7767         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7768         //if(this.wrap){
7769         //    this.el.removeClass('x-item-disabled');
7770         //}
7771     },
7772
7773     // private
7774     onShow : function(){
7775         var ae = this.getActionEl();
7776         
7777         if(ae){
7778             ae.dom.style.display = '';
7779             ae.dom.style.visibility = 'visible';
7780         }
7781     },
7782
7783     // private
7784     
7785     onHide : function(){
7786         var ae = this.getActionEl();
7787         ae.dom.style.display = 'none';
7788     },
7789
7790     /**
7791      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
7792      * by an implementing function.
7793      * @method
7794      * @param {EventObject} e
7795      */
7796     onTriggerClick : Roo.emptyFn
7797 });
7798  /*
7799  * Based on:
7800  * Ext JS Library 1.1.1
7801  * Copyright(c) 2006-2007, Ext JS, LLC.
7802  *
7803  * Originally Released Under LGPL - original licence link has changed is not relivant.
7804  *
7805  * Fork - LGPL
7806  * <script type="text/javascript">
7807  */
7808
7809
7810 /**
7811  * @class Roo.data.SortTypes
7812  * @singleton
7813  * Defines the default sorting (casting?) comparison functions used when sorting data.
7814  */
7815 Roo.data.SortTypes = {
7816     /**
7817      * Default sort that does nothing
7818      * @param {Mixed} s The value being converted
7819      * @return {Mixed} The comparison value
7820      */
7821     none : function(s){
7822         return s;
7823     },
7824     
7825     /**
7826      * The regular expression used to strip tags
7827      * @type {RegExp}
7828      * @property
7829      */
7830     stripTagsRE : /<\/?[^>]+>/gi,
7831     
7832     /**
7833      * Strips all HTML tags to sort on text only
7834      * @param {Mixed} s The value being converted
7835      * @return {String} The comparison value
7836      */
7837     asText : function(s){
7838         return String(s).replace(this.stripTagsRE, "");
7839     },
7840     
7841     /**
7842      * Strips all HTML tags to sort on text only - Case insensitive
7843      * @param {Mixed} s The value being converted
7844      * @return {String} The comparison value
7845      */
7846     asUCText : function(s){
7847         return String(s).toUpperCase().replace(this.stripTagsRE, "");
7848     },
7849     
7850     /**
7851      * Case insensitive string
7852      * @param {Mixed} s The value being converted
7853      * @return {String} The comparison value
7854      */
7855     asUCString : function(s) {
7856         return String(s).toUpperCase();
7857     },
7858     
7859     /**
7860      * Date sorting
7861      * @param {Mixed} s The value being converted
7862      * @return {Number} The comparison value
7863      */
7864     asDate : function(s) {
7865         if(!s){
7866             return 0;
7867         }
7868         if(s instanceof Date){
7869             return s.getTime();
7870         }
7871         return Date.parse(String(s));
7872     },
7873     
7874     /**
7875      * Float sorting
7876      * @param {Mixed} s The value being converted
7877      * @return {Float} The comparison value
7878      */
7879     asFloat : function(s) {
7880         var val = parseFloat(String(s).replace(/,/g, ""));
7881         if(isNaN(val)) val = 0;
7882         return val;
7883     },
7884     
7885     /**
7886      * Integer sorting
7887      * @param {Mixed} s The value being converted
7888      * @return {Number} The comparison value
7889      */
7890     asInt : function(s) {
7891         var val = parseInt(String(s).replace(/,/g, ""));
7892         if(isNaN(val)) val = 0;
7893         return val;
7894     }
7895 };/*
7896  * Based on:
7897  * Ext JS Library 1.1.1
7898  * Copyright(c) 2006-2007, Ext JS, LLC.
7899  *
7900  * Originally Released Under LGPL - original licence link has changed is not relivant.
7901  *
7902  * Fork - LGPL
7903  * <script type="text/javascript">
7904  */
7905
7906 /**
7907 * @class Roo.data.Record
7908  * Instances of this class encapsulate both record <em>definition</em> information, and record
7909  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7910  * to access Records cached in an {@link Roo.data.Store} object.<br>
7911  * <p>
7912  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7913  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7914  * objects.<br>
7915  * <p>
7916  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7917  * @constructor
7918  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7919  * {@link #create}. The parameters are the same.
7920  * @param {Array} data An associative Array of data values keyed by the field name.
7921  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7922  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7923  * not specified an integer id is generated.
7924  */
7925 Roo.data.Record = function(data, id){
7926     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7927     this.data = data;
7928 };
7929
7930 /**
7931  * Generate a constructor for a specific record layout.
7932  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7933  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7934  * Each field definition object may contain the following properties: <ul>
7935  * <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,
7936  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7937  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7938  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7939  * is being used, then this is a string containing the javascript expression to reference the data relative to 
7940  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7941  * to the data item relative to the record element. If the mapping expression is the same as the field name,
7942  * this may be omitted.</p></li>
7943  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7944  * <ul><li>auto (Default, implies no conversion)</li>
7945  * <li>string</li>
7946  * <li>int</li>
7947  * <li>float</li>
7948  * <li>boolean</li>
7949  * <li>date</li></ul></p></li>
7950  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7951  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7952  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7953  * by the Reader into an object that will be stored in the Record. It is passed the
7954  * following parameters:<ul>
7955  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7956  * </ul></p></li>
7957  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7958  * </ul>
7959  * <br>usage:<br><pre><code>
7960 var TopicRecord = Roo.data.Record.create(
7961     {name: 'title', mapping: 'topic_title'},
7962     {name: 'author', mapping: 'username'},
7963     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7964     {name: 'lastPost', mapping: 'post_time', type: 'date'},
7965     {name: 'lastPoster', mapping: 'user2'},
7966     {name: 'excerpt', mapping: 'post_text'}
7967 );
7968
7969 var myNewRecord = new TopicRecord({
7970     title: 'Do my job please',
7971     author: 'noobie',
7972     totalPosts: 1,
7973     lastPost: new Date(),
7974     lastPoster: 'Animal',
7975     excerpt: 'No way dude!'
7976 });
7977 myStore.add(myNewRecord);
7978 </code></pre>
7979  * @method create
7980  * @static
7981  */
7982 Roo.data.Record.create = function(o){
7983     var f = function(){
7984         f.superclass.constructor.apply(this, arguments);
7985     };
7986     Roo.extend(f, Roo.data.Record);
7987     var p = f.prototype;
7988     p.fields = new Roo.util.MixedCollection(false, function(field){
7989         return field.name;
7990     });
7991     for(var i = 0, len = o.length; i < len; i++){
7992         p.fields.add(new Roo.data.Field(o[i]));
7993     }
7994     f.getField = function(name){
7995         return p.fields.get(name);  
7996     };
7997     return f;
7998 };
7999
8000 Roo.data.Record.AUTO_ID = 1000;
8001 Roo.data.Record.EDIT = 'edit';
8002 Roo.data.Record.REJECT = 'reject';
8003 Roo.data.Record.COMMIT = 'commit';
8004
8005 Roo.data.Record.prototype = {
8006     /**
8007      * Readonly flag - true if this record has been modified.
8008      * @type Boolean
8009      */
8010     dirty : false,
8011     editing : false,
8012     error: null,
8013     modified: null,
8014
8015     // private
8016     join : function(store){
8017         this.store = store;
8018     },
8019
8020     /**
8021      * Set the named field to the specified value.
8022      * @param {String} name The name of the field to set.
8023      * @param {Object} value The value to set the field to.
8024      */
8025     set : function(name, value){
8026         if(this.data[name] == value){
8027             return;
8028         }
8029         this.dirty = true;
8030         if(!this.modified){
8031             this.modified = {};
8032         }
8033         if(typeof this.modified[name] == 'undefined'){
8034             this.modified[name] = this.data[name];
8035         }
8036         this.data[name] = value;
8037         if(!this.editing && this.store){
8038             this.store.afterEdit(this);
8039         }       
8040     },
8041
8042     /**
8043      * Get the value of the named field.
8044      * @param {String} name The name of the field to get the value of.
8045      * @return {Object} The value of the field.
8046      */
8047     get : function(name){
8048         return this.data[name]; 
8049     },
8050
8051     // private
8052     beginEdit : function(){
8053         this.editing = true;
8054         this.modified = {}; 
8055     },
8056
8057     // private
8058     cancelEdit : function(){
8059         this.editing = false;
8060         delete this.modified;
8061     },
8062
8063     // private
8064     endEdit : function(){
8065         this.editing = false;
8066         if(this.dirty && this.store){
8067             this.store.afterEdit(this);
8068         }
8069     },
8070
8071     /**
8072      * Usually called by the {@link Roo.data.Store} which owns the Record.
8073      * Rejects all changes made to the Record since either creation, or the last commit operation.
8074      * Modified fields are reverted to their original values.
8075      * <p>
8076      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8077      * of reject operations.
8078      */
8079     reject : function(){
8080         var m = this.modified;
8081         for(var n in m){
8082             if(typeof m[n] != "function"){
8083                 this.data[n] = m[n];
8084             }
8085         }
8086         this.dirty = false;
8087         delete this.modified;
8088         this.editing = false;
8089         if(this.store){
8090             this.store.afterReject(this);
8091         }
8092     },
8093
8094     /**
8095      * Usually called by the {@link Roo.data.Store} which owns the Record.
8096      * Commits all changes made to the Record since either creation, or the last commit operation.
8097      * <p>
8098      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8099      * of commit operations.
8100      */
8101     commit : function(){
8102         this.dirty = false;
8103         delete this.modified;
8104         this.editing = false;
8105         if(this.store){
8106             this.store.afterCommit(this);
8107         }
8108     },
8109
8110     // private
8111     hasError : function(){
8112         return this.error != null;
8113     },
8114
8115     // private
8116     clearError : function(){
8117         this.error = null;
8118     },
8119
8120     /**
8121      * Creates a copy of this record.
8122      * @param {String} id (optional) A new record id if you don't want to use this record's id
8123      * @return {Record}
8124      */
8125     copy : function(newId) {
8126         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8127     }
8128 };/*
8129  * Based on:
8130  * Ext JS Library 1.1.1
8131  * Copyright(c) 2006-2007, Ext JS, LLC.
8132  *
8133  * Originally Released Under LGPL - original licence link has changed is not relivant.
8134  *
8135  * Fork - LGPL
8136  * <script type="text/javascript">
8137  */
8138
8139
8140
8141 /**
8142  * @class Roo.data.Store
8143  * @extends Roo.util.Observable
8144  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8145  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8146  * <p>
8147  * 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
8148  * has no knowledge of the format of the data returned by the Proxy.<br>
8149  * <p>
8150  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8151  * instances from the data object. These records are cached and made available through accessor functions.
8152  * @constructor
8153  * Creates a new Store.
8154  * @param {Object} config A config object containing the objects needed for the Store to access data,
8155  * and read the data into Records.
8156  */
8157 Roo.data.Store = function(config){
8158     this.data = new Roo.util.MixedCollection(false);
8159     this.data.getKey = function(o){
8160         return o.id;
8161     };
8162     this.baseParams = {};
8163     // private
8164     this.paramNames = {
8165         "start" : "start",
8166         "limit" : "limit",
8167         "sort" : "sort",
8168         "dir" : "dir",
8169         "multisort" : "_multisort"
8170     };
8171
8172     if(config && config.data){
8173         this.inlineData = config.data;
8174         delete config.data;
8175     }
8176
8177     Roo.apply(this, config);
8178     
8179     if(this.reader){ // reader passed
8180         this.reader = Roo.factory(this.reader, Roo.data);
8181         this.reader.xmodule = this.xmodule || false;
8182         if(!this.recordType){
8183             this.recordType = this.reader.recordType;
8184         }
8185         if(this.reader.onMetaChange){
8186             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8187         }
8188     }
8189
8190     if(this.recordType){
8191         this.fields = this.recordType.prototype.fields;
8192     }
8193     this.modified = [];
8194
8195     this.addEvents({
8196         /**
8197          * @event datachanged
8198          * Fires when the data cache has changed, and a widget which is using this Store
8199          * as a Record cache should refresh its view.
8200          * @param {Store} this
8201          */
8202         datachanged : true,
8203         /**
8204          * @event metachange
8205          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8206          * @param {Store} this
8207          * @param {Object} meta The JSON metadata
8208          */
8209         metachange : true,
8210         /**
8211          * @event add
8212          * Fires when Records have been added to the Store
8213          * @param {Store} this
8214          * @param {Roo.data.Record[]} records The array of Records added
8215          * @param {Number} index The index at which the record(s) were added
8216          */
8217         add : true,
8218         /**
8219          * @event remove
8220          * Fires when a Record has been removed from the Store
8221          * @param {Store} this
8222          * @param {Roo.data.Record} record The Record that was removed
8223          * @param {Number} index The index at which the record was removed
8224          */
8225         remove : true,
8226         /**
8227          * @event update
8228          * Fires when a Record has been updated
8229          * @param {Store} this
8230          * @param {Roo.data.Record} record The Record that was updated
8231          * @param {String} operation The update operation being performed.  Value may be one of:
8232          * <pre><code>
8233  Roo.data.Record.EDIT
8234  Roo.data.Record.REJECT
8235  Roo.data.Record.COMMIT
8236          * </code></pre>
8237          */
8238         update : true,
8239         /**
8240          * @event clear
8241          * Fires when the data cache has been cleared.
8242          * @param {Store} this
8243          */
8244         clear : true,
8245         /**
8246          * @event beforeload
8247          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8248          * the load action will be canceled.
8249          * @param {Store} this
8250          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8251          */
8252         beforeload : true,
8253         /**
8254          * @event beforeloadadd
8255          * Fires after a new set of Records has been loaded.
8256          * @param {Store} this
8257          * @param {Roo.data.Record[]} records The Records that were loaded
8258          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8259          */
8260         beforeloadadd : true,
8261         /**
8262          * @event load
8263          * Fires after a new set of Records has been loaded, before they are added to the store.
8264          * @param {Store} this
8265          * @param {Roo.data.Record[]} records The Records that were loaded
8266          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8267          * @params {Object} return from reader
8268          */
8269         load : true,
8270         /**
8271          * @event loadexception
8272          * Fires if an exception occurs in the Proxy during loading.
8273          * Called with the signature of the Proxy's "loadexception" event.
8274          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8275          * 
8276          * @param {Proxy} 
8277          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8278          * @param {Object} load options 
8279          * @param {Object} jsonData from your request (normally this contains the Exception)
8280          */
8281         loadexception : true
8282     });
8283     
8284     if(this.proxy){
8285         this.proxy = Roo.factory(this.proxy, Roo.data);
8286         this.proxy.xmodule = this.xmodule || false;
8287         this.relayEvents(this.proxy,  ["loadexception"]);
8288     }
8289     this.sortToggle = {};
8290     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8291
8292     Roo.data.Store.superclass.constructor.call(this);
8293
8294     if(this.inlineData){
8295         this.loadData(this.inlineData);
8296         delete this.inlineData;
8297     }
8298 };
8299
8300 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8301      /**
8302     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8303     * without a remote query - used by combo/forms at present.
8304     */
8305     
8306     /**
8307     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8308     */
8309     /**
8310     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8311     */
8312     /**
8313     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8314     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8315     */
8316     /**
8317     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8318     * on any HTTP request
8319     */
8320     /**
8321     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8322     */
8323     /**
8324     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8325     */
8326     multiSort: false,
8327     /**
8328     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8329     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8330     */
8331     remoteSort : false,
8332
8333     /**
8334     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8335      * loaded or when a record is removed. (defaults to false).
8336     */
8337     pruneModifiedRecords : false,
8338
8339     // private
8340     lastOptions : null,
8341
8342     /**
8343      * Add Records to the Store and fires the add event.
8344      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8345      */
8346     add : function(records){
8347         records = [].concat(records);
8348         for(var i = 0, len = records.length; i < len; i++){
8349             records[i].join(this);
8350         }
8351         var index = this.data.length;
8352         this.data.addAll(records);
8353         this.fireEvent("add", this, records, index);
8354     },
8355
8356     /**
8357      * Remove a Record from the Store and fires the remove event.
8358      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8359      */
8360     remove : function(record){
8361         var index = this.data.indexOf(record);
8362         this.data.removeAt(index);
8363         if(this.pruneModifiedRecords){
8364             this.modified.remove(record);
8365         }
8366         this.fireEvent("remove", this, record, index);
8367     },
8368
8369     /**
8370      * Remove all Records from the Store and fires the clear event.
8371      */
8372     removeAll : function(){
8373         this.data.clear();
8374         if(this.pruneModifiedRecords){
8375             this.modified = [];
8376         }
8377         this.fireEvent("clear", this);
8378     },
8379
8380     /**
8381      * Inserts Records to the Store at the given index and fires the add event.
8382      * @param {Number} index The start index at which to insert the passed Records.
8383      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8384      */
8385     insert : function(index, records){
8386         records = [].concat(records);
8387         for(var i = 0, len = records.length; i < len; i++){
8388             this.data.insert(index, records[i]);
8389             records[i].join(this);
8390         }
8391         this.fireEvent("add", this, records, index);
8392     },
8393
8394     /**
8395      * Get the index within the cache of the passed Record.
8396      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8397      * @return {Number} The index of the passed Record. Returns -1 if not found.
8398      */
8399     indexOf : function(record){
8400         return this.data.indexOf(record);
8401     },
8402
8403     /**
8404      * Get the index within the cache of the Record with the passed id.
8405      * @param {String} id The id of the Record to find.
8406      * @return {Number} The index of the Record. Returns -1 if not found.
8407      */
8408     indexOfId : function(id){
8409         return this.data.indexOfKey(id);
8410     },
8411
8412     /**
8413      * Get the Record with the specified id.
8414      * @param {String} id The id of the Record to find.
8415      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8416      */
8417     getById : function(id){
8418         return this.data.key(id);
8419     },
8420
8421     /**
8422      * Get the Record at the specified index.
8423      * @param {Number} index The index of the Record to find.
8424      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8425      */
8426     getAt : function(index){
8427         return this.data.itemAt(index);
8428     },
8429
8430     /**
8431      * Returns a range of Records between specified indices.
8432      * @param {Number} startIndex (optional) The starting index (defaults to 0)
8433      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8434      * @return {Roo.data.Record[]} An array of Records
8435      */
8436     getRange : function(start, end){
8437         return this.data.getRange(start, end);
8438     },
8439
8440     // private
8441     storeOptions : function(o){
8442         o = Roo.apply({}, o);
8443         delete o.callback;
8444         delete o.scope;
8445         this.lastOptions = o;
8446     },
8447
8448     /**
8449      * Loads the Record cache from the configured Proxy using the configured Reader.
8450      * <p>
8451      * If using remote paging, then the first load call must specify the <em>start</em>
8452      * and <em>limit</em> properties in the options.params property to establish the initial
8453      * position within the dataset, and the number of Records to cache on each read from the Proxy.
8454      * <p>
8455      * <strong>It is important to note that for remote data sources, loading is asynchronous,
8456      * and this call will return before the new data has been loaded. Perform any post-processing
8457      * in a callback function, or in a "load" event handler.</strong>
8458      * <p>
8459      * @param {Object} options An object containing properties which control loading options:<ul>
8460      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8461      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8462      * passed the following arguments:<ul>
8463      * <li>r : Roo.data.Record[]</li>
8464      * <li>options: Options object from the load call</li>
8465      * <li>success: Boolean success indicator</li></ul></li>
8466      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8467      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8468      * </ul>
8469      */
8470     load : function(options){
8471         options = options || {};
8472         if(this.fireEvent("beforeload", this, options) !== false){
8473             this.storeOptions(options);
8474             var p = Roo.apply(options.params || {}, this.baseParams);
8475             // if meta was not loaded from remote source.. try requesting it.
8476             if (!this.reader.metaFromRemote) {
8477                 p._requestMeta = 1;
8478             }
8479             if(this.sortInfo && this.remoteSort){
8480                 var pn = this.paramNames;
8481                 p[pn["sort"]] = this.sortInfo.field;
8482                 p[pn["dir"]] = this.sortInfo.direction;
8483             }
8484             if (this.multiSort) {
8485                 var pn = this.paramNames;
8486                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8487             }
8488             
8489             this.proxy.load(p, this.reader, this.loadRecords, this, options);
8490         }
8491     },
8492
8493     /**
8494      * Reloads the Record cache from the configured Proxy using the configured Reader and
8495      * the options from the last load operation performed.
8496      * @param {Object} options (optional) An object containing properties which may override the options
8497      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8498      * the most recently used options are reused).
8499      */
8500     reload : function(options){
8501         this.load(Roo.applyIf(options||{}, this.lastOptions));
8502     },
8503
8504     // private
8505     // Called as a callback by the Reader during a load operation.
8506     loadRecords : function(o, options, success){
8507         if(!o || success === false){
8508             if(success !== false){
8509                 this.fireEvent("load", this, [], options, o);
8510             }
8511             if(options.callback){
8512                 options.callback.call(options.scope || this, [], options, false);
8513             }
8514             return;
8515         }
8516         // if data returned failure - throw an exception.
8517         if (o.success === false) {
8518             // show a message if no listener is registered.
8519             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8520                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8521             }
8522             // loadmask wil be hooked into this..
8523             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8524             return;
8525         }
8526         var r = o.records, t = o.totalRecords || r.length;
8527         
8528         this.fireEvent("beforeloadadd", this, r, options, o);
8529         
8530         if(!options || options.add !== true){
8531             if(this.pruneModifiedRecords){
8532                 this.modified = [];
8533             }
8534             for(var i = 0, len = r.length; i < len; i++){
8535                 r[i].join(this);
8536             }
8537             if(this.snapshot){
8538                 this.data = this.snapshot;
8539                 delete this.snapshot;
8540             }
8541             this.data.clear();
8542             this.data.addAll(r);
8543             this.totalLength = t;
8544             this.applySort();
8545             this.fireEvent("datachanged", this);
8546         }else{
8547             this.totalLength = Math.max(t, this.data.length+r.length);
8548             this.add(r);
8549         }
8550         this.fireEvent("load", this, r, options, o);
8551         if(options.callback){
8552             options.callback.call(options.scope || this, r, options, true);
8553         }
8554     },
8555
8556
8557     /**
8558      * Loads data from a passed data block. A Reader which understands the format of the data
8559      * must have been configured in the constructor.
8560      * @param {Object} data The data block from which to read the Records.  The format of the data expected
8561      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8562      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8563      */
8564     loadData : function(o, append){
8565         var r = this.reader.readRecords(o);
8566         this.loadRecords(r, {add: append}, true);
8567     },
8568
8569     /**
8570      * Gets the number of cached records.
8571      * <p>
8572      * <em>If using paging, this may not be the total size of the dataset. If the data object
8573      * used by the Reader contains the dataset size, then the getTotalCount() function returns
8574      * the data set size</em>
8575      */
8576     getCount : function(){
8577         return this.data.length || 0;
8578     },
8579
8580     /**
8581      * Gets the total number of records in the dataset as returned by the server.
8582      * <p>
8583      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8584      * the dataset size</em>
8585      */
8586     getTotalCount : function(){
8587         return this.totalLength || 0;
8588     },
8589
8590     /**
8591      * Returns the sort state of the Store as an object with two properties:
8592      * <pre><code>
8593  field {String} The name of the field by which the Records are sorted
8594  direction {String} The sort order, "ASC" or "DESC"
8595      * </code></pre>
8596      */
8597     getSortState : function(){
8598         return this.sortInfo;
8599     },
8600
8601     // private
8602     applySort : function(){
8603         if(this.sortInfo && !this.remoteSort){
8604             var s = this.sortInfo, f = s.field;
8605             var st = this.fields.get(f).sortType;
8606             var fn = function(r1, r2){
8607                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8608                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8609             };
8610             this.data.sort(s.direction, fn);
8611             if(this.snapshot && this.snapshot != this.data){
8612                 this.snapshot.sort(s.direction, fn);
8613             }
8614         }
8615     },
8616
8617     /**
8618      * Sets the default sort column and order to be used by the next load operation.
8619      * @param {String} fieldName The name of the field to sort by.
8620      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8621      */
8622     setDefaultSort : function(field, dir){
8623         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8624     },
8625
8626     /**
8627      * Sort the Records.
8628      * If remote sorting is used, the sort is performed on the server, and the cache is
8629      * reloaded. If local sorting is used, the cache is sorted internally.
8630      * @param {String} fieldName The name of the field to sort by.
8631      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8632      */
8633     sort : function(fieldName, dir){
8634         var f = this.fields.get(fieldName);
8635         if(!dir){
8636             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8637             
8638             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8639                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8640             }else{
8641                 dir = f.sortDir;
8642             }
8643         }
8644         this.sortToggle[f.name] = dir;
8645         this.sortInfo = {field: f.name, direction: dir};
8646         if(!this.remoteSort){
8647             this.applySort();
8648             this.fireEvent("datachanged", this);
8649         }else{
8650             this.load(this.lastOptions);
8651         }
8652     },
8653
8654     /**
8655      * Calls the specified function for each of the Records in the cache.
8656      * @param {Function} fn The function to call. The Record is passed as the first parameter.
8657      * Returning <em>false</em> aborts and exits the iteration.
8658      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8659      */
8660     each : function(fn, scope){
8661         this.data.each(fn, scope);
8662     },
8663
8664     /**
8665      * Gets all records modified since the last commit.  Modified records are persisted across load operations
8666      * (e.g., during paging).
8667      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8668      */
8669     getModifiedRecords : function(){
8670         return this.modified;
8671     },
8672
8673     // private
8674     createFilterFn : function(property, value, anyMatch){
8675         if(!value.exec){ // not a regex
8676             value = String(value);
8677             if(value.length == 0){
8678                 return false;
8679             }
8680             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8681         }
8682         return function(r){
8683             return value.test(r.data[property]);
8684         };
8685     },
8686
8687     /**
8688      * Sums the value of <i>property</i> for each record between start and end and returns the result.
8689      * @param {String} property A field on your records
8690      * @param {Number} start The record index to start at (defaults to 0)
8691      * @param {Number} end The last record index to include (defaults to length - 1)
8692      * @return {Number} The sum
8693      */
8694     sum : function(property, start, end){
8695         var rs = this.data.items, v = 0;
8696         start = start || 0;
8697         end = (end || end === 0) ? end : rs.length-1;
8698
8699         for(var i = start; i <= end; i++){
8700             v += (rs[i].data[property] || 0);
8701         }
8702         return v;
8703     },
8704
8705     /**
8706      * Filter the records by a specified property.
8707      * @param {String} field A field on your records
8708      * @param {String/RegExp} value Either a string that the field
8709      * should start with or a RegExp to test against the field
8710      * @param {Boolean} anyMatch True to match any part not just the beginning
8711      */
8712     filter : function(property, value, anyMatch){
8713         var fn = this.createFilterFn(property, value, anyMatch);
8714         return fn ? this.filterBy(fn) : this.clearFilter();
8715     },
8716
8717     /**
8718      * Filter by a function. The specified function will be called with each
8719      * record in this data source. If the function returns true the record is included,
8720      * otherwise it is filtered.
8721      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8722      * @param {Object} scope (optional) The scope of the function (defaults to this)
8723      */
8724     filterBy : function(fn, scope){
8725         this.snapshot = this.snapshot || this.data;
8726         this.data = this.queryBy(fn, scope||this);
8727         this.fireEvent("datachanged", this);
8728     },
8729
8730     /**
8731      * Query the records by a specified property.
8732      * @param {String} field A field on your records
8733      * @param {String/RegExp} value Either a string that the field
8734      * should start with or a RegExp to test against the field
8735      * @param {Boolean} anyMatch True to match any part not just the beginning
8736      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8737      */
8738     query : function(property, value, anyMatch){
8739         var fn = this.createFilterFn(property, value, anyMatch);
8740         return fn ? this.queryBy(fn) : this.data.clone();
8741     },
8742
8743     /**
8744      * Query by a function. The specified function will be called with each
8745      * record in this data source. If the function returns true the record is included
8746      * in the results.
8747      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8748      * @param {Object} scope (optional) The scope of the function (defaults to this)
8749       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8750      **/
8751     queryBy : function(fn, scope){
8752         var data = this.snapshot || this.data;
8753         return data.filterBy(fn, scope||this);
8754     },
8755
8756     /**
8757      * Collects unique values for a particular dataIndex from this store.
8758      * @param {String} dataIndex The property to collect
8759      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8760      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8761      * @return {Array} An array of the unique values
8762      **/
8763     collect : function(dataIndex, allowNull, bypassFilter){
8764         var d = (bypassFilter === true && this.snapshot) ?
8765                 this.snapshot.items : this.data.items;
8766         var v, sv, r = [], l = {};
8767         for(var i = 0, len = d.length; i < len; i++){
8768             v = d[i].data[dataIndex];
8769             sv = String(v);
8770             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8771                 l[sv] = true;
8772                 r[r.length] = v;
8773             }
8774         }
8775         return r;
8776     },
8777
8778     /**
8779      * Revert to a view of the Record cache with no filtering applied.
8780      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8781      */
8782     clearFilter : function(suppressEvent){
8783         if(this.snapshot && this.snapshot != this.data){
8784             this.data = this.snapshot;
8785             delete this.snapshot;
8786             if(suppressEvent !== true){
8787                 this.fireEvent("datachanged", this);
8788             }
8789         }
8790     },
8791
8792     // private
8793     afterEdit : function(record){
8794         if(this.modified.indexOf(record) == -1){
8795             this.modified.push(record);
8796         }
8797         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8798     },
8799     
8800     // private
8801     afterReject : function(record){
8802         this.modified.remove(record);
8803         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8804     },
8805
8806     // private
8807     afterCommit : function(record){
8808         this.modified.remove(record);
8809         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8810     },
8811
8812     /**
8813      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8814      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8815      */
8816     commitChanges : function(){
8817         var m = this.modified.slice(0);
8818         this.modified = [];
8819         for(var i = 0, len = m.length; i < len; i++){
8820             m[i].commit();
8821         }
8822     },
8823
8824     /**
8825      * Cancel outstanding changes on all changed records.
8826      */
8827     rejectChanges : function(){
8828         var m = this.modified.slice(0);
8829         this.modified = [];
8830         for(var i = 0, len = m.length; i < len; i++){
8831             m[i].reject();
8832         }
8833     },
8834
8835     onMetaChange : function(meta, rtype, o){
8836         this.recordType = rtype;
8837         this.fields = rtype.prototype.fields;
8838         delete this.snapshot;
8839         this.sortInfo = meta.sortInfo || this.sortInfo;
8840         this.modified = [];
8841         this.fireEvent('metachange', this, this.reader.meta);
8842     },
8843     
8844     moveIndex : function(data, type)
8845     {
8846         var index = this.indexOf(data);
8847         
8848         var newIndex = index + type;
8849         
8850         this.remove(data);
8851         
8852         this.insert(newIndex, data);
8853         
8854     }
8855 });/*
8856  * Based on:
8857  * Ext JS Library 1.1.1
8858  * Copyright(c) 2006-2007, Ext JS, LLC.
8859  *
8860  * Originally Released Under LGPL - original licence link has changed is not relivant.
8861  *
8862  * Fork - LGPL
8863  * <script type="text/javascript">
8864  */
8865
8866 /**
8867  * @class Roo.data.SimpleStore
8868  * @extends Roo.data.Store
8869  * Small helper class to make creating Stores from Array data easier.
8870  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8871  * @cfg {Array} fields An array of field definition objects, or field name strings.
8872  * @cfg {Array} data The multi-dimensional array of data
8873  * @constructor
8874  * @param {Object} config
8875  */
8876 Roo.data.SimpleStore = function(config){
8877     Roo.data.SimpleStore.superclass.constructor.call(this, {
8878         isLocal : true,
8879         reader: new Roo.data.ArrayReader({
8880                 id: config.id
8881             },
8882             Roo.data.Record.create(config.fields)
8883         ),
8884         proxy : new Roo.data.MemoryProxy(config.data)
8885     });
8886     this.load();
8887 };
8888 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8889  * Based on:
8890  * Ext JS Library 1.1.1
8891  * Copyright(c) 2006-2007, Ext JS, LLC.
8892  *
8893  * Originally Released Under LGPL - original licence link has changed is not relivant.
8894  *
8895  * Fork - LGPL
8896  * <script type="text/javascript">
8897  */
8898
8899 /**
8900 /**
8901  * @extends Roo.data.Store
8902  * @class Roo.data.JsonStore
8903  * Small helper class to make creating Stores for JSON data easier. <br/>
8904 <pre><code>
8905 var store = new Roo.data.JsonStore({
8906     url: 'get-images.php',
8907     root: 'images',
8908     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8909 });
8910 </code></pre>
8911  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8912  * JsonReader and HttpProxy (unless inline data is provided).</b>
8913  * @cfg {Array} fields An array of field definition objects, or field name strings.
8914  * @constructor
8915  * @param {Object} config
8916  */
8917 Roo.data.JsonStore = function(c){
8918     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8919         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8920         reader: new Roo.data.JsonReader(c, c.fields)
8921     }));
8922 };
8923 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8924  * Based on:
8925  * Ext JS Library 1.1.1
8926  * Copyright(c) 2006-2007, Ext JS, LLC.
8927  *
8928  * Originally Released Under LGPL - original licence link has changed is not relivant.
8929  *
8930  * Fork - LGPL
8931  * <script type="text/javascript">
8932  */
8933
8934  
8935 Roo.data.Field = function(config){
8936     if(typeof config == "string"){
8937         config = {name: config};
8938     }
8939     Roo.apply(this, config);
8940     
8941     if(!this.type){
8942         this.type = "auto";
8943     }
8944     
8945     var st = Roo.data.SortTypes;
8946     // named sortTypes are supported, here we look them up
8947     if(typeof this.sortType == "string"){
8948         this.sortType = st[this.sortType];
8949     }
8950     
8951     // set default sortType for strings and dates
8952     if(!this.sortType){
8953         switch(this.type){
8954             case "string":
8955                 this.sortType = st.asUCString;
8956                 break;
8957             case "date":
8958                 this.sortType = st.asDate;
8959                 break;
8960             default:
8961                 this.sortType = st.none;
8962         }
8963     }
8964
8965     // define once
8966     var stripRe = /[\$,%]/g;
8967
8968     // prebuilt conversion function for this field, instead of
8969     // switching every time we're reading a value
8970     if(!this.convert){
8971         var cv, dateFormat = this.dateFormat;
8972         switch(this.type){
8973             case "":
8974             case "auto":
8975             case undefined:
8976                 cv = function(v){ return v; };
8977                 break;
8978             case "string":
8979                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8980                 break;
8981             case "int":
8982                 cv = function(v){
8983                     return v !== undefined && v !== null && v !== '' ?
8984                            parseInt(String(v).replace(stripRe, ""), 10) : '';
8985                     };
8986                 break;
8987             case "float":
8988                 cv = function(v){
8989                     return v !== undefined && v !== null && v !== '' ?
8990                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
8991                     };
8992                 break;
8993             case "bool":
8994             case "boolean":
8995                 cv = function(v){ return v === true || v === "true" || v == 1; };
8996                 break;
8997             case "date":
8998                 cv = function(v){
8999                     if(!v){
9000                         return '';
9001                     }
9002                     if(v instanceof Date){
9003                         return v;
9004                     }
9005                     if(dateFormat){
9006                         if(dateFormat == "timestamp"){
9007                             return new Date(v*1000);
9008                         }
9009                         return Date.parseDate(v, dateFormat);
9010                     }
9011                     var parsed = Date.parse(v);
9012                     return parsed ? new Date(parsed) : null;
9013                 };
9014              break;
9015             
9016         }
9017         this.convert = cv;
9018     }
9019 };
9020
9021 Roo.data.Field.prototype = {
9022     dateFormat: null,
9023     defaultValue: "",
9024     mapping: null,
9025     sortType : null,
9026     sortDir : "ASC"
9027 };/*
9028  * Based on:
9029  * Ext JS Library 1.1.1
9030  * Copyright(c) 2006-2007, Ext JS, LLC.
9031  *
9032  * Originally Released Under LGPL - original licence link has changed is not relivant.
9033  *
9034  * Fork - LGPL
9035  * <script type="text/javascript">
9036  */
9037  
9038 // Base class for reading structured data from a data source.  This class is intended to be
9039 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9040
9041 /**
9042  * @class Roo.data.DataReader
9043  * Base class for reading structured data from a data source.  This class is intended to be
9044  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9045  */
9046
9047 Roo.data.DataReader = function(meta, recordType){
9048     
9049     this.meta = meta;
9050     
9051     this.recordType = recordType instanceof Array ? 
9052         Roo.data.Record.create(recordType) : recordType;
9053 };
9054
9055 Roo.data.DataReader.prototype = {
9056      /**
9057      * Create an empty record
9058      * @param {Object} data (optional) - overlay some values
9059      * @return {Roo.data.Record} record created.
9060      */
9061     newRow :  function(d) {
9062         var da =  {};
9063         this.recordType.prototype.fields.each(function(c) {
9064             switch( c.type) {
9065                 case 'int' : da[c.name] = 0; break;
9066                 case 'date' : da[c.name] = new Date(); break;
9067                 case 'float' : da[c.name] = 0.0; break;
9068                 case 'boolean' : da[c.name] = false; break;
9069                 default : da[c.name] = ""; break;
9070             }
9071             
9072         });
9073         return new this.recordType(Roo.apply(da, d));
9074     }
9075     
9076 };/*
9077  * Based on:
9078  * Ext JS Library 1.1.1
9079  * Copyright(c) 2006-2007, Ext JS, LLC.
9080  *
9081  * Originally Released Under LGPL - original licence link has changed is not relivant.
9082  *
9083  * Fork - LGPL
9084  * <script type="text/javascript">
9085  */
9086
9087 /**
9088  * @class Roo.data.DataProxy
9089  * @extends Roo.data.Observable
9090  * This class is an abstract base class for implementations which provide retrieval of
9091  * unformatted data objects.<br>
9092  * <p>
9093  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9094  * (of the appropriate type which knows how to parse the data object) to provide a block of
9095  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9096  * <p>
9097  * Custom implementations must implement the load method as described in
9098  * {@link Roo.data.HttpProxy#load}.
9099  */
9100 Roo.data.DataProxy = function(){
9101     this.addEvents({
9102         /**
9103          * @event beforeload
9104          * Fires before a network request is made to retrieve a data object.
9105          * @param {Object} This DataProxy object.
9106          * @param {Object} params The params parameter to the load function.
9107          */
9108         beforeload : true,
9109         /**
9110          * @event load
9111          * Fires before the load method's callback is called.
9112          * @param {Object} This DataProxy object.
9113          * @param {Object} o The data object.
9114          * @param {Object} arg The callback argument object passed to the load function.
9115          */
9116         load : true,
9117         /**
9118          * @event loadexception
9119          * Fires if an Exception occurs during data retrieval.
9120          * @param {Object} This DataProxy object.
9121          * @param {Object} o The data object.
9122          * @param {Object} arg The callback argument object passed to the load function.
9123          * @param {Object} e The Exception.
9124          */
9125         loadexception : true
9126     });
9127     Roo.data.DataProxy.superclass.constructor.call(this);
9128 };
9129
9130 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9131
9132     /**
9133      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9134      */
9135 /*
9136  * Based on:
9137  * Ext JS Library 1.1.1
9138  * Copyright(c) 2006-2007, Ext JS, LLC.
9139  *
9140  * Originally Released Under LGPL - original licence link has changed is not relivant.
9141  *
9142  * Fork - LGPL
9143  * <script type="text/javascript">
9144  */
9145 /**
9146  * @class Roo.data.MemoryProxy
9147  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9148  * to the Reader when its load method is called.
9149  * @constructor
9150  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9151  */
9152 Roo.data.MemoryProxy = function(data){
9153     if (data.data) {
9154         data = data.data;
9155     }
9156     Roo.data.MemoryProxy.superclass.constructor.call(this);
9157     this.data = data;
9158 };
9159
9160 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9161     /**
9162      * Load data from the requested source (in this case an in-memory
9163      * data object passed to the constructor), read the data object into
9164      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9165      * process that block using the passed callback.
9166      * @param {Object} params This parameter is not used by the MemoryProxy class.
9167      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9168      * object into a block of Roo.data.Records.
9169      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9170      * The function must be passed <ul>
9171      * <li>The Record block object</li>
9172      * <li>The "arg" argument from the load function</li>
9173      * <li>A boolean success indicator</li>
9174      * </ul>
9175      * @param {Object} scope The scope in which to call the callback
9176      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9177      */
9178     load : function(params, reader, callback, scope, arg){
9179         params = params || {};
9180         var result;
9181         try {
9182             result = reader.readRecords(this.data);
9183         }catch(e){
9184             this.fireEvent("loadexception", this, arg, null, e);
9185             callback.call(scope, null, arg, false);
9186             return;
9187         }
9188         callback.call(scope, result, arg, true);
9189     },
9190     
9191     // private
9192     update : function(params, records){
9193         
9194     }
9195 });/*
9196  * Based on:
9197  * Ext JS Library 1.1.1
9198  * Copyright(c) 2006-2007, Ext JS, LLC.
9199  *
9200  * Originally Released Under LGPL - original licence link has changed is not relivant.
9201  *
9202  * Fork - LGPL
9203  * <script type="text/javascript">
9204  */
9205 /**
9206  * @class Roo.data.HttpProxy
9207  * @extends Roo.data.DataProxy
9208  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9209  * configured to reference a certain URL.<br><br>
9210  * <p>
9211  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9212  * from which the running page was served.<br><br>
9213  * <p>
9214  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9215  * <p>
9216  * Be aware that to enable the browser to parse an XML document, the server must set
9217  * the Content-Type header in the HTTP response to "text/xml".
9218  * @constructor
9219  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9220  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9221  * will be used to make the request.
9222  */
9223 Roo.data.HttpProxy = function(conn){
9224     Roo.data.HttpProxy.superclass.constructor.call(this);
9225     // is conn a conn config or a real conn?
9226     this.conn = conn;
9227     this.useAjax = !conn || !conn.events;
9228   
9229 };
9230
9231 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9232     // thse are take from connection...
9233     
9234     /**
9235      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9236      */
9237     /**
9238      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9239      * extra parameters to each request made by this object. (defaults to undefined)
9240      */
9241     /**
9242      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9243      *  to each request made by this object. (defaults to undefined)
9244      */
9245     /**
9246      * @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)
9247      */
9248     /**
9249      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9250      */
9251      /**
9252      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9253      * @type Boolean
9254      */
9255   
9256
9257     /**
9258      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9259      * @type Boolean
9260      */
9261     /**
9262      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9263      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9264      * a finer-grained basis than the DataProxy events.
9265      */
9266     getConnection : function(){
9267         return this.useAjax ? Roo.Ajax : this.conn;
9268     },
9269
9270     /**
9271      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9272      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9273      * process that block using the passed callback.
9274      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9275      * for the request to the remote server.
9276      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9277      * object into a block of Roo.data.Records.
9278      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9279      * The function must be passed <ul>
9280      * <li>The Record block object</li>
9281      * <li>The "arg" argument from the load function</li>
9282      * <li>A boolean success indicator</li>
9283      * </ul>
9284      * @param {Object} scope The scope in which to call the callback
9285      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9286      */
9287     load : function(params, reader, callback, scope, arg){
9288         if(this.fireEvent("beforeload", this, params) !== false){
9289             var  o = {
9290                 params : params || {},
9291                 request: {
9292                     callback : callback,
9293                     scope : scope,
9294                     arg : arg
9295                 },
9296                 reader: reader,
9297                 callback : this.loadResponse,
9298                 scope: this
9299             };
9300             if(this.useAjax){
9301                 Roo.applyIf(o, this.conn);
9302                 if(this.activeRequest){
9303                     Roo.Ajax.abort(this.activeRequest);
9304                 }
9305                 this.activeRequest = Roo.Ajax.request(o);
9306             }else{
9307                 this.conn.request(o);
9308             }
9309         }else{
9310             callback.call(scope||this, null, arg, false);
9311         }
9312     },
9313
9314     // private
9315     loadResponse : function(o, success, response){
9316         delete this.activeRequest;
9317         if(!success){
9318             this.fireEvent("loadexception", this, o, response);
9319             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9320             return;
9321         }
9322         var result;
9323         try {
9324             result = o.reader.read(response);
9325         }catch(e){
9326             this.fireEvent("loadexception", this, o, response, e);
9327             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9328             return;
9329         }
9330         
9331         this.fireEvent("load", this, o, o.request.arg);
9332         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9333     },
9334
9335     // private
9336     update : function(dataSet){
9337
9338     },
9339
9340     // private
9341     updateResponse : function(dataSet){
9342
9343     }
9344 });/*
9345  * Based on:
9346  * Ext JS Library 1.1.1
9347  * Copyright(c) 2006-2007, Ext JS, LLC.
9348  *
9349  * Originally Released Under LGPL - original licence link has changed is not relivant.
9350  *
9351  * Fork - LGPL
9352  * <script type="text/javascript">
9353  */
9354
9355 /**
9356  * @class Roo.data.ScriptTagProxy
9357  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9358  * other than the originating domain of the running page.<br><br>
9359  * <p>
9360  * <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
9361  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9362  * <p>
9363  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9364  * source code that is used as the source inside a &lt;script> tag.<br><br>
9365  * <p>
9366  * In order for the browser to process the returned data, the server must wrap the data object
9367  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9368  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9369  * depending on whether the callback name was passed:
9370  * <p>
9371  * <pre><code>
9372 boolean scriptTag = false;
9373 String cb = request.getParameter("callback");
9374 if (cb != null) {
9375     scriptTag = true;
9376     response.setContentType("text/javascript");
9377 } else {
9378     response.setContentType("application/x-json");
9379 }
9380 Writer out = response.getWriter();
9381 if (scriptTag) {
9382     out.write(cb + "(");
9383 }
9384 out.print(dataBlock.toJsonString());
9385 if (scriptTag) {
9386     out.write(");");
9387 }
9388 </pre></code>
9389  *
9390  * @constructor
9391  * @param {Object} config A configuration object.
9392  */
9393 Roo.data.ScriptTagProxy = function(config){
9394     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9395     Roo.apply(this, config);
9396     this.head = document.getElementsByTagName("head")[0];
9397 };
9398
9399 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9400
9401 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9402     /**
9403      * @cfg {String} url The URL from which to request the data object.
9404      */
9405     /**
9406      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9407      */
9408     timeout : 30000,
9409     /**
9410      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9411      * the server the name of the callback function set up by the load call to process the returned data object.
9412      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9413      * javascript output which calls this named function passing the data object as its only parameter.
9414      */
9415     callbackParam : "callback",
9416     /**
9417      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9418      * name to the request.
9419      */
9420     nocache : true,
9421
9422     /**
9423      * Load data from the configured URL, read the data object into
9424      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9425      * process that block using the passed callback.
9426      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9427      * for the request to the remote server.
9428      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9429      * object into a block of Roo.data.Records.
9430      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9431      * The function must be passed <ul>
9432      * <li>The Record block object</li>
9433      * <li>The "arg" argument from the load function</li>
9434      * <li>A boolean success indicator</li>
9435      * </ul>
9436      * @param {Object} scope The scope in which to call the callback
9437      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9438      */
9439     load : function(params, reader, callback, scope, arg){
9440         if(this.fireEvent("beforeload", this, params) !== false){
9441
9442             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9443
9444             var url = this.url;
9445             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9446             if(this.nocache){
9447                 url += "&_dc=" + (new Date().getTime());
9448             }
9449             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9450             var trans = {
9451                 id : transId,
9452                 cb : "stcCallback"+transId,
9453                 scriptId : "stcScript"+transId,
9454                 params : params,
9455                 arg : arg,
9456                 url : url,
9457                 callback : callback,
9458                 scope : scope,
9459                 reader : reader
9460             };
9461             var conn = this;
9462
9463             window[trans.cb] = function(o){
9464                 conn.handleResponse(o, trans);
9465             };
9466
9467             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9468
9469             if(this.autoAbort !== false){
9470                 this.abort();
9471             }
9472
9473             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9474
9475             var script = document.createElement("script");
9476             script.setAttribute("src", url);
9477             script.setAttribute("type", "text/javascript");
9478             script.setAttribute("id", trans.scriptId);
9479             this.head.appendChild(script);
9480
9481             this.trans = trans;
9482         }else{
9483             callback.call(scope||this, null, arg, false);
9484         }
9485     },
9486
9487     // private
9488     isLoading : function(){
9489         return this.trans ? true : false;
9490     },
9491
9492     /**
9493      * Abort the current server request.
9494      */
9495     abort : function(){
9496         if(this.isLoading()){
9497             this.destroyTrans(this.trans);
9498         }
9499     },
9500
9501     // private
9502     destroyTrans : function(trans, isLoaded){
9503         this.head.removeChild(document.getElementById(trans.scriptId));
9504         clearTimeout(trans.timeoutId);
9505         if(isLoaded){
9506             window[trans.cb] = undefined;
9507             try{
9508                 delete window[trans.cb];
9509             }catch(e){}
9510         }else{
9511             // if hasn't been loaded, wait for load to remove it to prevent script error
9512             window[trans.cb] = function(){
9513                 window[trans.cb] = undefined;
9514                 try{
9515                     delete window[trans.cb];
9516                 }catch(e){}
9517             };
9518         }
9519     },
9520
9521     // private
9522     handleResponse : function(o, trans){
9523         this.trans = false;
9524         this.destroyTrans(trans, true);
9525         var result;
9526         try {
9527             result = trans.reader.readRecords(o);
9528         }catch(e){
9529             this.fireEvent("loadexception", this, o, trans.arg, e);
9530             trans.callback.call(trans.scope||window, null, trans.arg, false);
9531             return;
9532         }
9533         this.fireEvent("load", this, o, trans.arg);
9534         trans.callback.call(trans.scope||window, result, trans.arg, true);
9535     },
9536
9537     // private
9538     handleFailure : function(trans){
9539         this.trans = false;
9540         this.destroyTrans(trans, false);
9541         this.fireEvent("loadexception", this, null, trans.arg);
9542         trans.callback.call(trans.scope||window, null, trans.arg, false);
9543     }
9544 });/*
9545  * Based on:
9546  * Ext JS Library 1.1.1
9547  * Copyright(c) 2006-2007, Ext JS, LLC.
9548  *
9549  * Originally Released Under LGPL - original licence link has changed is not relivant.
9550  *
9551  * Fork - LGPL
9552  * <script type="text/javascript">
9553  */
9554
9555 /**
9556  * @class Roo.data.JsonReader
9557  * @extends Roo.data.DataReader
9558  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9559  * based on mappings in a provided Roo.data.Record constructor.
9560  * 
9561  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9562  * in the reply previously. 
9563  * 
9564  * <p>
9565  * Example code:
9566  * <pre><code>
9567 var RecordDef = Roo.data.Record.create([
9568     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
9569     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
9570 ]);
9571 var myReader = new Roo.data.JsonReader({
9572     totalProperty: "results",    // The property which contains the total dataset size (optional)
9573     root: "rows",                // The property which contains an Array of row objects
9574     id: "id"                     // The property within each row object that provides an ID for the record (optional)
9575 }, RecordDef);
9576 </code></pre>
9577  * <p>
9578  * This would consume a JSON file like this:
9579  * <pre><code>
9580 { 'results': 2, 'rows': [
9581     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9582     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9583 }
9584 </code></pre>
9585  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9586  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9587  * paged from the remote server.
9588  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9589  * @cfg {String} root name of the property which contains the Array of row objects.
9590  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9591  * @constructor
9592  * Create a new JsonReader
9593  * @param {Object} meta Metadata configuration options
9594  * @param {Object} recordType Either an Array of field definition objects,
9595  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9596  */
9597 Roo.data.JsonReader = function(meta, recordType){
9598     
9599     meta = meta || {};
9600     // set some defaults:
9601     Roo.applyIf(meta, {
9602         totalProperty: 'total',
9603         successProperty : 'success',
9604         root : 'data',
9605         id : 'id'
9606     });
9607     
9608     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9609 };
9610 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9611     
9612     /**
9613      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
9614      * Used by Store query builder to append _requestMeta to params.
9615      * 
9616      */
9617     metaFromRemote : false,
9618     /**
9619      * This method is only used by a DataProxy which has retrieved data from a remote server.
9620      * @param {Object} response The XHR object which contains the JSON data in its responseText.
9621      * @return {Object} data A data block which is used by an Roo.data.Store object as
9622      * a cache of Roo.data.Records.
9623      */
9624     read : function(response){
9625         var json = response.responseText;
9626        
9627         var o = /* eval:var:o */ eval("("+json+")");
9628         if(!o) {
9629             throw {message: "JsonReader.read: Json object not found"};
9630         }
9631         
9632         if(o.metaData){
9633             
9634             delete this.ef;
9635             this.metaFromRemote = true;
9636             this.meta = o.metaData;
9637             this.recordType = Roo.data.Record.create(o.metaData.fields);
9638             this.onMetaChange(this.meta, this.recordType, o);
9639         }
9640         return this.readRecords(o);
9641     },
9642
9643     // private function a store will implement
9644     onMetaChange : function(meta, recordType, o){
9645
9646     },
9647
9648     /**
9649          * @ignore
9650          */
9651     simpleAccess: function(obj, subsc) {
9652         return obj[subsc];
9653     },
9654
9655         /**
9656          * @ignore
9657          */
9658     getJsonAccessor: function(){
9659         var re = /[\[\.]/;
9660         return function(expr) {
9661             try {
9662                 return(re.test(expr))
9663                     ? new Function("obj", "return obj." + expr)
9664                     : function(obj){
9665                         return obj[expr];
9666                     };
9667             } catch(e){}
9668             return Roo.emptyFn;
9669         };
9670     }(),
9671
9672     /**
9673      * Create a data block containing Roo.data.Records from an XML document.
9674      * @param {Object} o An object which contains an Array of row objects in the property specified
9675      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9676      * which contains the total size of the dataset.
9677      * @return {Object} data A data block which is used by an Roo.data.Store object as
9678      * a cache of Roo.data.Records.
9679      */
9680     readRecords : function(o){
9681         /**
9682          * After any data loads, the raw JSON data is available for further custom processing.
9683          * @type Object
9684          */
9685         this.o = o;
9686         var s = this.meta, Record = this.recordType,
9687             f = Record.prototype.fields, fi = f.items, fl = f.length;
9688
9689 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
9690         if (!this.ef) {
9691             if(s.totalProperty) {
9692                     this.getTotal = this.getJsonAccessor(s.totalProperty);
9693                 }
9694                 if(s.successProperty) {
9695                     this.getSuccess = this.getJsonAccessor(s.successProperty);
9696                 }
9697                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9698                 if (s.id) {
9699                         var g = this.getJsonAccessor(s.id);
9700                         this.getId = function(rec) {
9701                                 var r = g(rec);
9702                                 return (r === undefined || r === "") ? null : r;
9703                         };
9704                 } else {
9705                         this.getId = function(){return null;};
9706                 }
9707             this.ef = [];
9708             for(var jj = 0; jj < fl; jj++){
9709                 f = fi[jj];
9710                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9711                 this.ef[jj] = this.getJsonAccessor(map);
9712             }
9713         }
9714
9715         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9716         if(s.totalProperty){
9717             var vt = parseInt(this.getTotal(o), 10);
9718             if(!isNaN(vt)){
9719                 totalRecords = vt;
9720             }
9721         }
9722         if(s.successProperty){
9723             var vs = this.getSuccess(o);
9724             if(vs === false || vs === 'false'){
9725                 success = false;
9726             }
9727         }
9728         var records = [];
9729             for(var i = 0; i < c; i++){
9730                     var n = root[i];
9731                 var values = {};
9732                 var id = this.getId(n);
9733                 for(var j = 0; j < fl; j++){
9734                     f = fi[j];
9735                 var v = this.ef[j](n);
9736                 if (!f.convert) {
9737                     Roo.log('missing convert for ' + f.name);
9738                     Roo.log(f);
9739                     continue;
9740                 }
9741                 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9742                 }
9743                 var record = new Record(values, id);
9744                 record.json = n;
9745                 records[i] = record;
9746             }
9747             return {
9748             raw : o,
9749                 success : success,
9750                 records : records,
9751                 totalRecords : totalRecords
9752             };
9753     }
9754 });/*
9755  * Based on:
9756  * Ext JS Library 1.1.1
9757  * Copyright(c) 2006-2007, Ext JS, LLC.
9758  *
9759  * Originally Released Under LGPL - original licence link has changed is not relivant.
9760  *
9761  * Fork - LGPL
9762  * <script type="text/javascript">
9763  */
9764
9765 /**
9766  * @class Roo.data.ArrayReader
9767  * @extends Roo.data.DataReader
9768  * Data reader class to create an Array of Roo.data.Record objects from an Array.
9769  * Each element of that Array represents a row of data fields. The
9770  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9771  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9772  * <p>
9773  * Example code:.
9774  * <pre><code>
9775 var RecordDef = Roo.data.Record.create([
9776     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
9777     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
9778 ]);
9779 var myReader = new Roo.data.ArrayReader({
9780     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
9781 }, RecordDef);
9782 </code></pre>
9783  * <p>
9784  * This would consume an Array like this:
9785  * <pre><code>
9786 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9787   </code></pre>
9788  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9789  * @constructor
9790  * Create a new JsonReader
9791  * @param {Object} meta Metadata configuration options.
9792  * @param {Object} recordType Either an Array of field definition objects
9793  * as specified to {@link Roo.data.Record#create},
9794  * or an {@link Roo.data.Record} object
9795  * created using {@link Roo.data.Record#create}.
9796  */
9797 Roo.data.ArrayReader = function(meta, recordType){
9798     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9799 };
9800
9801 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9802     /**
9803      * Create a data block containing Roo.data.Records from an XML document.
9804      * @param {Object} o An Array of row objects which represents the dataset.
9805      * @return {Object} data A data block which is used by an Roo.data.Store object as
9806      * a cache of Roo.data.Records.
9807      */
9808     readRecords : function(o){
9809         var sid = this.meta ? this.meta.id : null;
9810         var recordType = this.recordType, fields = recordType.prototype.fields;
9811         var records = [];
9812         var root = o;
9813             for(var i = 0; i < root.length; i++){
9814                     var n = root[i];
9815                 var values = {};
9816                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9817                 for(var j = 0, jlen = fields.length; j < jlen; j++){
9818                 var f = fields.items[j];
9819                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9820                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9821                 v = f.convert(v);
9822                 values[f.name] = v;
9823             }
9824                 var record = new recordType(values, id);
9825                 record.json = n;
9826                 records[records.length] = record;
9827             }
9828             return {
9829                 records : records,
9830                 totalRecords : records.length
9831             };
9832     }
9833 });/*
9834  * - LGPL
9835  * * 
9836  */
9837
9838 /**
9839  * @class Roo.bootstrap.ComboBox
9840  * @extends Roo.bootstrap.TriggerField
9841  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9842  * @cfg {Boolean} append (true|false) default false
9843  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9844  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
9845  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
9846  * @constructor
9847  * Create a new ComboBox.
9848  * @param {Object} config Configuration options
9849  */
9850 Roo.bootstrap.ComboBox = function(config){
9851     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9852     this.addEvents({
9853         /**
9854          * @event expand
9855          * Fires when the dropdown list is expanded
9856              * @param {Roo.bootstrap.ComboBox} combo This combo box
9857              */
9858         'expand' : true,
9859         /**
9860          * @event collapse
9861          * Fires when the dropdown list is collapsed
9862              * @param {Roo.bootstrap.ComboBox} combo This combo box
9863              */
9864         'collapse' : true,
9865         /**
9866          * @event beforeselect
9867          * Fires before a list item is selected. Return false to cancel the selection.
9868              * @param {Roo.bootstrap.ComboBox} combo This combo box
9869              * @param {Roo.data.Record} record The data record returned from the underlying store
9870              * @param {Number} index The index of the selected item in the dropdown list
9871              */
9872         'beforeselect' : true,
9873         /**
9874          * @event select
9875          * Fires when a list item is selected
9876              * @param {Roo.bootstrap.ComboBox} combo This combo box
9877              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9878              * @param {Number} index The index of the selected item in the dropdown list
9879              */
9880         'select' : true,
9881         /**
9882          * @event beforequery
9883          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9884          * The event object passed has these properties:
9885              * @param {Roo.bootstrap.ComboBox} combo This combo box
9886              * @param {String} query The query
9887              * @param {Boolean} forceAll true to force "all" query
9888              * @param {Boolean} cancel true to cancel the query
9889              * @param {Object} e The query event object
9890              */
9891         'beforequery': true,
9892          /**
9893          * @event add
9894          * Fires when the 'add' icon is pressed (add a listener to enable add button)
9895              * @param {Roo.bootstrap.ComboBox} combo This combo box
9896              */
9897         'add' : true,
9898         /**
9899          * @event edit
9900          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9901              * @param {Roo.bootstrap.ComboBox} combo This combo box
9902              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9903              */
9904         'edit' : true,
9905         /**
9906          * @event remove
9907          * Fires when the remove value from the combobox array
9908              * @param {Roo.bootstrap.ComboBox} combo This combo box
9909              */
9910         'remove' : true
9911         
9912     });
9913     
9914     this.item = [];
9915     this.tickItems = [];
9916     
9917     this.selectedIndex = -1;
9918     if(this.mode == 'local'){
9919         if(config.queryDelay === undefined){
9920             this.queryDelay = 10;
9921         }
9922         if(config.minChars === undefined){
9923             this.minChars = 0;
9924         }
9925     }
9926 };
9927
9928 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9929      
9930     /**
9931      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9932      * rendering into an Roo.Editor, defaults to false)
9933      */
9934     /**
9935      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9936      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9937      */
9938     /**
9939      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9940      */
9941     /**
9942      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9943      * the dropdown list (defaults to undefined, with no header element)
9944      */
9945
9946      /**
9947      * @cfg {String/Roo.Template} tpl The template to use to render the output
9948      */
9949      
9950      /**
9951      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9952      */
9953     listWidth: undefined,
9954     /**
9955      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9956      * mode = 'remote' or 'text' if mode = 'local')
9957      */
9958     displayField: undefined,
9959     /**
9960      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9961      * mode = 'remote' or 'value' if mode = 'local'). 
9962      * Note: use of a valueField requires the user make a selection
9963      * in order for a value to be mapped.
9964      */
9965     valueField: undefined,
9966     
9967     
9968     /**
9969      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9970      * field's data value (defaults to the underlying DOM element's name)
9971      */
9972     hiddenName: undefined,
9973     /**
9974      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9975      */
9976     listClass: '',
9977     /**
9978      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9979      */
9980     selectedClass: 'active',
9981     
9982     /**
9983      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9984      */
9985     shadow:'sides',
9986     /**
9987      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9988      * anchor positions (defaults to 'tl-bl')
9989      */
9990     listAlign: 'tl-bl?',
9991     /**
9992      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9993      */
9994     maxHeight: 300,
9995     /**
9996      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
9997      * query specified by the allQuery config option (defaults to 'query')
9998      */
9999     triggerAction: 'query',
10000     /**
10001      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10002      * (defaults to 4, does not apply if editable = false)
10003      */
10004     minChars : 4,
10005     /**
10006      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10007      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10008      */
10009     typeAhead: false,
10010     /**
10011      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10012      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10013      */
10014     queryDelay: 500,
10015     /**
10016      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10017      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10018      */
10019     pageSize: 0,
10020     /**
10021      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10022      * when editable = true (defaults to false)
10023      */
10024     selectOnFocus:false,
10025     /**
10026      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10027      */
10028     queryParam: 'query',
10029     /**
10030      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10031      * when mode = 'remote' (defaults to 'Loading...')
10032      */
10033     loadingText: 'Loading...',
10034     /**
10035      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10036      */
10037     resizable: false,
10038     /**
10039      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10040      */
10041     handleHeight : 8,
10042     /**
10043      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10044      * traditional select (defaults to true)
10045      */
10046     editable: true,
10047     /**
10048      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10049      */
10050     allQuery: '',
10051     /**
10052      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10053      */
10054     mode: 'remote',
10055     /**
10056      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10057      * listWidth has a higher value)
10058      */
10059     minListWidth : 70,
10060     /**
10061      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10062      * allow the user to set arbitrary text into the field (defaults to false)
10063      */
10064     forceSelection:false,
10065     /**
10066      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10067      * if typeAhead = true (defaults to 250)
10068      */
10069     typeAheadDelay : 250,
10070     /**
10071      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10072      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10073      */
10074     valueNotFoundText : undefined,
10075     /**
10076      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10077      */
10078     blockFocus : false,
10079     
10080     /**
10081      * @cfg {Boolean} disableClear Disable showing of clear button.
10082      */
10083     disableClear : false,
10084     /**
10085      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10086      */
10087     alwaysQuery : false,
10088     
10089     /**
10090      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10091      */
10092     multiple : false,
10093     
10094     //private
10095     addicon : false,
10096     editicon: false,
10097     
10098     page: 0,
10099     hasQuery: false,
10100     append: false,
10101     loadNext: false,
10102     autoFocus : true,
10103     tickable : false,
10104     btnPosition : 'right',
10105     
10106     // element that contains real text value.. (when hidden is used..)
10107     
10108     getAutoCreate : function()
10109     {
10110         var cfg = false;
10111         
10112         /*
10113          *  Normal ComboBox
10114          */
10115         if(!this.tickable){
10116             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10117             return cfg;
10118         }
10119         
10120         /*
10121          *  ComboBox with tickable selections
10122          */
10123              
10124         var align = this.labelAlign || this.parentLabelAlign();
10125         
10126         cfg = {
10127             cls : 'form-group roo-combobox-tickable' //input-group
10128         };
10129         
10130         
10131         var buttons = {
10132             tag : 'div',
10133             cls : 'tickable-buttons',
10134             cn : [
10135                 {
10136                     tag : 'button',
10137                     type : 'button',
10138                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10139                     html : 'Edit'
10140                 },
10141                 {
10142                     tag : 'button',
10143                     type : 'button',
10144                     name : 'ok',
10145                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10146                     html : 'Done'
10147                 },
10148                 {
10149                     tag : 'button',
10150                     type : 'button',
10151                     name : 'cancel',
10152                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10153                     html : 'Cancel'
10154                 }
10155             ]
10156         };
10157         
10158         var _this = this;
10159         Roo.each(buttons.cn, function(c){
10160             if (_this.size) {
10161                 c.cls += ' btn-' + _this.size;
10162             }
10163
10164             if (_this.disabled) {
10165                 c.disabled = true;
10166             }
10167         });
10168         
10169         var box = {
10170             tag: 'div',
10171             cn: [
10172                 {
10173                     tag: 'input',
10174                     type : 'hidden',
10175                     cls: 'form-hidden-field'
10176                 },
10177                 {
10178                     tag: 'ul',
10179                     cls: 'select2-choices',
10180                     cn:[
10181                         {
10182                             tag: 'li',
10183                             cls: 'select2-search-field',
10184                             cn: [
10185
10186                                 buttons
10187                             ]
10188                         }
10189                     ]
10190                 }
10191             ]
10192         }
10193         
10194         var combobox = {
10195             cls: 'select2-container input-group select2-container-multi',
10196             cn: [
10197                 box,
10198                 {
10199                     tag: 'ul',
10200                     cls: 'typeahead typeahead-long dropdown-menu',
10201                     style: 'display:none; max-height:' + this.maxHeight + 'px;'
10202                 }
10203             ]
10204         };
10205         
10206         if (align ==='left' && this.fieldLabel.length) {
10207             
10208                 Roo.log("left and has label");
10209                 cfg.cn = [
10210                     
10211                     {
10212                         tag: 'label',
10213                         'for' :  id,
10214                         cls : 'control-label col-sm-' + this.labelWidth,
10215                         html : this.fieldLabel
10216                         
10217                     },
10218                     {
10219                         cls : "col-sm-" + (12 - this.labelWidth), 
10220                         cn: [
10221                             combobox
10222                         ]
10223                     }
10224                     
10225                 ];
10226         } else if ( this.fieldLabel.length) {
10227                 Roo.log(" label");
10228                  cfg.cn = [
10229                    
10230                     {
10231                         tag: 'label',
10232                         //cls : 'input-group-addon',
10233                         html : this.fieldLabel
10234                         
10235                     },
10236                     
10237                     combobox
10238                     
10239                 ];
10240
10241         } else {
10242             
10243                 Roo.log(" no label && no align");
10244                 cfg = combobox
10245                      
10246                 
10247         }
10248          
10249         var settings=this;
10250         ['xs','sm','md','lg'].map(function(size){
10251             if (settings[size]) {
10252                 cfg.cls += ' col-' + size + '-' + settings[size];
10253             }
10254         });
10255         
10256         return cfg;
10257         
10258     },
10259     
10260     // private
10261     initEvents: function()
10262     {
10263         
10264         if (!this.store) {
10265             throw "can not find store for combo";
10266         }
10267         this.store = Roo.factory(this.store, Roo.data);
10268         
10269         if(this.tickable){
10270             this.initTickableEvnets();
10271             return;
10272         }
10273         
10274         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10275         
10276         
10277         if(this.hiddenName){
10278             
10279             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10280             
10281             this.hiddenField.dom.value =
10282                 this.hiddenValue !== undefined ? this.hiddenValue :
10283                 this.value !== undefined ? this.value : '';
10284
10285             // prevent input submission
10286             this.el.dom.removeAttribute('name');
10287             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10288              
10289              
10290         }
10291         //if(Roo.isGecko){
10292         //    this.el.dom.setAttribute('autocomplete', 'off');
10293         //}
10294
10295         var cls = 'x-combo-list';
10296         this.list = this.el.select('ul.dropdown-menu',true).first();
10297
10298         //this.list = new Roo.Layer({
10299         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10300         //});
10301         
10302         var _this = this;
10303         
10304         (function(){
10305             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10306             _this.list.setWidth(lw);
10307         }).defer(100);
10308         
10309         this.list.on('mouseover', this.onViewOver, this);
10310         this.list.on('mousemove', this.onViewMove, this);
10311         
10312         this.list.on('scroll', this.onViewScroll, this);
10313         
10314         /*
10315         this.list.swallowEvent('mousewheel');
10316         this.assetHeight = 0;
10317
10318         if(this.title){
10319             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10320             this.assetHeight += this.header.getHeight();
10321         }
10322
10323         this.innerList = this.list.createChild({cls:cls+'-inner'});
10324         this.innerList.on('mouseover', this.onViewOver, this);
10325         this.innerList.on('mousemove', this.onViewMove, this);
10326         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10327         
10328         if(this.allowBlank && !this.pageSize && !this.disableClear){
10329             this.footer = this.list.createChild({cls:cls+'-ft'});
10330             this.pageTb = new Roo.Toolbar(this.footer);
10331            
10332         }
10333         if(this.pageSize){
10334             this.footer = this.list.createChild({cls:cls+'-ft'});
10335             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10336                     {pageSize: this.pageSize});
10337             
10338         }
10339         
10340         if (this.pageTb && this.allowBlank && !this.disableClear) {
10341             var _this = this;
10342             this.pageTb.add(new Roo.Toolbar.Fill(), {
10343                 cls: 'x-btn-icon x-btn-clear',
10344                 text: '&#160;',
10345                 handler: function()
10346                 {
10347                     _this.collapse();
10348                     _this.clearValue();
10349                     _this.onSelect(false, -1);
10350                 }
10351             });
10352         }
10353         if (this.footer) {
10354             this.assetHeight += this.footer.getHeight();
10355         }
10356         */
10357             
10358         if(!this.tpl){
10359             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10360         }
10361
10362         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10363             singleSelect:true, store: this.store, selectedClass: this.selectedClass
10364         });
10365         //this.view.wrapEl.setDisplayed(false);
10366         this.view.on('click', this.onViewClick, this);
10367         
10368         
10369         
10370         this.store.on('beforeload', this.onBeforeLoad, this);
10371         this.store.on('load', this.onLoad, this);
10372         this.store.on('loadexception', this.onLoadException, this);
10373         /*
10374         if(this.resizable){
10375             this.resizer = new Roo.Resizable(this.list,  {
10376                pinned:true, handles:'se'
10377             });
10378             this.resizer.on('resize', function(r, w, h){
10379                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10380                 this.listWidth = w;
10381                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10382                 this.restrictHeight();
10383             }, this);
10384             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10385         }
10386         */
10387         if(!this.editable){
10388             this.editable = true;
10389             this.setEditable(false);
10390         }
10391         
10392         /*
10393         
10394         if (typeof(this.events.add.listeners) != 'undefined') {
10395             
10396             this.addicon = this.wrap.createChild(
10397                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
10398        
10399             this.addicon.on('click', function(e) {
10400                 this.fireEvent('add', this);
10401             }, this);
10402         }
10403         if (typeof(this.events.edit.listeners) != 'undefined') {
10404             
10405             this.editicon = this.wrap.createChild(
10406                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
10407             if (this.addicon) {
10408                 this.editicon.setStyle('margin-left', '40px');
10409             }
10410             this.editicon.on('click', function(e) {
10411                 
10412                 // we fire even  if inothing is selected..
10413                 this.fireEvent('edit', this, this.lastData );
10414                 
10415             }, this);
10416         }
10417         */
10418         
10419         this.keyNav = new Roo.KeyNav(this.inputEl(), {
10420             "up" : function(e){
10421                 this.inKeyMode = true;
10422                 this.selectPrev();
10423             },
10424
10425             "down" : function(e){
10426                 if(!this.isExpanded()){
10427                     this.onTriggerClick();
10428                 }else{
10429                     this.inKeyMode = true;
10430                     this.selectNext();
10431                 }
10432             },
10433
10434             "enter" : function(e){
10435 //                this.onViewClick();
10436                 //return true;
10437                 this.collapse();
10438                 
10439                 if(this.fireEvent("specialkey", this, e)){
10440                     this.onViewClick(false);
10441                 }
10442                 
10443                 return true;
10444             },
10445
10446             "esc" : function(e){
10447                 this.collapse();
10448             },
10449
10450             "tab" : function(e){
10451                 this.collapse();
10452                 
10453                 if(this.fireEvent("specialkey", this, e)){
10454                     this.onViewClick(false);
10455                 }
10456                 
10457                 return true;
10458             },
10459
10460             scope : this,
10461
10462             doRelay : function(foo, bar, hname){
10463                 if(hname == 'down' || this.scope.isExpanded()){
10464                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10465                 }
10466                 return true;
10467             },
10468
10469             forceKeyDown: true
10470         });
10471         
10472         
10473         this.queryDelay = Math.max(this.queryDelay || 10,
10474                 this.mode == 'local' ? 10 : 250);
10475         
10476         
10477         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10478         
10479         if(this.typeAhead){
10480             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10481         }
10482         if(this.editable !== false){
10483             this.inputEl().on("keyup", this.onKeyUp, this);
10484         }
10485         if(this.forceSelection){
10486             this.inputEl().on('blur', this.doForce, this);
10487         }
10488         
10489         if(this.multiple){
10490             this.choices = this.el.select('ul.select2-choices', true).first();
10491             this.searchField = this.el.select('ul li.select2-search-field', true).first();
10492         }
10493     },
10494     
10495     initTickableEvnets: function()
10496     {   
10497         if(this.hiddenName){
10498             
10499             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10500             
10501             this.hiddenField.dom.value =
10502                 this.hiddenValue !== undefined ? this.hiddenValue :
10503                 this.value !== undefined ? this.value : '';
10504
10505             // prevent input submission
10506             this.el.dom.removeAttribute('name');
10507             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10508              
10509              
10510         }
10511         
10512         this.list = this.el.select('ul.dropdown-menu',true).first();
10513         
10514         this.choices = this.el.select('ul.select2-choices', true).first();
10515         this.searchField = this.el.select('ul li.select2-search-field', true).first();
10516         this.searchField.on("click", this.onTriggerClick, this, {preventDefault:true});
10517          
10518         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
10519         this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10520         
10521         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
10522         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
10523         
10524         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
10525         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
10526         
10527         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
10528         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
10529         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
10530         
10531         this.okBtn.hide();
10532         this.cancelBtn.hide();
10533         
10534         var _this = this;
10535         
10536         (function(){
10537             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10538             _this.list.setWidth(lw);
10539         }).defer(100);
10540         
10541         this.list.on('mouseover', this.onViewOver, this);
10542         this.list.on('mousemove', this.onViewMove, this);
10543         
10544         this.list.on('scroll', this.onViewScroll, this);
10545         
10546         if(!this.tpl){
10547             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>';
10548         }
10549
10550         this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10551             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
10552         });
10553         
10554         //this.view.wrapEl.setDisplayed(false);
10555         this.view.on('click', this.onViewClick, this);
10556         
10557         
10558         
10559         this.store.on('beforeload', this.onBeforeLoad, this);
10560         this.store.on('load', this.onLoad, this);
10561         this.store.on('loadexception', this.onLoadException, this);
10562         
10563 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
10564 //            "up" : function(e){
10565 //                this.inKeyMode = true;
10566 //                this.selectPrev();
10567 //            },
10568 //
10569 //            "down" : function(e){
10570 //                if(!this.isExpanded()){
10571 //                    this.onTriggerClick();
10572 //                }else{
10573 //                    this.inKeyMode = true;
10574 //                    this.selectNext();
10575 //                }
10576 //            },
10577 //
10578 //            "enter" : function(e){
10579 ////                this.onViewClick();
10580 //                //return true;
10581 //                this.collapse();
10582 //                
10583 //                if(this.fireEvent("specialkey", this, e)){
10584 //                    this.onViewClick(false);
10585 //                }
10586 //                
10587 //                return true;
10588 //            },
10589 //
10590 //            "esc" : function(e){
10591 //                this.collapse();
10592 //            },
10593 //
10594 //            "tab" : function(e){
10595 //                this.collapse();
10596 //                
10597 //                if(this.fireEvent("specialkey", this, e)){
10598 //                    this.onViewClick(false);
10599 //                }
10600 //                
10601 //                return true;
10602 //            },
10603 //
10604 //            scope : this,
10605 //
10606 //            doRelay : function(foo, bar, hname){
10607 //                if(hname == 'down' || this.scope.isExpanded()){
10608 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10609 //                }
10610 //                return true;
10611 //            },
10612 //
10613 //            forceKeyDown: true
10614 //        });
10615         
10616         
10617         this.queryDelay = Math.max(this.queryDelay || 10,
10618                 this.mode == 'local' ? 10 : 250);
10619         
10620         
10621         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10622         
10623         if(this.typeAhead){
10624             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10625         }
10626     },
10627
10628     onDestroy : function(){
10629         if(this.view){
10630             this.view.setStore(null);
10631             this.view.el.removeAllListeners();
10632             this.view.el.remove();
10633             this.view.purgeListeners();
10634         }
10635         if(this.list){
10636             this.list.dom.innerHTML  = '';
10637         }
10638         
10639         if(this.store){
10640             this.store.un('beforeload', this.onBeforeLoad, this);
10641             this.store.un('load', this.onLoad, this);
10642             this.store.un('loadexception', this.onLoadException, this);
10643         }
10644         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10645     },
10646
10647     // private
10648     fireKey : function(e){
10649         if(e.isNavKeyPress() && !this.list.isVisible()){
10650             this.fireEvent("specialkey", this, e);
10651         }
10652     },
10653
10654     // private
10655     onResize: function(w, h){
10656 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10657 //        
10658 //        if(typeof w != 'number'){
10659 //            // we do not handle it!?!?
10660 //            return;
10661 //        }
10662 //        var tw = this.trigger.getWidth();
10663 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
10664 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
10665 //        var x = w - tw;
10666 //        this.inputEl().setWidth( this.adjustWidth('input', x));
10667 //            
10668 //        //this.trigger.setStyle('left', x+'px');
10669 //        
10670 //        if(this.list && this.listWidth === undefined){
10671 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10672 //            this.list.setWidth(lw);
10673 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10674 //        }
10675         
10676     
10677         
10678     },
10679
10680     /**
10681      * Allow or prevent the user from directly editing the field text.  If false is passed,
10682      * the user will only be able to select from the items defined in the dropdown list.  This method
10683      * is the runtime equivalent of setting the 'editable' config option at config time.
10684      * @param {Boolean} value True to allow the user to directly edit the field text
10685      */
10686     setEditable : function(value){
10687         if(value == this.editable){
10688             return;
10689         }
10690         this.editable = value;
10691         if(!value){
10692             this.inputEl().dom.setAttribute('readOnly', true);
10693             this.inputEl().on('mousedown', this.onTriggerClick,  this);
10694             this.inputEl().addClass('x-combo-noedit');
10695         }else{
10696             this.inputEl().dom.setAttribute('readOnly', false);
10697             this.inputEl().un('mousedown', this.onTriggerClick,  this);
10698             this.inputEl().removeClass('x-combo-noedit');
10699         }
10700     },
10701
10702     // private
10703     
10704     onBeforeLoad : function(combo,opts){
10705         if(!this.hasFocus){
10706             return;
10707         }
10708          if (!opts.add) {
10709             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10710          }
10711         this.restrictHeight();
10712         this.selectedIndex = -1;
10713     },
10714
10715     // private
10716     onLoad : function(){
10717         
10718         this.hasQuery = false;
10719         
10720         if(!this.hasFocus){
10721             return;
10722         }
10723         
10724         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10725             this.loading.hide();
10726         }
10727         
10728         if(this.store.getCount() > 0){
10729             this.expand();
10730             this.restrictHeight();
10731             if(this.lastQuery == this.allQuery){
10732                 if(this.editable && !this.tickable){
10733                     this.inputEl().dom.select();
10734                 }
10735                 if(!this.selectByValue(this.value, true) && this.autoFocus){
10736                     this.select(0, true);
10737                 }
10738             }else{
10739                 if(this.autoFocus){
10740                     this.selectNext();
10741                 }
10742                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10743                     this.taTask.delay(this.typeAheadDelay);
10744                 }
10745             }
10746         }else{
10747             this.onEmptyResults();
10748         }
10749         
10750         //this.el.focus();
10751     },
10752     // private
10753     onLoadException : function()
10754     {
10755         this.hasQuery = false;
10756         
10757         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10758             this.loading.hide();
10759         }
10760         
10761         this.collapse();
10762         Roo.log(this.store.reader.jsonData);
10763         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10764             // fixme
10765             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10766         }
10767         
10768         
10769     },
10770     // private
10771     onTypeAhead : function(){
10772         if(this.store.getCount() > 0){
10773             var r = this.store.getAt(0);
10774             var newValue = r.data[this.displayField];
10775             var len = newValue.length;
10776             var selStart = this.getRawValue().length;
10777             
10778             if(selStart != len){
10779                 this.setRawValue(newValue);
10780                 this.selectText(selStart, newValue.length);
10781             }
10782         }
10783     },
10784
10785     // private
10786     onSelect : function(record, index){
10787         
10788         if(this.fireEvent('beforeselect', this, record, index) !== false){
10789         
10790             this.setFromData(index > -1 ? record.data : false);
10791             
10792             this.collapse();
10793             this.fireEvent('select', this, record, index);
10794         }
10795     },
10796
10797     /**
10798      * Returns the currently selected field value or empty string if no value is set.
10799      * @return {String} value The selected value
10800      */
10801     getValue : function(){
10802         
10803         if(this.multiple){
10804             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10805         }
10806         
10807         if(this.valueField){
10808             return typeof this.value != 'undefined' ? this.value : '';
10809         }else{
10810             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10811         }
10812     },
10813
10814     /**
10815      * Clears any text/value currently set in the field
10816      */
10817     clearValue : function(){
10818         if(this.hiddenField){
10819             this.hiddenField.dom.value = '';
10820         }
10821         this.value = '';
10822         this.setRawValue('');
10823         this.lastSelectionText = '';
10824         
10825     },
10826
10827     /**
10828      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
10829      * will be displayed in the field.  If the value does not match the data value of an existing item,
10830      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10831      * Otherwise the field will be blank (although the value will still be set).
10832      * @param {String} value The value to match
10833      */
10834     setValue : function(v){
10835         if(this.multiple){
10836             this.syncValue();
10837             return;
10838         }
10839         
10840         var text = v;
10841         if(this.valueField){
10842             var r = this.findRecord(this.valueField, v);
10843             if(r){
10844                 text = r.data[this.displayField];
10845             }else if(this.valueNotFoundText !== undefined){
10846                 text = this.valueNotFoundText;
10847             }
10848         }
10849         this.lastSelectionText = text;
10850         if(this.hiddenField){
10851             this.hiddenField.dom.value = v;
10852         }
10853         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10854         this.value = v;
10855     },
10856     /**
10857      * @property {Object} the last set data for the element
10858      */
10859     
10860     lastData : false,
10861     /**
10862      * Sets the value of the field based on a object which is related to the record format for the store.
10863      * @param {Object} value the value to set as. or false on reset?
10864      */
10865     setFromData : function(o){
10866         
10867         if(this.multiple){
10868             this.addItem(o);
10869             return;
10870         }
10871             
10872         var dv = ''; // display value
10873         var vv = ''; // value value..
10874         this.lastData = o;
10875         if (this.displayField) {
10876             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10877         } else {
10878             // this is an error condition!!!
10879             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
10880         }
10881         
10882         if(this.valueField){
10883             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10884         }
10885         
10886         if(this.hiddenField){
10887             this.hiddenField.dom.value = vv;
10888             
10889             this.lastSelectionText = dv;
10890             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10891             this.value = vv;
10892             return;
10893         }
10894         // no hidden field.. - we store the value in 'value', but still display
10895         // display field!!!!
10896         this.lastSelectionText = dv;
10897         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10898         this.value = vv;
10899         
10900         
10901     },
10902     // private
10903     reset : function(){
10904         // overridden so that last data is reset..
10905         this.setValue(this.originalValue);
10906         this.clearInvalid();
10907         this.lastData = false;
10908         if (this.view) {
10909             this.view.clearSelections();
10910         }
10911     },
10912     // private
10913     findRecord : function(prop, value){
10914         var record;
10915         if(this.store.getCount() > 0){
10916             this.store.each(function(r){
10917                 if(r.data[prop] == value){
10918                     record = r;
10919                     return false;
10920                 }
10921                 return true;
10922             });
10923         }
10924         return record;
10925     },
10926     
10927     getName: function()
10928     {
10929         // returns hidden if it's set..
10930         if (!this.rendered) {return ''};
10931         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
10932         
10933     },
10934     // private
10935     onViewMove : function(e, t){
10936         this.inKeyMode = false;
10937     },
10938
10939     // private
10940     onViewOver : function(e, t){
10941         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10942             return;
10943         }
10944         var item = this.view.findItemFromChild(t);
10945         
10946         if(item){
10947             var index = this.view.indexOf(item);
10948             this.select(index, false);
10949         }
10950     },
10951
10952     // private
10953     onViewClick : function(view, doFocus, el, e)
10954     {
10955         var index = this.view.getSelectedIndexes()[0];
10956         
10957         var r = this.store.getAt(index);
10958         
10959         if(this.tickable){
10960             
10961             if(e.getTarget().nodeName.toLowerCase() != 'input'){
10962                 return;
10963             }
10964             
10965             var rm = false;
10966             var _this = this;
10967             
10968             Roo.each(this.tickItems, function(v,k){
10969                 
10970                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
10971                     _this.tickItems.splice(k, 1);
10972                     rm = true;
10973                     return;
10974                 }
10975             })
10976             
10977             if(rm){
10978                 return;
10979             }
10980             
10981             this.tickItems.push(r.data);
10982             return;
10983         }
10984         
10985         if(r){
10986             this.onSelect(r, index);
10987         }
10988         if(doFocus !== false && !this.blockFocus){
10989             this.inputEl().focus();
10990         }
10991     },
10992
10993     // private
10994     restrictHeight : function(){
10995         //this.innerList.dom.style.height = '';
10996         //var inner = this.innerList.dom;
10997         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10998         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10999         //this.list.beginUpdate();
11000         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11001         this.list.alignTo(this.inputEl(), this.listAlign);
11002         //this.list.endUpdate();
11003     },
11004
11005     // private
11006     onEmptyResults : function(){
11007         this.collapse();
11008     },
11009
11010     /**
11011      * Returns true if the dropdown list is expanded, else false.
11012      */
11013     isExpanded : function(){
11014         return this.list.isVisible();
11015     },
11016
11017     /**
11018      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11019      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11020      * @param {String} value The data value of the item to select
11021      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11022      * selected item if it is not currently in view (defaults to true)
11023      * @return {Boolean} True if the value matched an item in the list, else false
11024      */
11025     selectByValue : function(v, scrollIntoView){
11026         if(v !== undefined && v !== null){
11027             var r = this.findRecord(this.valueField || this.displayField, v);
11028             if(r){
11029                 this.select(this.store.indexOf(r), scrollIntoView);
11030                 return true;
11031             }
11032         }
11033         return false;
11034     },
11035
11036     /**
11037      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11038      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11039      * @param {Number} index The zero-based index of the list item to select
11040      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11041      * selected item if it is not currently in view (defaults to true)
11042      */
11043     select : function(index, scrollIntoView){
11044         this.selectedIndex = index;
11045         this.view.select(index);
11046         if(scrollIntoView !== false){
11047             var el = this.view.getNode(index);
11048             if(el){
11049                 //this.innerList.scrollChildIntoView(el, false);
11050                 
11051             }
11052         }
11053     },
11054
11055     // private
11056     selectNext : function(){
11057         var ct = this.store.getCount();
11058         if(ct > 0){
11059             if(this.selectedIndex == -1){
11060                 this.select(0);
11061             }else if(this.selectedIndex < ct-1){
11062                 this.select(this.selectedIndex+1);
11063             }
11064         }
11065     },
11066
11067     // private
11068     selectPrev : function(){
11069         var ct = this.store.getCount();
11070         if(ct > 0){
11071             if(this.selectedIndex == -1){
11072                 this.select(0);
11073             }else if(this.selectedIndex != 0){
11074                 this.select(this.selectedIndex-1);
11075             }
11076         }
11077     },
11078
11079     // private
11080     onKeyUp : function(e){
11081         if(this.editable !== false && !e.isSpecialKey()){
11082             this.lastKey = e.getKey();
11083             this.dqTask.delay(this.queryDelay);
11084         }
11085     },
11086
11087     // private
11088     validateBlur : function(){
11089         return !this.list || !this.list.isVisible();   
11090     },
11091
11092     // private
11093     initQuery : function(){
11094         this.doQuery(this.getRawValue());
11095     },
11096
11097     // private
11098     doForce : function(){
11099         if(this.inputEl().dom.value.length > 0){
11100             this.inputEl().dom.value =
11101                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11102              
11103         }
11104     },
11105
11106     /**
11107      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11108      * query allowing the query action to be canceled if needed.
11109      * @param {String} query The SQL query to execute
11110      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11111      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11112      * saved in the current store (defaults to false)
11113      */
11114     doQuery : function(q, forceAll){
11115         
11116         if(q === undefined || q === null){
11117             q = '';
11118         }
11119         var qe = {
11120             query: q,
11121             forceAll: forceAll,
11122             combo: this,
11123             cancel:false
11124         };
11125         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11126             return false;
11127         }
11128         q = qe.query;
11129         
11130         forceAll = qe.forceAll;
11131         if(forceAll === true || (q.length >= this.minChars)){
11132             
11133             this.hasQuery = true;
11134             
11135             if(this.lastQuery != q || this.alwaysQuery){
11136                 this.lastQuery = q;
11137                 if(this.mode == 'local'){
11138                     this.selectedIndex = -1;
11139                     if(forceAll){
11140                         this.store.clearFilter();
11141                     }else{
11142                         this.store.filter(this.displayField, q);
11143                     }
11144                     this.onLoad();
11145                 }else{
11146                     this.store.baseParams[this.queryParam] = q;
11147                     
11148                     var options = {params : this.getParams(q)};
11149                     
11150                     if(this.loadNext){
11151                         options.add = true;
11152                         options.params.start = this.page * this.pageSize;
11153                     }
11154                     
11155                     this.store.load(options);
11156                     /*
11157                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11158                      *  we should expand the list on onLoad
11159                      *  so command out it
11160                      */
11161 //                    this.expand();
11162                 }
11163             }else{
11164                 this.selectedIndex = -1;
11165                 this.onLoad();   
11166             }
11167         }
11168         
11169         this.loadNext = false;
11170     },
11171
11172     // private
11173     getParams : function(q){
11174         var p = {};
11175         //p[this.queryParam] = q;
11176         
11177         if(this.pageSize){
11178             p.start = 0;
11179             p.limit = this.pageSize;
11180         }
11181         return p;
11182     },
11183
11184     /**
11185      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11186      */
11187     collapse : function(){
11188         if(!this.isExpanded()){
11189             return;
11190         }
11191         
11192         this.list.hide();
11193         
11194         if(this.tickable){
11195             this.okBtn.hide();
11196             this.cancelBtn.hide();
11197             this.trigger.show();
11198         }
11199         
11200         Roo.get(document).un('mousedown', this.collapseIf, this);
11201         Roo.get(document).un('mousewheel', this.collapseIf, this);
11202         if (!this.editable) {
11203             Roo.get(document).un('keydown', this.listKeyPress, this);
11204         }
11205         this.fireEvent('collapse', this);
11206     },
11207
11208     // private
11209     collapseIf : function(e){
11210         var in_combo  = e.within(this.el);
11211         var in_list =  e.within(this.list);
11212         
11213         if (in_combo || in_list) {
11214             //e.stopPropagation();
11215             return;
11216         }
11217         
11218         if(this.tickable){
11219             this.onTickableFooterButtonClick(e, false, false);
11220         }
11221
11222         this.collapse();
11223         
11224     },
11225
11226     /**
11227      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11228      */
11229     expand : function(){
11230        
11231         if(this.isExpanded() || !this.hasFocus){
11232             return;
11233         }
11234          Roo.log('expand');
11235         this.list.alignTo(this.inputEl(), this.listAlign);
11236         this.list.show();
11237         
11238         if(this.tickable){
11239             
11240             this.tickItems = Roo.apply([], this.item);
11241             
11242             this.okBtn.show();
11243             this.cancelBtn.show();
11244             this.trigger.hide();
11245             
11246         }
11247         
11248         Roo.get(document).on('mousedown', this.collapseIf, this);
11249         Roo.get(document).on('mousewheel', this.collapseIf, this);
11250         if (!this.editable) {
11251             Roo.get(document).on('keydown', this.listKeyPress, this);
11252         }
11253         
11254         this.fireEvent('expand', this);
11255     },
11256
11257     // private
11258     // Implements the default empty TriggerField.onTriggerClick function
11259     onTriggerClick : function()
11260     {
11261         Roo.log('trigger click');
11262         
11263         if(this.disabled){
11264             return;
11265         }
11266         
11267         if(this.tickable){
11268             this.onTickableTriggerClick();
11269             return;
11270         }
11271         
11272         this.page = 0;
11273         this.loadNext = false;
11274         
11275         if(this.isExpanded()){
11276             this.collapse();
11277             if (!this.blockFocus) {
11278                 this.inputEl().focus();
11279             }
11280             
11281         }else {
11282             this.hasFocus = true;
11283             if(this.triggerAction == 'all') {
11284                 this.doQuery(this.allQuery, true);
11285             } else {
11286                 this.doQuery(this.getRawValue());
11287             }
11288             if (!this.blockFocus) {
11289                 this.inputEl().focus();
11290             }
11291         }
11292     },
11293     
11294     onTickableTriggerClick : function()
11295     {
11296         this.page = 0;
11297         this.loadNext = false;
11298         this.hasFocus = true;
11299         
11300         if(this.triggerAction == 'all') {
11301             this.doQuery(this.allQuery, true);
11302         } else {
11303             this.doQuery(this.getRawValue());
11304         }
11305     },
11306     
11307     listKeyPress : function(e)
11308     {
11309         //Roo.log('listkeypress');
11310         // scroll to first matching element based on key pres..
11311         if (e.isSpecialKey()) {
11312             return false;
11313         }
11314         var k = String.fromCharCode(e.getKey()).toUpperCase();
11315         //Roo.log(k);
11316         var match  = false;
11317         var csel = this.view.getSelectedNodes();
11318         var cselitem = false;
11319         if (csel.length) {
11320             var ix = this.view.indexOf(csel[0]);
11321             cselitem  = this.store.getAt(ix);
11322             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
11323                 cselitem = false;
11324             }
11325             
11326         }
11327         
11328         this.store.each(function(v) { 
11329             if (cselitem) {
11330                 // start at existing selection.
11331                 if (cselitem.id == v.id) {
11332                     cselitem = false;
11333                 }
11334                 return true;
11335             }
11336                 
11337             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
11338                 match = this.store.indexOf(v);
11339                 return false;
11340             }
11341             return true;
11342         }, this);
11343         
11344         if (match === false) {
11345             return true; // no more action?
11346         }
11347         // scroll to?
11348         this.view.select(match);
11349         var sn = Roo.get(this.view.getSelectedNodes()[0])
11350         //sn.scrollIntoView(sn.dom.parentNode, false);
11351     },
11352     
11353     onViewScroll : function(e, t){
11354         
11355         if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
11356             return;
11357         }
11358         
11359         this.hasQuery = true;
11360         
11361         this.loading = this.list.select('.loading', true).first();
11362         
11363         if(this.loading === null){
11364             this.list.createChild({
11365                 tag: 'div',
11366                 cls: 'loading select2-more-results select2-active',
11367                 html: 'Loading more results...'
11368             })
11369             
11370             this.loading = this.list.select('.loading', true).first();
11371             
11372             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
11373             
11374             this.loading.hide();
11375         }
11376         
11377         this.loading.show();
11378         
11379         var _combo = this;
11380         
11381         this.page++;
11382         this.loadNext = true;
11383         
11384         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
11385         
11386         return;
11387     },
11388     
11389     addItem : function(o)
11390     {   
11391         var dv = ''; // display value
11392         
11393         if (this.displayField) {
11394             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11395         } else {
11396             // this is an error condition!!!
11397             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11398         }
11399         
11400         if(!dv.length){
11401             return;
11402         }
11403         
11404         var choice = this.choices.createChild({
11405             tag: 'li',
11406             cls: 'select2-search-choice',
11407             cn: [
11408                 {
11409                     tag: 'div',
11410                     html: dv
11411                 },
11412                 {
11413                     tag: 'a',
11414                     href: '#',
11415                     cls: 'select2-search-choice-close',
11416                     tabindex: '-1'
11417                 }
11418             ]
11419             
11420         }, this.searchField);
11421         
11422         var close = choice.select('a.select2-search-choice-close', true).first()
11423         
11424         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
11425         
11426         this.item.push(o);
11427         
11428         this.lastData = o;
11429         
11430         this.syncValue();
11431         
11432         this.inputEl().dom.value = '';
11433         
11434     },
11435     
11436     onRemoveItem : function(e, _self, o)
11437     {
11438         e.preventDefault();
11439         var index = this.item.indexOf(o.data) * 1;
11440         
11441         if( index < 0){
11442             Roo.log('not this item?!');
11443             return;
11444         }
11445         
11446         this.item.splice(index, 1);
11447         o.item.remove();
11448         
11449         this.syncValue();
11450         
11451         this.fireEvent('remove', this, e);
11452         
11453     },
11454     
11455     syncValue : function()
11456     {
11457         if(!this.item.length){
11458             this.clearValue();
11459             return;
11460         }
11461             
11462         var value = [];
11463         var _this = this;
11464         Roo.each(this.item, function(i){
11465             if(_this.valueField){
11466                 value.push(i[_this.valueField]);
11467                 return;
11468             }
11469
11470             value.push(i);
11471         });
11472
11473         this.value = value.join(',');
11474
11475         if(this.hiddenField){
11476             this.hiddenField.dom.value = this.value;
11477         }
11478     },
11479     
11480     clearItem : function()
11481     {
11482         if(!this.multiple){
11483             return;
11484         }
11485         
11486         this.item = [];
11487         
11488         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11489            c.remove();
11490         });
11491         
11492         this.syncValue();
11493     },
11494     
11495     inputEl: function ()
11496     {
11497         if(this.tickable){
11498             return this.searchField;
11499         }
11500         return this.el.select('input.form-control',true).first();
11501     },
11502     
11503     
11504     onTickableFooterButtonClick : function(e, btn, el)
11505     {
11506         e.preventDefault();
11507         
11508         if(btn && btn.name == 'cancel'){
11509             this.tickItems = Roo.apply([], this.item);
11510             this.collapse();
11511             return;
11512         }
11513         
11514         this.clearItem();
11515         
11516         var _this = this;
11517         
11518         Roo.each(this.tickItems, function(o){
11519             _this.addItem(o);
11520         });
11521         
11522         this.collapse();
11523         
11524     }
11525     
11526     
11527
11528     /** 
11529     * @cfg {Boolean} grow 
11530     * @hide 
11531     */
11532     /** 
11533     * @cfg {Number} growMin 
11534     * @hide 
11535     */
11536     /** 
11537     * @cfg {Number} growMax 
11538     * @hide 
11539     */
11540     /**
11541      * @hide
11542      * @method autoSize
11543      */
11544 });
11545 /*
11546  * Based on:
11547  * Ext JS Library 1.1.1
11548  * Copyright(c) 2006-2007, Ext JS, LLC.
11549  *
11550  * Originally Released Under LGPL - original licence link has changed is not relivant.
11551  *
11552  * Fork - LGPL
11553  * <script type="text/javascript">
11554  */
11555
11556 /**
11557  * @class Roo.View
11558  * @extends Roo.util.Observable
11559  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
11560  * This class also supports single and multi selection modes. <br>
11561  * Create a data model bound view:
11562  <pre><code>
11563  var store = new Roo.data.Store(...);
11564
11565  var view = new Roo.View({
11566     el : "my-element",
11567     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
11568  
11569     singleSelect: true,
11570     selectedClass: "ydataview-selected",
11571     store: store
11572  });
11573
11574  // listen for node click?
11575  view.on("click", function(vw, index, node, e){
11576  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11577  });
11578
11579  // load XML data
11580  dataModel.load("foobar.xml");
11581  </code></pre>
11582  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11583  * <br><br>
11584  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11585  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11586  * 
11587  * Note: old style constructor is still suported (container, template, config)
11588  * 
11589  * @constructor
11590  * Create a new View
11591  * @param {Object} config The config object
11592  * 
11593  */
11594 Roo.View = function(config, depreciated_tpl, depreciated_config){
11595     
11596     this.parent = false;
11597     
11598     if (typeof(depreciated_tpl) == 'undefined') {
11599         // new way.. - universal constructor.
11600         Roo.apply(this, config);
11601         this.el  = Roo.get(this.el);
11602     } else {
11603         // old format..
11604         this.el  = Roo.get(config);
11605         this.tpl = depreciated_tpl;
11606         Roo.apply(this, depreciated_config);
11607     }
11608     this.wrapEl  = this.el.wrap().wrap();
11609     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11610     
11611     
11612     if(typeof(this.tpl) == "string"){
11613         this.tpl = new Roo.Template(this.tpl);
11614     } else {
11615         // support xtype ctors..
11616         this.tpl = new Roo.factory(this.tpl, Roo);
11617     }
11618     
11619     
11620     this.tpl.compile();
11621     
11622     /** @private */
11623     this.addEvents({
11624         /**
11625          * @event beforeclick
11626          * Fires before a click is processed. Returns false to cancel the default action.
11627          * @param {Roo.View} this
11628          * @param {Number} index The index of the target node
11629          * @param {HTMLElement} node The target node
11630          * @param {Roo.EventObject} e The raw event object
11631          */
11632             "beforeclick" : true,
11633         /**
11634          * @event click
11635          * Fires when a template node is clicked.
11636          * @param {Roo.View} this
11637          * @param {Number} index The index of the target node
11638          * @param {HTMLElement} node The target node
11639          * @param {Roo.EventObject} e The raw event object
11640          */
11641             "click" : true,
11642         /**
11643          * @event dblclick
11644          * Fires when a template node is double clicked.
11645          * @param {Roo.View} this
11646          * @param {Number} index The index of the target node
11647          * @param {HTMLElement} node The target node
11648          * @param {Roo.EventObject} e The raw event object
11649          */
11650             "dblclick" : true,
11651         /**
11652          * @event contextmenu
11653          * Fires when a template node is right clicked.
11654          * @param {Roo.View} this
11655          * @param {Number} index The index of the target node
11656          * @param {HTMLElement} node The target node
11657          * @param {Roo.EventObject} e The raw event object
11658          */
11659             "contextmenu" : true,
11660         /**
11661          * @event selectionchange
11662          * Fires when the selected nodes change.
11663          * @param {Roo.View} this
11664          * @param {Array} selections Array of the selected nodes
11665          */
11666             "selectionchange" : true,
11667     
11668         /**
11669          * @event beforeselect
11670          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11671          * @param {Roo.View} this
11672          * @param {HTMLElement} node The node to be selected
11673          * @param {Array} selections Array of currently selected nodes
11674          */
11675             "beforeselect" : true,
11676         /**
11677          * @event preparedata
11678          * Fires on every row to render, to allow you to change the data.
11679          * @param {Roo.View} this
11680          * @param {Object} data to be rendered (change this)
11681          */
11682           "preparedata" : true
11683           
11684           
11685         });
11686
11687
11688
11689     this.el.on({
11690         "click": this.onClick,
11691         "dblclick": this.onDblClick,
11692         "contextmenu": this.onContextMenu,
11693         scope:this
11694     });
11695
11696     this.selections = [];
11697     this.nodes = [];
11698     this.cmp = new Roo.CompositeElementLite([]);
11699     if(this.store){
11700         this.store = Roo.factory(this.store, Roo.data);
11701         this.setStore(this.store, true);
11702     }
11703     
11704     if ( this.footer && this.footer.xtype) {
11705            
11706          var fctr = this.wrapEl.appendChild(document.createElement("div"));
11707         
11708         this.footer.dataSource = this.store
11709         this.footer.container = fctr;
11710         this.footer = Roo.factory(this.footer, Roo);
11711         fctr.insertFirst(this.el);
11712         
11713         // this is a bit insane - as the paging toolbar seems to detach the el..
11714 //        dom.parentNode.parentNode.parentNode
11715          // they get detached?
11716     }
11717     
11718     
11719     Roo.View.superclass.constructor.call(this);
11720     
11721     
11722 };
11723
11724 Roo.extend(Roo.View, Roo.util.Observable, {
11725     
11726      /**
11727      * @cfg {Roo.data.Store} store Data store to load data from.
11728      */
11729     store : false,
11730     
11731     /**
11732      * @cfg {String|Roo.Element} el The container element.
11733      */
11734     el : '',
11735     
11736     /**
11737      * @cfg {String|Roo.Template} tpl The template used by this View 
11738      */
11739     tpl : false,
11740     /**
11741      * @cfg {String} dataName the named area of the template to use as the data area
11742      *                          Works with domtemplates roo-name="name"
11743      */
11744     dataName: false,
11745     /**
11746      * @cfg {String} selectedClass The css class to add to selected nodes
11747      */
11748     selectedClass : "x-view-selected",
11749      /**
11750      * @cfg {String} emptyText The empty text to show when nothing is loaded.
11751      */
11752     emptyText : "",
11753     
11754     /**
11755      * @cfg {String} text to display on mask (default Loading)
11756      */
11757     mask : false,
11758     /**
11759      * @cfg {Boolean} multiSelect Allow multiple selection
11760      */
11761     multiSelect : false,
11762     /**
11763      * @cfg {Boolean} singleSelect Allow single selection
11764      */
11765     singleSelect:  false,
11766     
11767     /**
11768      * @cfg {Boolean} toggleSelect - selecting 
11769      */
11770     toggleSelect : false,
11771     
11772     /**
11773      * @cfg {Boolean} tickable - selecting 
11774      */
11775     tickable : false,
11776     
11777     /**
11778      * Returns the element this view is bound to.
11779      * @return {Roo.Element}
11780      */
11781     getEl : function(){
11782         return this.wrapEl;
11783     },
11784     
11785     
11786
11787     /**
11788      * Refreshes the view. - called by datachanged on the store. - do not call directly.
11789      */
11790     refresh : function(){
11791         Roo.log('refresh');
11792         var t = this.tpl;
11793         
11794         // if we are using something like 'domtemplate', then
11795         // the what gets used is:
11796         // t.applySubtemplate(NAME, data, wrapping data..)
11797         // the outer template then get' applied with
11798         //     the store 'extra data'
11799         // and the body get's added to the
11800         //      roo-name="data" node?
11801         //      <span class='roo-tpl-{name}'></span> ?????
11802         
11803         
11804         
11805         this.clearSelections();
11806         this.el.update("");
11807         var html = [];
11808         var records = this.store.getRange();
11809         if(records.length < 1) {
11810             
11811             // is this valid??  = should it render a template??
11812             
11813             this.el.update(this.emptyText);
11814             return;
11815         }
11816         var el = this.el;
11817         if (this.dataName) {
11818             this.el.update(t.apply(this.store.meta)); //????
11819             el = this.el.child('.roo-tpl-' + this.dataName);
11820         }
11821         
11822         for(var i = 0, len = records.length; i < len; i++){
11823             var data = this.prepareData(records[i].data, i, records[i]);
11824             this.fireEvent("preparedata", this, data, i, records[i]);
11825             
11826             var d = Roo.apply({}, data);
11827             
11828             if(this.tickable){
11829                 Roo.apply(d, {'roo-id' : Roo.id()});
11830                 
11831                 var _this = this;
11832             
11833                 Roo.each(this.parent.item, function(item){
11834                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
11835                         return;
11836                     }
11837                     Roo.apply(d, {'roo-data-checked' : 'checked'});
11838                 });
11839             }
11840             
11841             html[html.length] = Roo.util.Format.trim(
11842                 this.dataName ?
11843                     t.applySubtemplate(this.dataName, d, this.store.meta) :
11844                     t.apply(d)
11845             );
11846         }
11847         
11848         
11849         
11850         el.update(html.join(""));
11851         this.nodes = el.dom.childNodes;
11852         this.updateIndexes(0);
11853     },
11854     
11855
11856     /**
11857      * Function to override to reformat the data that is sent to
11858      * the template for each node.
11859      * DEPRICATED - use the preparedata event handler.
11860      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11861      * a JSON object for an UpdateManager bound view).
11862      */
11863     prepareData : function(data, index, record)
11864     {
11865         this.fireEvent("preparedata", this, data, index, record);
11866         return data;
11867     },
11868
11869     onUpdate : function(ds, record){
11870          Roo.log('on update');   
11871         this.clearSelections();
11872         var index = this.store.indexOf(record);
11873         var n = this.nodes[index];
11874         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11875         n.parentNode.removeChild(n);
11876         this.updateIndexes(index, index);
11877     },
11878
11879     
11880     
11881 // --------- FIXME     
11882     onAdd : function(ds, records, index)
11883     {
11884         Roo.log(['on Add', ds, records, index] );        
11885         this.clearSelections();
11886         if(this.nodes.length == 0){
11887             this.refresh();
11888             return;
11889         }
11890         var n = this.nodes[index];
11891         for(var i = 0, len = records.length; i < len; i++){
11892             var d = this.prepareData(records[i].data, i, records[i]);
11893             if(n){
11894                 this.tpl.insertBefore(n, d);
11895             }else{
11896                 
11897                 this.tpl.append(this.el, d);
11898             }
11899         }
11900         this.updateIndexes(index);
11901     },
11902
11903     onRemove : function(ds, record, index){
11904         Roo.log('onRemove');
11905         this.clearSelections();
11906         var el = this.dataName  ?
11907             this.el.child('.roo-tpl-' + this.dataName) :
11908             this.el; 
11909         
11910         el.dom.removeChild(this.nodes[index]);
11911         this.updateIndexes(index);
11912     },
11913
11914     /**
11915      * Refresh an individual node.
11916      * @param {Number} index
11917      */
11918     refreshNode : function(index){
11919         this.onUpdate(this.store, this.store.getAt(index));
11920     },
11921
11922     updateIndexes : function(startIndex, endIndex){
11923         var ns = this.nodes;
11924         startIndex = startIndex || 0;
11925         endIndex = endIndex || ns.length - 1;
11926         for(var i = startIndex; i <= endIndex; i++){
11927             ns[i].nodeIndex = i;
11928         }
11929     },
11930
11931     /**
11932      * Changes the data store this view uses and refresh the view.
11933      * @param {Store} store
11934      */
11935     setStore : function(store, initial){
11936         if(!initial && this.store){
11937             this.store.un("datachanged", this.refresh);
11938             this.store.un("add", this.onAdd);
11939             this.store.un("remove", this.onRemove);
11940             this.store.un("update", this.onUpdate);
11941             this.store.un("clear", this.refresh);
11942             this.store.un("beforeload", this.onBeforeLoad);
11943             this.store.un("load", this.onLoad);
11944             this.store.un("loadexception", this.onLoad);
11945         }
11946         if(store){
11947           
11948             store.on("datachanged", this.refresh, this);
11949             store.on("add", this.onAdd, this);
11950             store.on("remove", this.onRemove, this);
11951             store.on("update", this.onUpdate, this);
11952             store.on("clear", this.refresh, this);
11953             store.on("beforeload", this.onBeforeLoad, this);
11954             store.on("load", this.onLoad, this);
11955             store.on("loadexception", this.onLoad, this);
11956         }
11957         
11958         if(store){
11959             this.refresh();
11960         }
11961     },
11962     /**
11963      * onbeforeLoad - masks the loading area.
11964      *
11965      */
11966     onBeforeLoad : function(store,opts)
11967     {
11968          Roo.log('onBeforeLoad');   
11969         if (!opts.add) {
11970             this.el.update("");
11971         }
11972         this.el.mask(this.mask ? this.mask : "Loading" ); 
11973     },
11974     onLoad : function ()
11975     {
11976         this.el.unmask();
11977     },
11978     
11979
11980     /**
11981      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11982      * @param {HTMLElement} node
11983      * @return {HTMLElement} The template node
11984      */
11985     findItemFromChild : function(node){
11986         var el = this.dataName  ?
11987             this.el.child('.roo-tpl-' + this.dataName,true) :
11988             this.el.dom; 
11989         
11990         if(!node || node.parentNode == el){
11991                     return node;
11992             }
11993             var p = node.parentNode;
11994             while(p && p != el){
11995             if(p.parentNode == el){
11996                 return p;
11997             }
11998             p = p.parentNode;
11999         }
12000             return null;
12001     },
12002
12003     /** @ignore */
12004     onClick : function(e){
12005         var item = this.findItemFromChild(e.getTarget());
12006         if(item){
12007             var index = this.indexOf(item);
12008             if(this.onItemClick(item, index, e) !== false){
12009                 this.fireEvent("click", this, index, item, e);
12010             }
12011         }else{
12012             this.clearSelections();
12013         }
12014     },
12015
12016     /** @ignore */
12017     onContextMenu : function(e){
12018         var item = this.findItemFromChild(e.getTarget());
12019         if(item){
12020             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12021         }
12022     },
12023
12024     /** @ignore */
12025     onDblClick : function(e){
12026         var item = this.findItemFromChild(e.getTarget());
12027         if(item){
12028             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12029         }
12030     },
12031
12032     onItemClick : function(item, index, e)
12033     {
12034         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12035             return false;
12036         }
12037         if (this.toggleSelect) {
12038             var m = this.isSelected(item) ? 'unselect' : 'select';
12039             Roo.log(m);
12040             var _t = this;
12041             _t[m](item, true, false);
12042             return true;
12043         }
12044         if(this.multiSelect || this.singleSelect){
12045             if(this.multiSelect && e.shiftKey && this.lastSelection){
12046                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12047             }else{
12048                 this.select(item, this.multiSelect && e.ctrlKey);
12049                 this.lastSelection = item;
12050             }
12051             
12052             if(!this.tickable){
12053                 e.preventDefault();
12054             }
12055             
12056         }
12057         return true;
12058     },
12059
12060     /**
12061      * Get the number of selected nodes.
12062      * @return {Number}
12063      */
12064     getSelectionCount : function(){
12065         return this.selections.length;
12066     },
12067
12068     /**
12069      * Get the currently selected nodes.
12070      * @return {Array} An array of HTMLElements
12071      */
12072     getSelectedNodes : function(){
12073         return this.selections;
12074     },
12075
12076     /**
12077      * Get the indexes of the selected nodes.
12078      * @return {Array}
12079      */
12080     getSelectedIndexes : function(){
12081         var indexes = [], s = this.selections;
12082         for(var i = 0, len = s.length; i < len; i++){
12083             indexes.push(s[i].nodeIndex);
12084         }
12085         return indexes;
12086     },
12087
12088     /**
12089      * Clear all selections
12090      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12091      */
12092     clearSelections : function(suppressEvent){
12093         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12094             this.cmp.elements = this.selections;
12095             this.cmp.removeClass(this.selectedClass);
12096             this.selections = [];
12097             if(!suppressEvent){
12098                 this.fireEvent("selectionchange", this, this.selections);
12099             }
12100         }
12101     },
12102
12103     /**
12104      * Returns true if the passed node is selected
12105      * @param {HTMLElement/Number} node The node or node index
12106      * @return {Boolean}
12107      */
12108     isSelected : function(node){
12109         var s = this.selections;
12110         if(s.length < 1){
12111             return false;
12112         }
12113         node = this.getNode(node);
12114         return s.indexOf(node) !== -1;
12115     },
12116
12117     /**
12118      * Selects nodes.
12119      * @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
12120      * @param {Boolean} keepExisting (optional) true to keep existing selections
12121      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12122      */
12123     select : function(nodeInfo, keepExisting, suppressEvent){
12124         if(nodeInfo instanceof Array){
12125             if(!keepExisting){
12126                 this.clearSelections(true);
12127             }
12128             for(var i = 0, len = nodeInfo.length; i < len; i++){
12129                 this.select(nodeInfo[i], true, true);
12130             }
12131             return;
12132         } 
12133         var node = this.getNode(nodeInfo);
12134         if(!node || this.isSelected(node)){
12135             return; // already selected.
12136         }
12137         if(!keepExisting){
12138             this.clearSelections(true);
12139         }
12140         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12141             Roo.fly(node).addClass(this.selectedClass);
12142             this.selections.push(node);
12143             if(!suppressEvent){
12144                 this.fireEvent("selectionchange", this, this.selections);
12145             }
12146         }
12147         
12148         
12149     },
12150       /**
12151      * Unselects nodes.
12152      * @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
12153      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12154      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12155      */
12156     unselect : function(nodeInfo, keepExisting, suppressEvent)
12157     {
12158         if(nodeInfo instanceof Array){
12159             Roo.each(this.selections, function(s) {
12160                 this.unselect(s, nodeInfo);
12161             }, this);
12162             return;
12163         }
12164         var node = this.getNode(nodeInfo);
12165         if(!node || !this.isSelected(node)){
12166             Roo.log("not selected");
12167             return; // not selected.
12168         }
12169         // fireevent???
12170         var ns = [];
12171         Roo.each(this.selections, function(s) {
12172             if (s == node ) {
12173                 Roo.fly(node).removeClass(this.selectedClass);
12174
12175                 return;
12176             }
12177             ns.push(s);
12178         },this);
12179         
12180         this.selections= ns;
12181         this.fireEvent("selectionchange", this, this.selections);
12182     },
12183
12184     /**
12185      * Gets a template node.
12186      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12187      * @return {HTMLElement} The node or null if it wasn't found
12188      */
12189     getNode : function(nodeInfo){
12190         if(typeof nodeInfo == "string"){
12191             return document.getElementById(nodeInfo);
12192         }else if(typeof nodeInfo == "number"){
12193             return this.nodes[nodeInfo];
12194         }
12195         return nodeInfo;
12196     },
12197
12198     /**
12199      * Gets a range template nodes.
12200      * @param {Number} startIndex
12201      * @param {Number} endIndex
12202      * @return {Array} An array of nodes
12203      */
12204     getNodes : function(start, end){
12205         var ns = this.nodes;
12206         start = start || 0;
12207         end = typeof end == "undefined" ? ns.length - 1 : end;
12208         var nodes = [];
12209         if(start <= end){
12210             for(var i = start; i <= end; i++){
12211                 nodes.push(ns[i]);
12212             }
12213         } else{
12214             for(var i = start; i >= end; i--){
12215                 nodes.push(ns[i]);
12216             }
12217         }
12218         return nodes;
12219     },
12220
12221     /**
12222      * Finds the index of the passed node
12223      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12224      * @return {Number} The index of the node or -1
12225      */
12226     indexOf : function(node){
12227         node = this.getNode(node);
12228         if(typeof node.nodeIndex == "number"){
12229             return node.nodeIndex;
12230         }
12231         var ns = this.nodes;
12232         for(var i = 0, len = ns.length; i < len; i++){
12233             if(ns[i] == node){
12234                 return i;
12235             }
12236         }
12237         return -1;
12238     }
12239 });
12240 /*
12241  * - LGPL
12242  *
12243  * based on jquery fullcalendar
12244  * 
12245  */
12246
12247 Roo.bootstrap = Roo.bootstrap || {};
12248 /**
12249  * @class Roo.bootstrap.Calendar
12250  * @extends Roo.bootstrap.Component
12251  * Bootstrap Calendar class
12252  * @cfg {Boolean} loadMask (true|false) default false
12253  * @cfg {Object} header generate the user specific header of the calendar, default false
12254
12255  * @constructor
12256  * Create a new Container
12257  * @param {Object} config The config object
12258  */
12259
12260
12261
12262 Roo.bootstrap.Calendar = function(config){
12263     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12264      this.addEvents({
12265         /**
12266              * @event select
12267              * Fires when a date is selected
12268              * @param {DatePicker} this
12269              * @param {Date} date The selected date
12270              */
12271         'select': true,
12272         /**
12273              * @event monthchange
12274              * Fires when the displayed month changes 
12275              * @param {DatePicker} this
12276              * @param {Date} date The selected month
12277              */
12278         'monthchange': true,
12279         /**
12280              * @event evententer
12281              * Fires when mouse over an event
12282              * @param {Calendar} this
12283              * @param {event} Event
12284              */
12285         'evententer': true,
12286         /**
12287              * @event eventleave
12288              * Fires when the mouse leaves an
12289              * @param {Calendar} this
12290              * @param {event}
12291              */
12292         'eventleave': true,
12293         /**
12294              * @event eventclick
12295              * Fires when the mouse click an
12296              * @param {Calendar} this
12297              * @param {event}
12298              */
12299         'eventclick': true
12300         
12301     });
12302
12303 };
12304
12305 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
12306     
12307      /**
12308      * @cfg {Number} startDay
12309      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
12310      */
12311     startDay : 0,
12312     
12313     loadMask : false,
12314     
12315     header : false,
12316       
12317     getAutoCreate : function(){
12318         
12319         
12320         var fc_button = function(name, corner, style, content ) {
12321             return Roo.apply({},{
12322                 tag : 'span',
12323                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
12324                          (corner.length ?
12325                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
12326                             ''
12327                         ),
12328                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
12329                 unselectable: 'on'
12330             });
12331         };
12332         
12333         var header = {};
12334         
12335         if(!this.header){
12336             header = {
12337                 tag : 'table',
12338                 cls : 'fc-header',
12339                 style : 'width:100%',
12340                 cn : [
12341                     {
12342                         tag: 'tr',
12343                         cn : [
12344                             {
12345                                 tag : 'td',
12346                                 cls : 'fc-header-left',
12347                                 cn : [
12348                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
12349                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
12350                                     { tag: 'span', cls: 'fc-header-space' },
12351                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
12352
12353
12354                                 ]
12355                             },
12356
12357                             {
12358                                 tag : 'td',
12359                                 cls : 'fc-header-center',
12360                                 cn : [
12361                                     {
12362                                         tag: 'span',
12363                                         cls: 'fc-header-title',
12364                                         cn : {
12365                                             tag: 'H2',
12366                                             html : 'month / year'
12367                                         }
12368                                     }
12369
12370                                 ]
12371                             },
12372                             {
12373                                 tag : 'td',
12374                                 cls : 'fc-header-right',
12375                                 cn : [
12376                               /*      fc_button('month', 'left', '', 'month' ),
12377                                     fc_button('week', '', '', 'week' ),
12378                                     fc_button('day', 'right', '', 'day' )
12379                                 */    
12380
12381                                 ]
12382                             }
12383
12384                         ]
12385                     }
12386                 ]
12387             };
12388         }
12389         
12390         header = this.header;
12391         
12392        
12393         var cal_heads = function() {
12394             var ret = [];
12395             // fixme - handle this.
12396             
12397             for (var i =0; i < Date.dayNames.length; i++) {
12398                 var d = Date.dayNames[i];
12399                 ret.push({
12400                     tag: 'th',
12401                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
12402                     html : d.substring(0,3)
12403                 });
12404                 
12405             }
12406             ret[0].cls += ' fc-first';
12407             ret[6].cls += ' fc-last';
12408             return ret;
12409         };
12410         var cal_cell = function(n) {
12411             return  {
12412                 tag: 'td',
12413                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
12414                 cn : [
12415                     {
12416                         cn : [
12417                             {
12418                                 cls: 'fc-day-number',
12419                                 html: 'D'
12420                             },
12421                             {
12422                                 cls: 'fc-day-content',
12423                              
12424                                 cn : [
12425                                      {
12426                                         style: 'position: relative;' // height: 17px;
12427                                     }
12428                                 ]
12429                             }
12430                             
12431                             
12432                         ]
12433                     }
12434                 ]
12435                 
12436             }
12437         };
12438         var cal_rows = function() {
12439             
12440             var ret = []
12441             for (var r = 0; r < 6; r++) {
12442                 var row= {
12443                     tag : 'tr',
12444                     cls : 'fc-week',
12445                     cn : []
12446                 };
12447                 
12448                 for (var i =0; i < Date.dayNames.length; i++) {
12449                     var d = Date.dayNames[i];
12450                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
12451
12452                 }
12453                 row.cn[0].cls+=' fc-first';
12454                 row.cn[0].cn[0].style = 'min-height:90px';
12455                 row.cn[6].cls+=' fc-last';
12456                 ret.push(row);
12457                 
12458             }
12459             ret[0].cls += ' fc-first';
12460             ret[4].cls += ' fc-prev-last';
12461             ret[5].cls += ' fc-last';
12462             return ret;
12463             
12464         };
12465         
12466         var cal_table = {
12467             tag: 'table',
12468             cls: 'fc-border-separate',
12469             style : 'width:100%',
12470             cellspacing  : 0,
12471             cn : [
12472                 { 
12473                     tag: 'thead',
12474                     cn : [
12475                         { 
12476                             tag: 'tr',
12477                             cls : 'fc-first fc-last',
12478                             cn : cal_heads()
12479                         }
12480                     ]
12481                 },
12482                 { 
12483                     tag: 'tbody',
12484                     cn : cal_rows()
12485                 }
12486                   
12487             ]
12488         };
12489          
12490          var cfg = {
12491             cls : 'fc fc-ltr',
12492             cn : [
12493                 header,
12494                 {
12495                     cls : 'fc-content',
12496                     style : "position: relative;",
12497                     cn : [
12498                         {
12499                             cls : 'fc-view fc-view-month fc-grid',
12500                             style : 'position: relative',
12501                             unselectable : 'on',
12502                             cn : [
12503                                 {
12504                                     cls : 'fc-event-container',
12505                                     style : 'position:absolute;z-index:8;top:0;left:0;'
12506                                 },
12507                                 cal_table
12508                             ]
12509                         }
12510                     ]
12511     
12512                 }
12513            ] 
12514             
12515         };
12516         
12517          
12518         
12519         return cfg;
12520     },
12521     
12522     
12523     initEvents : function()
12524     {
12525         if(!this.store){
12526             throw "can not find store for calendar";
12527         }
12528         
12529         var mark = {
12530             tag: "div",
12531             cls:"x-dlg-mask",
12532             style: "text-align:center",
12533             cn: [
12534                 {
12535                     tag: "div",
12536                     style: "background-color:white;width:50%;margin:250 auto",
12537                     cn: [
12538                         {
12539                             tag: "img",
12540                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
12541                         },
12542                         {
12543                             tag: "span",
12544                             html: "Loading"
12545                         }
12546                         
12547                     ]
12548                 }
12549             ]
12550         }
12551         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12552         
12553         var size = this.el.select('.fc-content', true).first().getSize();
12554         this.maskEl.setSize(size.width, size.height);
12555         this.maskEl.enableDisplayMode("block");
12556         if(!this.loadMask){
12557             this.maskEl.hide();
12558         }
12559         
12560         this.store = Roo.factory(this.store, Roo.data);
12561         this.store.on('load', this.onLoad, this);
12562         this.store.on('beforeload', this.onBeforeLoad, this);
12563         
12564         this.resize();
12565         
12566         this.cells = this.el.select('.fc-day',true);
12567         //Roo.log(this.cells);
12568         this.textNodes = this.el.query('.fc-day-number');
12569         this.cells.addClassOnOver('fc-state-hover');
12570         
12571         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12572         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12573         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12574         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12575         
12576         this.on('monthchange', this.onMonthChange, this);
12577         
12578         this.update(new Date().clearTime());
12579     },
12580     
12581     resize : function() {
12582         var sz  = this.el.getSize();
12583         
12584         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12585         this.el.select('.fc-day-content div',true).setHeight(34);
12586     },
12587     
12588     
12589     // private
12590     showPrevMonth : function(e){
12591         this.update(this.activeDate.add("mo", -1));
12592     },
12593     showToday : function(e){
12594         this.update(new Date().clearTime());
12595     },
12596     // private
12597     showNextMonth : function(e){
12598         this.update(this.activeDate.add("mo", 1));
12599     },
12600
12601     // private
12602     showPrevYear : function(){
12603         this.update(this.activeDate.add("y", -1));
12604     },
12605
12606     // private
12607     showNextYear : function(){
12608         this.update(this.activeDate.add("y", 1));
12609     },
12610
12611     
12612    // private
12613     update : function(date)
12614     {
12615         var vd = this.activeDate;
12616         this.activeDate = date;
12617 //        if(vd && this.el){
12618 //            var t = date.getTime();
12619 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12620 //                Roo.log('using add remove');
12621 //                
12622 //                this.fireEvent('monthchange', this, date);
12623 //                
12624 //                this.cells.removeClass("fc-state-highlight");
12625 //                this.cells.each(function(c){
12626 //                   if(c.dateValue == t){
12627 //                       c.addClass("fc-state-highlight");
12628 //                       setTimeout(function(){
12629 //                            try{c.dom.firstChild.focus();}catch(e){}
12630 //                       }, 50);
12631 //                       return false;
12632 //                   }
12633 //                   return true;
12634 //                });
12635 //                return;
12636 //            }
12637 //        }
12638         
12639         var days = date.getDaysInMonth();
12640         
12641         var firstOfMonth = date.getFirstDateOfMonth();
12642         var startingPos = firstOfMonth.getDay()-this.startDay;
12643         
12644         if(startingPos < this.startDay){
12645             startingPos += 7;
12646         }
12647         
12648         var pm = date.add(Date.MONTH, -1);
12649         var prevStart = pm.getDaysInMonth()-startingPos;
12650 //        
12651         this.cells = this.el.select('.fc-day',true);
12652         this.textNodes = this.el.query('.fc-day-number');
12653         this.cells.addClassOnOver('fc-state-hover');
12654         
12655         var cells = this.cells.elements;
12656         var textEls = this.textNodes;
12657         
12658         Roo.each(cells, function(cell){
12659             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12660         });
12661         
12662         days += startingPos;
12663
12664         // convert everything to numbers so it's fast
12665         var day = 86400000;
12666         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12667         //Roo.log(d);
12668         //Roo.log(pm);
12669         //Roo.log(prevStart);
12670         
12671         var today = new Date().clearTime().getTime();
12672         var sel = date.clearTime().getTime();
12673         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12674         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12675         var ddMatch = this.disabledDatesRE;
12676         var ddText = this.disabledDatesText;
12677         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12678         var ddaysText = this.disabledDaysText;
12679         var format = this.format;
12680         
12681         var setCellClass = function(cal, cell){
12682             cell.row = 0;
12683             cell.events = [];
12684             cell.more = [];
12685             //Roo.log('set Cell Class');
12686             cell.title = "";
12687             var t = d.getTime();
12688             
12689             //Roo.log(d);
12690             
12691             cell.dateValue = t;
12692             if(t == today){
12693                 cell.className += " fc-today";
12694                 cell.className += " fc-state-highlight";
12695                 cell.title = cal.todayText;
12696             }
12697             if(t == sel){
12698                 // disable highlight in other month..
12699                 //cell.className += " fc-state-highlight";
12700                 
12701             }
12702             // disabling
12703             if(t < min) {
12704                 cell.className = " fc-state-disabled";
12705                 cell.title = cal.minText;
12706                 return;
12707             }
12708             if(t > max) {
12709                 cell.className = " fc-state-disabled";
12710                 cell.title = cal.maxText;
12711                 return;
12712             }
12713             if(ddays){
12714                 if(ddays.indexOf(d.getDay()) != -1){
12715                     cell.title = ddaysText;
12716                     cell.className = " fc-state-disabled";
12717                 }
12718             }
12719             if(ddMatch && format){
12720                 var fvalue = d.dateFormat(format);
12721                 if(ddMatch.test(fvalue)){
12722                     cell.title = ddText.replace("%0", fvalue);
12723                     cell.className = " fc-state-disabled";
12724                 }
12725             }
12726             
12727             if (!cell.initialClassName) {
12728                 cell.initialClassName = cell.dom.className;
12729             }
12730             
12731             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
12732         };
12733
12734         var i = 0;
12735         
12736         for(; i < startingPos; i++) {
12737             textEls[i].innerHTML = (++prevStart);
12738             d.setDate(d.getDate()+1);
12739             
12740             cells[i].className = "fc-past fc-other-month";
12741             setCellClass(this, cells[i]);
12742         }
12743         
12744         var intDay = 0;
12745         
12746         for(; i < days; i++){
12747             intDay = i - startingPos + 1;
12748             textEls[i].innerHTML = (intDay);
12749             d.setDate(d.getDate()+1);
12750             
12751             cells[i].className = ''; // "x-date-active";
12752             setCellClass(this, cells[i]);
12753         }
12754         var extraDays = 0;
12755         
12756         for(; i < 42; i++) {
12757             textEls[i].innerHTML = (++extraDays);
12758             d.setDate(d.getDate()+1);
12759             
12760             cells[i].className = "fc-future fc-other-month";
12761             setCellClass(this, cells[i]);
12762         }
12763         
12764         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12765         
12766         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12767         
12768         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12769         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12770         
12771         if(totalRows != 6){
12772             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12773             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12774         }
12775         
12776         this.fireEvent('monthchange', this, date);
12777         
12778         
12779         /*
12780         if(!this.internalRender){
12781             var main = this.el.dom.firstChild;
12782             var w = main.offsetWidth;
12783             this.el.setWidth(w + this.el.getBorderWidth("lr"));
12784             Roo.fly(main).setWidth(w);
12785             this.internalRender = true;
12786             // opera does not respect the auto grow header center column
12787             // then, after it gets a width opera refuses to recalculate
12788             // without a second pass
12789             if(Roo.isOpera && !this.secondPass){
12790                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12791                 this.secondPass = true;
12792                 this.update.defer(10, this, [date]);
12793             }
12794         }
12795         */
12796         
12797     },
12798     
12799     findCell : function(dt) {
12800         dt = dt.clearTime().getTime();
12801         var ret = false;
12802         this.cells.each(function(c){
12803             //Roo.log("check " +c.dateValue + '?=' + dt);
12804             if(c.dateValue == dt){
12805                 ret = c;
12806                 return false;
12807             }
12808             return true;
12809         });
12810         
12811         return ret;
12812     },
12813     
12814     findCells : function(ev) {
12815         var s = ev.start.clone().clearTime().getTime();
12816        // Roo.log(s);
12817         var e= ev.end.clone().clearTime().getTime();
12818        // Roo.log(e);
12819         var ret = [];
12820         this.cells.each(function(c){
12821              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12822             
12823             if(c.dateValue > e){
12824                 return ;
12825             }
12826             if(c.dateValue < s){
12827                 return ;
12828             }
12829             ret.push(c);
12830         });
12831         
12832         return ret;    
12833     },
12834     
12835 //    findBestRow: function(cells)
12836 //    {
12837 //        var ret = 0;
12838 //        
12839 //        for (var i =0 ; i < cells.length;i++) {
12840 //            ret  = Math.max(cells[i].rows || 0,ret);
12841 //        }
12842 //        return ret;
12843 //        
12844 //    },
12845     
12846     
12847     addItem : function(ev)
12848     {
12849         // look for vertical location slot in
12850         var cells = this.findCells(ev);
12851         
12852 //        ev.row = this.findBestRow(cells);
12853         
12854         // work out the location.
12855         
12856         var crow = false;
12857         var rows = [];
12858         for(var i =0; i < cells.length; i++) {
12859             
12860             cells[i].row = cells[0].row;
12861             
12862             if(i == 0){
12863                 cells[i].row = cells[i].row + 1;
12864             }
12865             
12866             if (!crow) {
12867                 crow = {
12868                     start : cells[i],
12869                     end :  cells[i]
12870                 };
12871                 continue;
12872             }
12873             if (crow.start.getY() == cells[i].getY()) {
12874                 // on same row.
12875                 crow.end = cells[i];
12876                 continue;
12877             }
12878             // different row.
12879             rows.push(crow);
12880             crow = {
12881                 start: cells[i],
12882                 end : cells[i]
12883             };
12884             
12885         }
12886         
12887         rows.push(crow);
12888         ev.els = [];
12889         ev.rows = rows;
12890         ev.cells = cells;
12891         
12892         cells[0].events.push(ev);
12893         
12894         this.calevents.push(ev);
12895     },
12896     
12897     clearEvents: function() {
12898         
12899         if(!this.calevents){
12900             return;
12901         }
12902         
12903         Roo.each(this.cells.elements, function(c){
12904             c.row = 0;
12905             c.events = [];
12906             c.more = [];
12907         });
12908         
12909         Roo.each(this.calevents, function(e) {
12910             Roo.each(e.els, function(el) {
12911                 el.un('mouseenter' ,this.onEventEnter, this);
12912                 el.un('mouseleave' ,this.onEventLeave, this);
12913                 el.remove();
12914             },this);
12915         },this);
12916         
12917         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12918             e.remove();
12919         });
12920         
12921     },
12922     
12923     renderEvents: function()
12924     {   
12925         var _this = this;
12926         
12927         this.cells.each(function(c) {
12928             
12929             if(c.row < 5){
12930                 return;
12931             }
12932             
12933             var ev = c.events;
12934             
12935             var r = 4;
12936             if(c.row != c.events.length){
12937                 r = 4 - (4 - (c.row - c.events.length));
12938             }
12939             
12940             c.events = ev.slice(0, r);
12941             c.more = ev.slice(r);
12942             
12943             if(c.more.length && c.more.length == 1){
12944                 c.events.push(c.more.pop());
12945             }
12946             
12947             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12948             
12949         });
12950             
12951         this.cells.each(function(c) {
12952             
12953             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12954             
12955             
12956             for (var e = 0; e < c.events.length; e++){
12957                 var ev = c.events[e];
12958                 var rows = ev.rows;
12959                 
12960                 for(var i = 0; i < rows.length; i++) {
12961                 
12962                     // how many rows should it span..
12963
12964                     var  cfg = {
12965                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12966                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12967
12968                         unselectable : "on",
12969                         cn : [
12970                             {
12971                                 cls: 'fc-event-inner',
12972                                 cn : [
12973     //                                {
12974     //                                  tag:'span',
12975     //                                  cls: 'fc-event-time',
12976     //                                  html : cells.length > 1 ? '' : ev.time
12977     //                                },
12978                                     {
12979                                       tag:'span',
12980                                       cls: 'fc-event-title',
12981                                       html : String.format('{0}', ev.title)
12982                                     }
12983
12984
12985                                 ]
12986                             },
12987                             {
12988                                 cls: 'ui-resizable-handle ui-resizable-e',
12989                                 html : '&nbsp;&nbsp;&nbsp'
12990                             }
12991
12992                         ]
12993                     };
12994
12995                     if (i == 0) {
12996                         cfg.cls += ' fc-event-start';
12997                     }
12998                     if ((i+1) == rows.length) {
12999                         cfg.cls += ' fc-event-end';
13000                     }
13001
13002                     var ctr = _this.el.select('.fc-event-container',true).first();
13003                     var cg = ctr.createChild(cfg);
13004
13005                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13006                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13007
13008                     var r = (c.more.length) ? 1 : 0;
13009                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13010                     cg.setWidth(ebox.right - sbox.x -2);
13011
13012                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13013                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13014                     cg.on('click', _this.onEventClick, _this, ev);
13015
13016                     ev.els.push(cg);
13017                     
13018                 }
13019                 
13020             }
13021             
13022             
13023             if(c.more.length){
13024                 var  cfg = {
13025                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13026                     style : 'position: absolute',
13027                     unselectable : "on",
13028                     cn : [
13029                         {
13030                             cls: 'fc-event-inner',
13031                             cn : [
13032                                 {
13033                                   tag:'span',
13034                                   cls: 'fc-event-title',
13035                                   html : 'More'
13036                                 }
13037
13038
13039                             ]
13040                         },
13041                         {
13042                             cls: 'ui-resizable-handle ui-resizable-e',
13043                             html : '&nbsp;&nbsp;&nbsp'
13044                         }
13045
13046                     ]
13047                 };
13048
13049                 var ctr = _this.el.select('.fc-event-container',true).first();
13050                 var cg = ctr.createChild(cfg);
13051
13052                 var sbox = c.select('.fc-day-content',true).first().getBox();
13053                 var ebox = c.select('.fc-day-content',true).first().getBox();
13054                 //Roo.log(cg);
13055                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13056                 cg.setWidth(ebox.right - sbox.x -2);
13057
13058                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13059                 
13060             }
13061             
13062         });
13063         
13064         
13065         
13066     },
13067     
13068     onEventEnter: function (e, el,event,d) {
13069         this.fireEvent('evententer', this, el, event);
13070     },
13071     
13072     onEventLeave: function (e, el,event,d) {
13073         this.fireEvent('eventleave', this, el, event);
13074     },
13075     
13076     onEventClick: function (e, el,event,d) {
13077         this.fireEvent('eventclick', this, el, event);
13078     },
13079     
13080     onMonthChange: function () {
13081         this.store.load();
13082     },
13083     
13084     onMoreEventClick: function(e, el, more)
13085     {
13086         var _this = this;
13087         
13088         this.calpopover.placement = 'right';
13089         this.calpopover.setTitle('More');
13090         
13091         this.calpopover.setContent('');
13092         
13093         var ctr = this.calpopover.el.select('.popover-content', true).first();
13094         
13095         Roo.each(more, function(m){
13096             var cfg = {
13097                 cls : 'fc-event-hori fc-event-draggable',
13098                 html : m.title
13099             }
13100             var cg = ctr.createChild(cfg);
13101             
13102             cg.on('click', _this.onEventClick, _this, m);
13103         });
13104         
13105         this.calpopover.show(el);
13106         
13107         
13108     },
13109     
13110     onLoad: function () 
13111     {   
13112         this.calevents = [];
13113         var cal = this;
13114         
13115         if(this.store.getCount() > 0){
13116             this.store.data.each(function(d){
13117                cal.addItem({
13118                     id : d.data.id,
13119                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13120                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13121                     time : d.data.start_time,
13122                     title : d.data.title,
13123                     description : d.data.description,
13124                     venue : d.data.venue
13125                 });
13126             });
13127         }
13128         
13129         this.renderEvents();
13130         
13131         if(this.calevents.length && this.loadMask){
13132             this.maskEl.hide();
13133         }
13134     },
13135     
13136     onBeforeLoad: function()
13137     {
13138         this.clearEvents();
13139         if(this.loadMask){
13140             this.maskEl.show();
13141         }
13142     }
13143 });
13144
13145  
13146  /*
13147  * - LGPL
13148  *
13149  * element
13150  * 
13151  */
13152
13153 /**
13154  * @class Roo.bootstrap.Popover
13155  * @extends Roo.bootstrap.Component
13156  * Bootstrap Popover class
13157  * @cfg {String} html contents of the popover   (or false to use children..)
13158  * @cfg {String} title of popover (or false to hide)
13159  * @cfg {String} placement how it is placed
13160  * @cfg {String} trigger click || hover (or false to trigger manually)
13161  * @cfg {String} over what (parent or false to trigger manually.)
13162  * 
13163  * @constructor
13164  * Create a new Popover
13165  * @param {Object} config The config object
13166  */
13167
13168 Roo.bootstrap.Popover = function(config){
13169     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13170 };
13171
13172 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13173     
13174     title: 'Fill in a title',
13175     html: false,
13176     
13177     placement : 'right',
13178     trigger : 'hover', // hover
13179     
13180     over: 'parent',
13181     
13182     can_build_overlaid : false,
13183     
13184     getChildContainer : function()
13185     {
13186         return this.el.select('.popover-content',true).first();
13187     },
13188     
13189     getAutoCreate : function(){
13190          Roo.log('make popover?');
13191         var cfg = {
13192            cls : 'popover roo-dynamic',
13193            style: 'display:block',
13194            cn : [
13195                 {
13196                     cls : 'arrow'
13197                 },
13198                 {
13199                     cls : 'popover-inner',
13200                     cn : [
13201                         {
13202                             tag: 'h3',
13203                             cls: 'popover-title',
13204                             html : this.title
13205                         },
13206                         {
13207                             cls : 'popover-content',
13208                             html : this.html
13209                         }
13210                     ]
13211                     
13212                 }
13213            ]
13214         };
13215         
13216         return cfg;
13217     },
13218     setTitle: function(str)
13219     {
13220         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13221     },
13222     setContent: function(str)
13223     {
13224         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13225     },
13226     // as it get's added to the bottom of the page.
13227     onRender : function(ct, position)
13228     {
13229         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13230         if(!this.el){
13231             var cfg = Roo.apply({},  this.getAutoCreate());
13232             cfg.id = Roo.id();
13233             
13234             if (this.cls) {
13235                 cfg.cls += ' ' + this.cls;
13236             }
13237             if (this.style) {
13238                 cfg.style = this.style;
13239             }
13240             Roo.log("adding to ")
13241             this.el = Roo.get(document.body).createChild(cfg, position);
13242             Roo.log(this.el);
13243         }
13244         this.initEvents();
13245     },
13246     
13247     initEvents : function()
13248     {
13249         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13250         this.el.enableDisplayMode('block');
13251         this.el.hide();
13252         if (this.over === false) {
13253             return; 
13254         }
13255         if (this.triggers === false) {
13256             return;
13257         }
13258         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13259         var triggers = this.trigger ? this.trigger.split(' ') : [];
13260         Roo.each(triggers, function(trigger) {
13261         
13262             if (trigger == 'click') {
13263                 on_el.on('click', this.toggle, this);
13264             } else if (trigger != 'manual') {
13265                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
13266                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
13267       
13268                 on_el.on(eventIn  ,this.enter, this);
13269                 on_el.on(eventOut, this.leave, this);
13270             }
13271         }, this);
13272         
13273     },
13274     
13275     
13276     // private
13277     timeout : null,
13278     hoverState : null,
13279     
13280     toggle : function () {
13281         this.hoverState == 'in' ? this.leave() : this.enter();
13282     },
13283     
13284     enter : function () {
13285        
13286     
13287         clearTimeout(this.timeout);
13288     
13289         this.hoverState = 'in'
13290     
13291         if (!this.delay || !this.delay.show) {
13292             this.show();
13293             return 
13294         }
13295         var _t = this;
13296         this.timeout = setTimeout(function () {
13297             if (_t.hoverState == 'in') {
13298                 _t.show();
13299             }
13300         }, this.delay.show)
13301     },
13302     leave : function() {
13303         clearTimeout(this.timeout);
13304     
13305         this.hoverState = 'out'
13306     
13307         if (!this.delay || !this.delay.hide) {
13308             this.hide();
13309             return 
13310         }
13311         var _t = this;
13312         this.timeout = setTimeout(function () {
13313             if (_t.hoverState == 'out') {
13314                 _t.hide();
13315             }
13316         }, this.delay.hide)
13317     },
13318     
13319     show : function (on_el)
13320     {
13321         if (!on_el) {
13322             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13323         }
13324         // set content.
13325         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
13326         if (this.html !== false) {
13327             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
13328         }
13329         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
13330         if (!this.title.length) {
13331             this.el.select('.popover-title',true).hide();
13332         }
13333         
13334         var placement = typeof this.placement == 'function' ?
13335             this.placement.call(this, this.el, on_el) :
13336             this.placement;
13337             
13338         var autoToken = /\s?auto?\s?/i;
13339         var autoPlace = autoToken.test(placement);
13340         if (autoPlace) {
13341             placement = placement.replace(autoToken, '') || 'top';
13342         }
13343         
13344         //this.el.detach()
13345         //this.el.setXY([0,0]);
13346         this.el.show();
13347         this.el.dom.style.display='block';
13348         this.el.addClass(placement);
13349         
13350         //this.el.appendTo(on_el);
13351         
13352         var p = this.getPosition();
13353         var box = this.el.getBox();
13354         
13355         if (autoPlace) {
13356             // fixme..
13357         }
13358         var align = Roo.bootstrap.Popover.alignment[placement]
13359         this.el.alignTo(on_el, align[0],align[1]);
13360         //var arrow = this.el.select('.arrow',true).first();
13361         //arrow.set(align[2], 
13362         
13363         this.el.addClass('in');
13364         this.hoverState = null;
13365         
13366         if (this.el.hasClass('fade')) {
13367             // fade it?
13368         }
13369         
13370     },
13371     hide : function()
13372     {
13373         this.el.setXY([0,0]);
13374         this.el.removeClass('in');
13375         this.el.hide();
13376         
13377     }
13378     
13379 });
13380
13381 Roo.bootstrap.Popover.alignment = {
13382     'left' : ['r-l', [-10,0], 'right'],
13383     'right' : ['l-r', [10,0], 'left'],
13384     'bottom' : ['t-b', [0,10], 'top'],
13385     'top' : [ 'b-t', [0,-10], 'bottom']
13386 };
13387
13388  /*
13389  * - LGPL
13390  *
13391  * Progress
13392  * 
13393  */
13394
13395 /**
13396  * @class Roo.bootstrap.Progress
13397  * @extends Roo.bootstrap.Component
13398  * Bootstrap Progress class
13399  * @cfg {Boolean} striped striped of the progress bar
13400  * @cfg {Boolean} active animated of the progress bar
13401  * 
13402  * 
13403  * @constructor
13404  * Create a new Progress
13405  * @param {Object} config The config object
13406  */
13407
13408 Roo.bootstrap.Progress = function(config){
13409     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
13410 };
13411
13412 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
13413     
13414     striped : false,
13415     active: false,
13416     
13417     getAutoCreate : function(){
13418         var cfg = {
13419             tag: 'div',
13420             cls: 'progress'
13421         };
13422         
13423         
13424         if(this.striped){
13425             cfg.cls += ' progress-striped';
13426         }
13427       
13428         if(this.active){
13429             cfg.cls += ' active';
13430         }
13431         
13432         
13433         return cfg;
13434     }
13435    
13436 });
13437
13438  
13439
13440  /*
13441  * - LGPL
13442  *
13443  * ProgressBar
13444  * 
13445  */
13446
13447 /**
13448  * @class Roo.bootstrap.ProgressBar
13449  * @extends Roo.bootstrap.Component
13450  * Bootstrap ProgressBar class
13451  * @cfg {Number} aria_valuenow aria-value now
13452  * @cfg {Number} aria_valuemin aria-value min
13453  * @cfg {Number} aria_valuemax aria-value max
13454  * @cfg {String} label label for the progress bar
13455  * @cfg {String} panel (success | info | warning | danger )
13456  * @cfg {String} role role of the progress bar
13457  * @cfg {String} sr_only text
13458  * 
13459  * 
13460  * @constructor
13461  * Create a new ProgressBar
13462  * @param {Object} config The config object
13463  */
13464
13465 Roo.bootstrap.ProgressBar = function(config){
13466     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
13467 };
13468
13469 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
13470     
13471     aria_valuenow : 0,
13472     aria_valuemin : 0,
13473     aria_valuemax : 100,
13474     label : false,
13475     panel : false,
13476     role : false,
13477     sr_only: false,
13478     
13479     getAutoCreate : function()
13480     {
13481         
13482         var cfg = {
13483             tag: 'div',
13484             cls: 'progress-bar',
13485             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
13486         };
13487         
13488         if(this.sr_only){
13489             cfg.cn = {
13490                 tag: 'span',
13491                 cls: 'sr-only',
13492                 html: this.sr_only
13493             }
13494         }
13495         
13496         if(this.role){
13497             cfg.role = this.role;
13498         }
13499         
13500         if(this.aria_valuenow){
13501             cfg['aria-valuenow'] = this.aria_valuenow;
13502         }
13503         
13504         if(this.aria_valuemin){
13505             cfg['aria-valuemin'] = this.aria_valuemin;
13506         }
13507         
13508         if(this.aria_valuemax){
13509             cfg['aria-valuemax'] = this.aria_valuemax;
13510         }
13511         
13512         if(this.label && !this.sr_only){
13513             cfg.html = this.label;
13514         }
13515         
13516         if(this.panel){
13517             cfg.cls += ' progress-bar-' + this.panel;
13518         }
13519         
13520         return cfg;
13521     },
13522     
13523     update : function(aria_valuenow)
13524     {
13525         this.aria_valuenow = aria_valuenow;
13526         
13527         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13528     }
13529    
13530 });
13531
13532  
13533
13534  /*
13535  * - LGPL
13536  *
13537  * TabPanel
13538  * 
13539  */
13540
13541 /**
13542  * @class Roo.bootstrap.TabPanel
13543  * @extends Roo.bootstrap.Component
13544  * Bootstrap TabPanel class
13545  * @cfg {Boolean} active panel active
13546  * @cfg {String} html panel content
13547  * @cfg {String} tabId tab relate id
13548  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13549  * 
13550  * 
13551  * @constructor
13552  * Create a new TabPanel
13553  * @param {Object} config The config object
13554  */
13555
13556 Roo.bootstrap.TabPanel = function(config){
13557     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13558      this.addEvents({
13559         /**
13560              * @event changed
13561              * Fires when the active status changes
13562              * @param {Roo.bootstrap.TabPanel} this
13563              * @param {Boolean} state the new state
13564             
13565          */
13566         'changed': true
13567      });
13568 };
13569
13570 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
13571     
13572     active: false,
13573     html: false,
13574     tabId: false,
13575     navId : false,
13576     
13577     getAutoCreate : function(){
13578         var cfg = {
13579             tag: 'div',
13580             cls: 'tab-pane',
13581             html: this.html || ''
13582         };
13583         
13584         if(this.active){
13585             cfg.cls += ' active';
13586         }
13587         
13588         if(this.tabId){
13589             cfg.tabId = this.tabId;
13590         }
13591         
13592         return cfg;
13593     },
13594     onRender : function(ct, position)
13595     {
13596        // Roo.log("Call onRender: " + this.xtype);
13597         
13598         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13599         
13600         if (this.navId && this.tabId) {
13601             var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13602             if (!item) {
13603                 Roo.log("could not find navID:"  + this.navId + ", tabId: " + this.tabId);
13604             } else {
13605                 item.on('changed', function(item, state) {
13606                     this.setActive(state);
13607                 }, this);
13608             }
13609         }
13610         
13611     },
13612     setActive: function(state)
13613     {
13614         Roo.log("panel - set active " + this.tabId + "=" + state);
13615         
13616         this.active = state;
13617         if (!state) {
13618             this.el.removeClass('active');
13619             
13620         } else  if (!this.el.hasClass('active')) {
13621             this.el.addClass('active');
13622         }
13623         this.fireEvent('changed', this, state);
13624     }
13625     
13626     
13627 });
13628  
13629
13630  
13631
13632  /*
13633  * - LGPL
13634  *
13635  * DateField
13636  * 
13637  */
13638
13639 /**
13640  * @class Roo.bootstrap.DateField
13641  * @extends Roo.bootstrap.Input
13642  * Bootstrap DateField class
13643  * @cfg {Number} weekStart default 0
13644  * @cfg {Number} weekStart default 0
13645  * @cfg {Number} viewMode default empty, (months|years)
13646  * @cfg {Number} minViewMode default empty, (months|years)
13647  * @cfg {Number} startDate default -Infinity
13648  * @cfg {Number} endDate default Infinity
13649  * @cfg {Boolean} todayHighlight default false
13650  * @cfg {Boolean} todayBtn default false
13651  * @cfg {Boolean} calendarWeeks default false
13652  * @cfg {Object} daysOfWeekDisabled default empty
13653  * 
13654  * @cfg {Boolean} keyboardNavigation default true
13655  * @cfg {String} language default en
13656  * 
13657  * @constructor
13658  * Create a new DateField
13659  * @param {Object} config The config object
13660  */
13661
13662 Roo.bootstrap.DateField = function(config){
13663     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13664      this.addEvents({
13665             /**
13666              * @event show
13667              * Fires when this field show.
13668              * @param {Roo.bootstrap.DateField} this
13669              * @param {Mixed} date The date value
13670              */
13671             show : true,
13672             /**
13673              * @event show
13674              * Fires when this field hide.
13675              * @param {Roo.bootstrap.DateField} this
13676              * @param {Mixed} date The date value
13677              */
13678             hide : true,
13679             /**
13680              * @event select
13681              * Fires when select a date.
13682              * @param {Roo.bootstrap.DateField} this
13683              * @param {Mixed} date The date value
13684              */
13685             select : true
13686         });
13687 };
13688
13689 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
13690     
13691     /**
13692      * @cfg {String} format
13693      * The default date format string which can be overriden for localization support.  The format must be
13694      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13695      */
13696     format : "m/d/y",
13697     /**
13698      * @cfg {String} altFormats
13699      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13700      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13701      */
13702     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13703     
13704     weekStart : 0,
13705     
13706     viewMode : '',
13707     
13708     minViewMode : '',
13709     
13710     todayHighlight : false,
13711     
13712     todayBtn: false,
13713     
13714     language: 'en',
13715     
13716     keyboardNavigation: true,
13717     
13718     calendarWeeks: false,
13719     
13720     startDate: -Infinity,
13721     
13722     endDate: Infinity,
13723     
13724     daysOfWeekDisabled: [],
13725     
13726     _events: [],
13727     
13728     UTCDate: function()
13729     {
13730         return new Date(Date.UTC.apply(Date, arguments));
13731     },
13732     
13733     UTCToday: function()
13734     {
13735         var today = new Date();
13736         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13737     },
13738     
13739     getDate: function() {
13740             var d = this.getUTCDate();
13741             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13742     },
13743     
13744     getUTCDate: function() {
13745             return this.date;
13746     },
13747     
13748     setDate: function(d) {
13749             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13750     },
13751     
13752     setUTCDate: function(d) {
13753             this.date = d;
13754             this.setValue(this.formatDate(this.date));
13755     },
13756         
13757     onRender: function(ct, position)
13758     {
13759         
13760         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13761         
13762         this.language = this.language || 'en';
13763         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13764         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13765         
13766         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13767         this.format = this.format || 'm/d/y';
13768         this.isInline = false;
13769         this.isInput = true;
13770         this.component = this.el.select('.add-on', true).first() || false;
13771         this.component = (this.component && this.component.length === 0) ? false : this.component;
13772         this.hasInput = this.component && this.inputEL().length;
13773         
13774         if (typeof(this.minViewMode === 'string')) {
13775             switch (this.minViewMode) {
13776                 case 'months':
13777                     this.minViewMode = 1;
13778                     break;
13779                 case 'years':
13780                     this.minViewMode = 2;
13781                     break;
13782                 default:
13783                     this.minViewMode = 0;
13784                     break;
13785             }
13786         }
13787         
13788         if (typeof(this.viewMode === 'string')) {
13789             switch (this.viewMode) {
13790                 case 'months':
13791                     this.viewMode = 1;
13792                     break;
13793                 case 'years':
13794                     this.viewMode = 2;
13795                     break;
13796                 default:
13797                     this.viewMode = 0;
13798                     break;
13799             }
13800         }
13801                 
13802         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13803         
13804         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13805         
13806         this.picker().on('mousedown', this.onMousedown, this);
13807         this.picker().on('click', this.onClick, this);
13808         
13809         this.picker().addClass('datepicker-dropdown');
13810         
13811         this.startViewMode = this.viewMode;
13812         
13813         
13814         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13815             if(!this.calendarWeeks){
13816                 v.remove();
13817                 return;
13818             };
13819             
13820             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13821             v.attr('colspan', function(i, val){
13822                 return parseInt(val) + 1;
13823             });
13824         })
13825                         
13826         
13827         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13828         
13829         this.setStartDate(this.startDate);
13830         this.setEndDate(this.endDate);
13831         
13832         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13833         
13834         this.fillDow();
13835         this.fillMonths();
13836         this.update();
13837         this.showMode();
13838         
13839         if(this.isInline) {
13840             this.show();
13841         }
13842     },
13843     
13844     picker : function()
13845     {
13846         return this.el.select('.datepicker', true).first();
13847     },
13848     
13849     fillDow: function()
13850     {
13851         var dowCnt = this.weekStart;
13852         
13853         var dow = {
13854             tag: 'tr',
13855             cn: [
13856                 
13857             ]
13858         };
13859         
13860         if(this.calendarWeeks){
13861             dow.cn.push({
13862                 tag: 'th',
13863                 cls: 'cw',
13864                 html: '&nbsp;'
13865             })
13866         }
13867         
13868         while (dowCnt < this.weekStart + 7) {
13869             dow.cn.push({
13870                 tag: 'th',
13871                 cls: 'dow',
13872                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13873             });
13874         }
13875         
13876         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13877     },
13878     
13879     fillMonths: function()
13880     {    
13881         var i = 0
13882         var months = this.picker().select('>.datepicker-months td', true).first();
13883         
13884         months.dom.innerHTML = '';
13885         
13886         while (i < 12) {
13887             var month = {
13888                 tag: 'span',
13889                 cls: 'month',
13890                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13891             }
13892             
13893             months.createChild(month);
13894         }
13895         
13896     },
13897     
13898     update: function()
13899     {
13900         
13901         this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13902         
13903         if (this.date < this.startDate) {
13904             this.viewDate = new Date(this.startDate);
13905         } else if (this.date > this.endDate) {
13906             this.viewDate = new Date(this.endDate);
13907         } else {
13908             this.viewDate = new Date(this.date);
13909         }
13910         
13911         this.fill();
13912     },
13913     
13914     fill: function() 
13915     {
13916         var d = new Date(this.viewDate),
13917                 year = d.getUTCFullYear(),
13918                 month = d.getUTCMonth(),
13919                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13920                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13921                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13922                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13923                 currentDate = this.date && this.date.valueOf(),
13924                 today = this.UTCToday();
13925         
13926         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13927         
13928 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13929         
13930 //        this.picker.select('>tfoot th.today').
13931 //                                              .text(dates[this.language].today)
13932 //                                              .toggle(this.todayBtn !== false);
13933     
13934         this.updateNavArrows();
13935         this.fillMonths();
13936                                                 
13937         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13938         
13939         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13940          
13941         prevMonth.setUTCDate(day);
13942         
13943         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13944         
13945         var nextMonth = new Date(prevMonth);
13946         
13947         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13948         
13949         nextMonth = nextMonth.valueOf();
13950         
13951         var fillMonths = false;
13952         
13953         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13954         
13955         while(prevMonth.valueOf() < nextMonth) {
13956             var clsName = '';
13957             
13958             if (prevMonth.getUTCDay() === this.weekStart) {
13959                 if(fillMonths){
13960                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13961                 }
13962                     
13963                 fillMonths = {
13964                     tag: 'tr',
13965                     cn: []
13966                 };
13967                 
13968                 if(this.calendarWeeks){
13969                     // ISO 8601: First week contains first thursday.
13970                     // ISO also states week starts on Monday, but we can be more abstract here.
13971                     var
13972                     // Start of current week: based on weekstart/current date
13973                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13974                     // Thursday of this week
13975                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13976                     // First Thursday of year, year from thursday
13977                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13978                     // Calendar week: ms between thursdays, div ms per day, div 7 days
13979                     calWeek =  (th - yth) / 864e5 / 7 + 1;
13980                     
13981                     fillMonths.cn.push({
13982                         tag: 'td',
13983                         cls: 'cw',
13984                         html: calWeek
13985                     });
13986                 }
13987             }
13988             
13989             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13990                 clsName += ' old';
13991             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13992                 clsName += ' new';
13993             }
13994             if (this.todayHighlight &&
13995                 prevMonth.getUTCFullYear() == today.getFullYear() &&
13996                 prevMonth.getUTCMonth() == today.getMonth() &&
13997                 prevMonth.getUTCDate() == today.getDate()) {
13998                 clsName += ' today';
13999             }
14000             
14001             if (currentDate && prevMonth.valueOf() === currentDate) {
14002                 clsName += ' active';
14003             }
14004             
14005             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14006                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14007                     clsName += ' disabled';
14008             }
14009             
14010             fillMonths.cn.push({
14011                 tag: 'td',
14012                 cls: 'day ' + clsName,
14013                 html: prevMonth.getDate()
14014             })
14015             
14016             prevMonth.setDate(prevMonth.getDate()+1);
14017         }
14018           
14019         var currentYear = this.date && this.date.getUTCFullYear();
14020         var currentMonth = this.date && this.date.getUTCMonth();
14021         
14022         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14023         
14024         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14025             v.removeClass('active');
14026             
14027             if(currentYear === year && k === currentMonth){
14028                 v.addClass('active');
14029             }
14030             
14031             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14032                 v.addClass('disabled');
14033             }
14034             
14035         });
14036         
14037         
14038         year = parseInt(year/10, 10) * 10;
14039         
14040         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14041         
14042         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14043         
14044         year -= 1;
14045         for (var i = -1; i < 11; i++) {
14046             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
14047                 tag: 'span',
14048                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
14049                 html: year
14050             })
14051             
14052             year += 1;
14053         }
14054     },
14055     
14056     showMode: function(dir) 
14057     {
14058         if (dir) {
14059             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
14060         }
14061         Roo.each(this.picker().select('>div',true).elements, function(v){
14062             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14063             v.hide();
14064         });
14065         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
14066     },
14067     
14068     place: function()
14069     {
14070         if(this.isInline) return;
14071         
14072         this.picker().removeClass(['bottom', 'top']);
14073         
14074         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
14075             /*
14076              * place to the top of element!
14077              *
14078              */
14079             
14080             this.picker().addClass('top');
14081             this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14082             
14083             return;
14084         }
14085         
14086         this.picker().addClass('bottom');
14087         
14088         this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
14089     },
14090     
14091     parseDate : function(value)
14092     {
14093         if(!value || value instanceof Date){
14094             return value;
14095         }
14096         var v = Date.parseDate(value, this.format);
14097         if (!v && this.useIso) {
14098             v = Date.parseDate(value, 'Y-m-d');
14099         }
14100         if(!v && this.altFormats){
14101             if(!this.altFormatsArray){
14102                 this.altFormatsArray = this.altFormats.split("|");
14103             }
14104             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
14105                 v = Date.parseDate(value, this.altFormatsArray[i]);
14106             }
14107         }
14108         return v;
14109     },
14110     
14111     formatDate : function(date, fmt)
14112     {
14113         return (!date || !(date instanceof Date)) ?
14114         date : date.dateFormat(fmt || this.format);
14115     },
14116     
14117     onFocus : function()
14118     {
14119         Roo.bootstrap.DateField.superclass.onFocus.call(this);
14120         this.show();
14121     },
14122     
14123     onBlur : function()
14124     {
14125         Roo.bootstrap.DateField.superclass.onBlur.call(this);
14126         
14127         var d = this.inputEl().getValue();
14128         
14129         if(d && d.length){
14130             this.setValue(d);
14131         }
14132                 
14133         this.hide();
14134     },
14135     
14136     show : function()
14137     {
14138         this.picker().show();
14139         this.update();
14140         this.place();
14141         
14142         this.fireEvent('show', this, this.date);
14143     },
14144     
14145     hide : function()
14146     {
14147         if(this.isInline) return;
14148         this.picker().hide();
14149         this.viewMode = this.startViewMode;
14150         this.showMode();
14151         
14152         this.fireEvent('hide', this, this.date);
14153         
14154     },
14155     
14156     onMousedown: function(e)
14157     {
14158         e.stopPropagation();
14159         e.preventDefault();
14160     },
14161     
14162     keyup: function(e)
14163     {
14164         Roo.bootstrap.DateField.superclass.keyup.call(this);
14165         this.update();
14166     },
14167
14168     setValue: function(v)
14169     {
14170         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
14171         
14172         var d = new Date(v);
14173         
14174         if(isNaN(d.getTime())){
14175             return;
14176         }
14177         
14178         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
14179
14180         this.update();
14181
14182         this.fireEvent('select', this, this.date);
14183         
14184     },
14185     
14186     getValue: function()
14187     {
14188         return this.formatDate(this.date);
14189     },
14190     
14191     fireKey: function(e)
14192     {
14193         if (!this.picker().isVisible()){
14194             if (e.keyCode == 27) // allow escape to hide and re-show picker
14195                 this.show();
14196             return;
14197         }
14198         var dateChanged = false,
14199         dir, day, month,
14200         newDate, newViewDate;
14201         
14202         switch(e.keyCode){
14203             case 27: // escape
14204                 this.hide();
14205                 e.preventDefault();
14206                 break;
14207             case 37: // left
14208             case 39: // right
14209                 if (!this.keyboardNavigation) break;
14210                 dir = e.keyCode == 37 ? -1 : 1;
14211                 
14212                 if (e.ctrlKey){
14213                     newDate = this.moveYear(this.date, dir);
14214                     newViewDate = this.moveYear(this.viewDate, dir);
14215                 } else if (e.shiftKey){
14216                     newDate = this.moveMonth(this.date, dir);
14217                     newViewDate = this.moveMonth(this.viewDate, dir);
14218                 } else {
14219                     newDate = new Date(this.date);
14220                     newDate.setUTCDate(this.date.getUTCDate() + dir);
14221                     newViewDate = new Date(this.viewDate);
14222                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
14223                 }
14224                 if (this.dateWithinRange(newDate)){
14225                     this.date = newDate;
14226                     this.viewDate = newViewDate;
14227                     this.setValue(this.formatDate(this.date));
14228 //                    this.update();
14229                     e.preventDefault();
14230                     dateChanged = true;
14231                 }
14232                 break;
14233             case 38: // up
14234             case 40: // down
14235                 if (!this.keyboardNavigation) break;
14236                 dir = e.keyCode == 38 ? -1 : 1;
14237                 if (e.ctrlKey){
14238                     newDate = this.moveYear(this.date, dir);
14239                     newViewDate = this.moveYear(this.viewDate, dir);
14240                 } else if (e.shiftKey){
14241                     newDate = this.moveMonth(this.date, dir);
14242                     newViewDate = this.moveMonth(this.viewDate, dir);
14243                 } else {
14244                     newDate = new Date(this.date);
14245                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
14246                     newViewDate = new Date(this.viewDate);
14247                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
14248                 }
14249                 if (this.dateWithinRange(newDate)){
14250                     this.date = newDate;
14251                     this.viewDate = newViewDate;
14252                     this.setValue(this.formatDate(this.date));
14253 //                    this.update();
14254                     e.preventDefault();
14255                     dateChanged = true;
14256                 }
14257                 break;
14258             case 13: // enter
14259                 this.setValue(this.formatDate(this.date));
14260                 this.hide();
14261                 e.preventDefault();
14262                 break;
14263             case 9: // tab
14264                 this.setValue(this.formatDate(this.date));
14265                 this.hide();
14266                 break;
14267                 
14268         }
14269     },
14270     
14271     
14272     onClick: function(e) 
14273     {
14274         e.stopPropagation();
14275         e.preventDefault();
14276         
14277         var target = e.getTarget();
14278         
14279         if(target.nodeName.toLowerCase() === 'i'){
14280             target = Roo.get(target).dom.parentNode;
14281         }
14282         
14283         var nodeName = target.nodeName;
14284         var className = target.className;
14285         var html = target.innerHTML;
14286         
14287         switch(nodeName.toLowerCase()) {
14288             case 'th':
14289                 switch(className) {
14290                     case 'switch':
14291                         this.showMode(1);
14292                         break;
14293                     case 'prev':
14294                     case 'next':
14295                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
14296                         switch(this.viewMode){
14297                                 case 0:
14298                                         this.viewDate = this.moveMonth(this.viewDate, dir);
14299                                         break;
14300                                 case 1:
14301                                 case 2:
14302                                         this.viewDate = this.moveYear(this.viewDate, dir);
14303                                         break;
14304                         }
14305                         this.fill();
14306                         break;
14307                     case 'today':
14308                         var date = new Date();
14309                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
14310 //                        this.fill()
14311                         this.setValue(this.formatDate(this.date));
14312                         
14313                         this.hide();
14314                         break;
14315                 }
14316                 break;
14317             case 'span':
14318                 if (className.indexOf('disabled') === -1) {
14319                     this.viewDate.setUTCDate(1);
14320                     if (className.indexOf('month') !== -1) {
14321                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
14322                     } else {
14323                         var year = parseInt(html, 10) || 0;
14324                         this.viewDate.setUTCFullYear(year);
14325                         
14326                     }
14327                     this.showMode(-1);
14328                     this.fill();
14329                 }
14330                 break;
14331                 
14332             case 'td':
14333                 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
14334                     var day = parseInt(html, 10) || 1;
14335                     var year = this.viewDate.getUTCFullYear(),
14336                         month = this.viewDate.getUTCMonth();
14337
14338                     if (className.indexOf('old') !== -1) {
14339                         if(month === 0 ){
14340                             month = 11;
14341                             year -= 1;
14342                         }else{
14343                             month -= 1;
14344                         }
14345                     } else if (className.indexOf('new') !== -1) {
14346                         if (month == 11) {
14347                             month = 0;
14348                             year += 1;
14349                         } else {
14350                             month += 1;
14351                         }
14352                     }
14353                     this.date = this.UTCDate(year, month, day,0,0,0,0);
14354                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
14355 //                    this.fill();
14356                     this.setValue(this.formatDate(this.date));
14357                     this.hide();
14358                 }
14359                 break;
14360         }
14361     },
14362     
14363     setStartDate: function(startDate)
14364     {
14365         this.startDate = startDate || -Infinity;
14366         if (this.startDate !== -Infinity) {
14367             this.startDate = this.parseDate(this.startDate);
14368         }
14369         this.update();
14370         this.updateNavArrows();
14371     },
14372
14373     setEndDate: function(endDate)
14374     {
14375         this.endDate = endDate || Infinity;
14376         if (this.endDate !== Infinity) {
14377             this.endDate = this.parseDate(this.endDate);
14378         }
14379         this.update();
14380         this.updateNavArrows();
14381     },
14382     
14383     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
14384     {
14385         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
14386         if (typeof(this.daysOfWeekDisabled) !== 'object') {
14387             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
14388         }
14389         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
14390             return parseInt(d, 10);
14391         });
14392         this.update();
14393         this.updateNavArrows();
14394     },
14395     
14396     updateNavArrows: function() 
14397     {
14398         var d = new Date(this.viewDate),
14399         year = d.getUTCFullYear(),
14400         month = d.getUTCMonth();
14401         
14402         Roo.each(this.picker().select('.prev', true).elements, function(v){
14403             v.show();
14404             switch (this.viewMode) {
14405                 case 0:
14406
14407                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
14408                         v.hide();
14409                     }
14410                     break;
14411                 case 1:
14412                 case 2:
14413                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
14414                         v.hide();
14415                     }
14416                     break;
14417             }
14418         });
14419         
14420         Roo.each(this.picker().select('.next', true).elements, function(v){
14421             v.show();
14422             switch (this.viewMode) {
14423                 case 0:
14424
14425                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
14426                         v.hide();
14427                     }
14428                     break;
14429                 case 1:
14430                 case 2:
14431                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
14432                         v.hide();
14433                     }
14434                     break;
14435             }
14436         })
14437     },
14438     
14439     moveMonth: function(date, dir)
14440     {
14441         if (!dir) return date;
14442         var new_date = new Date(date.valueOf()),
14443         day = new_date.getUTCDate(),
14444         month = new_date.getUTCMonth(),
14445         mag = Math.abs(dir),
14446         new_month, test;
14447         dir = dir > 0 ? 1 : -1;
14448         if (mag == 1){
14449             test = dir == -1
14450             // If going back one month, make sure month is not current month
14451             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
14452             ? function(){
14453                 return new_date.getUTCMonth() == month;
14454             }
14455             // If going forward one month, make sure month is as expected
14456             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
14457             : function(){
14458                 return new_date.getUTCMonth() != new_month;
14459             };
14460             new_month = month + dir;
14461             new_date.setUTCMonth(new_month);
14462             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
14463             if (new_month < 0 || new_month > 11)
14464                 new_month = (new_month + 12) % 12;
14465         } else {
14466             // For magnitudes >1, move one month at a time...
14467             for (var i=0; i<mag; i++)
14468                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
14469                 new_date = this.moveMonth(new_date, dir);
14470             // ...then reset the day, keeping it in the new month
14471             new_month = new_date.getUTCMonth();
14472             new_date.setUTCDate(day);
14473             test = function(){
14474                 return new_month != new_date.getUTCMonth();
14475             };
14476         }
14477         // Common date-resetting loop -- if date is beyond end of month, make it
14478         // end of month
14479         while (test()){
14480             new_date.setUTCDate(--day);
14481             new_date.setUTCMonth(new_month);
14482         }
14483         return new_date;
14484     },
14485
14486     moveYear: function(date, dir)
14487     {
14488         return this.moveMonth(date, dir*12);
14489     },
14490
14491     dateWithinRange: function(date)
14492     {
14493         return date >= this.startDate && date <= this.endDate;
14494     },
14495
14496     
14497     remove: function() 
14498     {
14499         this.picker().remove();
14500     }
14501    
14502 });
14503
14504 Roo.apply(Roo.bootstrap.DateField,  {
14505     
14506     head : {
14507         tag: 'thead',
14508         cn: [
14509         {
14510             tag: 'tr',
14511             cn: [
14512             {
14513                 tag: 'th',
14514                 cls: 'prev',
14515                 html: '<i class="fa fa-arrow-left"/>'
14516             },
14517             {
14518                 tag: 'th',
14519                 cls: 'switch',
14520                 colspan: '5'
14521             },
14522             {
14523                 tag: 'th',
14524                 cls: 'next',
14525                 html: '<i class="fa fa-arrow-right"/>'
14526             }
14527
14528             ]
14529         }
14530         ]
14531     },
14532     
14533     content : {
14534         tag: 'tbody',
14535         cn: [
14536         {
14537             tag: 'tr',
14538             cn: [
14539             {
14540                 tag: 'td',
14541                 colspan: '7'
14542             }
14543             ]
14544         }
14545         ]
14546     },
14547     
14548     footer : {
14549         tag: 'tfoot',
14550         cn: [
14551         {
14552             tag: 'tr',
14553             cn: [
14554             {
14555                 tag: 'th',
14556                 colspan: '7',
14557                 cls: 'today'
14558             }
14559                     
14560             ]
14561         }
14562         ]
14563     },
14564     
14565     dates:{
14566         en: {
14567             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
14568             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
14569             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
14570             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
14571             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14572             today: "Today"
14573         }
14574     },
14575     
14576     modes: [
14577     {
14578         clsName: 'days',
14579         navFnc: 'Month',
14580         navStep: 1
14581     },
14582     {
14583         clsName: 'months',
14584         navFnc: 'FullYear',
14585         navStep: 1
14586     },
14587     {
14588         clsName: 'years',
14589         navFnc: 'FullYear',
14590         navStep: 10
14591     }]
14592 });
14593
14594 Roo.apply(Roo.bootstrap.DateField,  {
14595   
14596     template : {
14597         tag: 'div',
14598         cls: 'datepicker dropdown-menu',
14599         cn: [
14600         {
14601             tag: 'div',
14602             cls: 'datepicker-days',
14603             cn: [
14604             {
14605                 tag: 'table',
14606                 cls: 'table-condensed',
14607                 cn:[
14608                 Roo.bootstrap.DateField.head,
14609                 {
14610                     tag: 'tbody'
14611                 },
14612                 Roo.bootstrap.DateField.footer
14613                 ]
14614             }
14615             ]
14616         },
14617         {
14618             tag: 'div',
14619             cls: 'datepicker-months',
14620             cn: [
14621             {
14622                 tag: 'table',
14623                 cls: 'table-condensed',
14624                 cn:[
14625                 Roo.bootstrap.DateField.head,
14626                 Roo.bootstrap.DateField.content,
14627                 Roo.bootstrap.DateField.footer
14628                 ]
14629             }
14630             ]
14631         },
14632         {
14633             tag: 'div',
14634             cls: 'datepicker-years',
14635             cn: [
14636             {
14637                 tag: 'table',
14638                 cls: 'table-condensed',
14639                 cn:[
14640                 Roo.bootstrap.DateField.head,
14641                 Roo.bootstrap.DateField.content,
14642                 Roo.bootstrap.DateField.footer
14643                 ]
14644             }
14645             ]
14646         }
14647         ]
14648     }
14649 });
14650
14651  
14652
14653  /*
14654  * - LGPL
14655  *
14656  * TimeField
14657  * 
14658  */
14659
14660 /**
14661  * @class Roo.bootstrap.TimeField
14662  * @extends Roo.bootstrap.Input
14663  * Bootstrap DateField class
14664  * 
14665  * 
14666  * @constructor
14667  * Create a new TimeField
14668  * @param {Object} config The config object
14669  */
14670
14671 Roo.bootstrap.TimeField = function(config){
14672     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14673     this.addEvents({
14674             /**
14675              * @event show
14676              * Fires when this field show.
14677              * @param {Roo.bootstrap.DateField} this
14678              * @param {Mixed} date The date value
14679              */
14680             show : true,
14681             /**
14682              * @event show
14683              * Fires when this field hide.
14684              * @param {Roo.bootstrap.DateField} this
14685              * @param {Mixed} date The date value
14686              */
14687             hide : true,
14688             /**
14689              * @event select
14690              * Fires when select a date.
14691              * @param {Roo.bootstrap.DateField} this
14692              * @param {Mixed} date The date value
14693              */
14694             select : true
14695         });
14696 };
14697
14698 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
14699     
14700     /**
14701      * @cfg {String} format
14702      * The default time format string which can be overriden for localization support.  The format must be
14703      * valid according to {@link Date#parseDate} (defaults to 'H:i').
14704      */
14705     format : "H:i",
14706        
14707     onRender: function(ct, position)
14708     {
14709         
14710         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14711                 
14712         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14713         
14714         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14715         
14716         this.pop = this.picker().select('>.datepicker-time',true).first();
14717         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block' 
14718         
14719         this.picker().on('mousedown', this.onMousedown, this);
14720         this.picker().on('click', this.onClick, this);
14721         
14722         this.picker().addClass('datepicker-dropdown');
14723     
14724         this.fillTime();
14725         this.update();
14726             
14727         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14728         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14729         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14730         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14731         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14732         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14733
14734     },
14735     
14736     fireKey: function(e){
14737         if (!this.picker().isVisible()){
14738             if (e.keyCode == 27) // allow escape to hide and re-show picker
14739                 this.show();
14740             return;
14741         }
14742
14743         e.preventDefault();
14744         
14745         switch(e.keyCode){
14746             case 27: // escape
14747                 this.hide();
14748                 break;
14749             case 37: // left
14750             case 39: // right
14751                 this.onTogglePeriod();
14752                 break;
14753             case 38: // up
14754                 this.onIncrementMinutes();
14755                 break;
14756             case 40: // down
14757                 this.onDecrementMinutes();
14758                 break;
14759             case 13: // enter
14760             case 9: // tab
14761                 this.setTime();
14762                 break;
14763         }
14764     },
14765     
14766     onClick: function(e) {
14767         e.stopPropagation();
14768         e.preventDefault();
14769     },
14770     
14771     picker : function()
14772     {
14773         return this.el.select('.datepicker', true).first();
14774     },
14775     
14776     fillTime: function()
14777     {    
14778         var time = this.pop.select('tbody', true).first();
14779         
14780         time.dom.innerHTML = '';
14781         
14782         time.createChild({
14783             tag: 'tr',
14784             cn: [
14785                 {
14786                     tag: 'td',
14787                     cn: [
14788                         {
14789                             tag: 'a',
14790                             href: '#',
14791                             cls: 'btn',
14792                             cn: [
14793                                 {
14794                                     tag: 'span',
14795                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
14796                                 }
14797                             ]
14798                         } 
14799                     ]
14800                 },
14801                 {
14802                     tag: 'td',
14803                     cls: 'separator'
14804                 },
14805                 {
14806                     tag: 'td',
14807                     cn: [
14808                         {
14809                             tag: 'a',
14810                             href: '#',
14811                             cls: 'btn',
14812                             cn: [
14813                                 {
14814                                     tag: 'span',
14815                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
14816                                 }
14817                             ]
14818                         }
14819                     ]
14820                 },
14821                 {
14822                     tag: 'td',
14823                     cls: 'separator'
14824                 }
14825             ]
14826         });
14827         
14828         time.createChild({
14829             tag: 'tr',
14830             cn: [
14831                 {
14832                     tag: 'td',
14833                     cn: [
14834                         {
14835                             tag: 'span',
14836                             cls: 'timepicker-hour',
14837                             html: '00'
14838                         }  
14839                     ]
14840                 },
14841                 {
14842                     tag: 'td',
14843                     cls: 'separator',
14844                     html: ':'
14845                 },
14846                 {
14847                     tag: 'td',
14848                     cn: [
14849                         {
14850                             tag: 'span',
14851                             cls: 'timepicker-minute',
14852                             html: '00'
14853                         }  
14854                     ]
14855                 },
14856                 {
14857                     tag: 'td',
14858                     cls: 'separator'
14859                 },
14860                 {
14861                     tag: 'td',
14862                     cn: [
14863                         {
14864                             tag: 'button',
14865                             type: 'button',
14866                             cls: 'btn btn-primary period',
14867                             html: 'AM'
14868                             
14869                         }
14870                     ]
14871                 }
14872             ]
14873         });
14874         
14875         time.createChild({
14876             tag: 'tr',
14877             cn: [
14878                 {
14879                     tag: 'td',
14880                     cn: [
14881                         {
14882                             tag: 'a',
14883                             href: '#',
14884                             cls: 'btn',
14885                             cn: [
14886                                 {
14887                                     tag: 'span',
14888                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
14889                                 }
14890                             ]
14891                         }
14892                     ]
14893                 },
14894                 {
14895                     tag: 'td',
14896                     cls: 'separator'
14897                 },
14898                 {
14899                     tag: 'td',
14900                     cn: [
14901                         {
14902                             tag: 'a',
14903                             href: '#',
14904                             cls: 'btn',
14905                             cn: [
14906                                 {
14907                                     tag: 'span',
14908                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
14909                                 }
14910                             ]
14911                         }
14912                     ]
14913                 },
14914                 {
14915                     tag: 'td',
14916                     cls: 'separator'
14917                 }
14918             ]
14919         });
14920         
14921     },
14922     
14923     update: function()
14924     {
14925         
14926         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14927         
14928         this.fill();
14929     },
14930     
14931     fill: function() 
14932     {
14933         var hours = this.time.getHours();
14934         var minutes = this.time.getMinutes();
14935         var period = 'AM';
14936         
14937         if(hours > 11){
14938             period = 'PM';
14939         }
14940         
14941         if(hours == 0){
14942             hours = 12;
14943         }
14944         
14945         
14946         if(hours > 12){
14947             hours = hours - 12;
14948         }
14949         
14950         if(hours < 10){
14951             hours = '0' + hours;
14952         }
14953         
14954         if(minutes < 10){
14955             minutes = '0' + minutes;
14956         }
14957         
14958         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14959         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14960         this.pop.select('button', true).first().dom.innerHTML = period;
14961         
14962     },
14963     
14964     place: function()
14965     {   
14966         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14967         
14968         var cls = ['bottom'];
14969         
14970         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14971             cls.pop();
14972             cls.push('top');
14973         }
14974         
14975         cls.push('right');
14976         
14977         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14978             cls.pop();
14979             cls.push('left');
14980         }
14981         
14982         this.picker().addClass(cls.join('-'));
14983         
14984         var _this = this;
14985         
14986         Roo.each(cls, function(c){
14987             if(c == 'bottom'){
14988                 _this.picker().setTop(_this.inputEl().getHeight());
14989                 return;
14990             }
14991             if(c == 'top'){
14992                 _this.picker().setTop(0 - _this.picker().getHeight());
14993                 return;
14994             }
14995             
14996             if(c == 'left'){
14997                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14998                 return;
14999             }
15000             if(c == 'right'){
15001                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15002                 return;
15003             }
15004         });
15005         
15006     },
15007   
15008     onFocus : function()
15009     {
15010         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15011         this.show();
15012     },
15013     
15014     onBlur : function()
15015     {
15016         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
15017         this.hide();
15018     },
15019     
15020     show : function()
15021     {
15022         this.picker().show();
15023         this.pop.show();
15024         this.update();
15025         this.place();
15026         
15027         this.fireEvent('show', this, this.date);
15028     },
15029     
15030     hide : function()
15031     {
15032         this.picker().hide();
15033         this.pop.hide();
15034         
15035         this.fireEvent('hide', this, this.date);
15036     },
15037     
15038     setTime : function()
15039     {
15040         this.hide();
15041         this.setValue(this.time.format(this.format));
15042         
15043         this.fireEvent('select', this, this.date);
15044         
15045         
15046     },
15047     
15048     onMousedown: function(e){
15049         e.stopPropagation();
15050         e.preventDefault();
15051     },
15052     
15053     onIncrementHours: function()
15054     {
15055         Roo.log('onIncrementHours');
15056         this.time = this.time.add(Date.HOUR, 1);
15057         this.update();
15058         
15059     },
15060     
15061     onDecrementHours: function()
15062     {
15063         Roo.log('onDecrementHours');
15064         this.time = this.time.add(Date.HOUR, -1);
15065         this.update();
15066     },
15067     
15068     onIncrementMinutes: function()
15069     {
15070         Roo.log('onIncrementMinutes');
15071         this.time = this.time.add(Date.MINUTE, 1);
15072         this.update();
15073     },
15074     
15075     onDecrementMinutes: function()
15076     {
15077         Roo.log('onDecrementMinutes');
15078         this.time = this.time.add(Date.MINUTE, -1);
15079         this.update();
15080     },
15081     
15082     onTogglePeriod: function()
15083     {
15084         Roo.log('onTogglePeriod');
15085         this.time = this.time.add(Date.HOUR, 12);
15086         this.update();
15087     }
15088     
15089    
15090 });
15091
15092 Roo.apply(Roo.bootstrap.TimeField,  {
15093     
15094     content : {
15095         tag: 'tbody',
15096         cn: [
15097             {
15098                 tag: 'tr',
15099                 cn: [
15100                 {
15101                     tag: 'td',
15102                     colspan: '7'
15103                 }
15104                 ]
15105             }
15106         ]
15107     },
15108     
15109     footer : {
15110         tag: 'tfoot',
15111         cn: [
15112             {
15113                 tag: 'tr',
15114                 cn: [
15115                 {
15116                     tag: 'th',
15117                     colspan: '7',
15118                     cls: '',
15119                     cn: [
15120                         {
15121                             tag: 'button',
15122                             cls: 'btn btn-info ok',
15123                             html: 'OK'
15124                         }
15125                     ]
15126                 }
15127
15128                 ]
15129             }
15130         ]
15131     }
15132 });
15133
15134 Roo.apply(Roo.bootstrap.TimeField,  {
15135   
15136     template : {
15137         tag: 'div',
15138         cls: 'datepicker dropdown-menu',
15139         cn: [
15140             {
15141                 tag: 'div',
15142                 cls: 'datepicker-time',
15143                 cn: [
15144                 {
15145                     tag: 'table',
15146                     cls: 'table-condensed',
15147                     cn:[
15148                     Roo.bootstrap.TimeField.content,
15149                     Roo.bootstrap.TimeField.footer
15150                     ]
15151                 }
15152                 ]
15153             }
15154         ]
15155     }
15156 });
15157
15158  
15159
15160  /*
15161  * - LGPL
15162  *
15163  * CheckBox
15164  * 
15165  */
15166
15167 /**
15168  * @class Roo.bootstrap.CheckBox
15169  * @extends Roo.bootstrap.Input
15170  * Bootstrap CheckBox class
15171  * 
15172  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
15173  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
15174  * @cfg {String} boxLabel The text that appears beside the checkbox
15175  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
15176  * @cfg {Boolean} checked initnal the element
15177  * 
15178  * 
15179  * @constructor
15180  * Create a new CheckBox
15181  * @param {Object} config The config object
15182  */
15183
15184 Roo.bootstrap.CheckBox = function(config){
15185     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
15186    
15187         this.addEvents({
15188             /**
15189             * @event check
15190             * Fires when the element is checked or unchecked.
15191             * @param {Roo.bootstrap.CheckBox} this This input
15192             * @param {Boolean} checked The new checked value
15193             */
15194            check : true
15195         });
15196 };
15197
15198 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
15199     
15200     inputType: 'checkbox',
15201     inputValue: 1,
15202     valueOff: 0,
15203     boxLabel: false,
15204     checked: false,
15205     weight : false,
15206     
15207     getAutoCreate : function()
15208     {
15209         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15210         
15211         var id = Roo.id();
15212         
15213         var cfg = {};
15214         
15215         cfg.cls = 'form-group checkbox' //input-group
15216         
15217         
15218         
15219         
15220         var input =  {
15221             tag: 'input',
15222             id : id,
15223             type : this.inputType,
15224             value : (!this.checked) ? this.valueOff : this.inputValue,
15225             cls : 'roo-checkbox', //'form-box',
15226             placeholder : this.placeholder || ''
15227             
15228         };
15229         
15230         if (this.weight) { // Validity check?
15231             cfg.cls += " checkbox-" + this.weight;
15232         }
15233         
15234         if (this.disabled) {
15235             input.disabled=true;
15236         }
15237         
15238         if(this.checked){
15239             input.checked = this.checked;
15240         }
15241         
15242         if (this.name) {
15243             input.name = this.name;
15244         }
15245         
15246         if (this.size) {
15247             input.cls += ' input-' + this.size;
15248         }
15249         
15250         var settings=this;
15251         ['xs','sm','md','lg'].map(function(size){
15252             if (settings[size]) {
15253                 cfg.cls += ' col-' + size + '-' + settings[size];
15254             }
15255         });
15256         
15257        
15258         
15259         var inputblock = input;
15260         
15261         
15262         
15263         
15264         if (this.before || this.after) {
15265             
15266             inputblock = {
15267                 cls : 'input-group',
15268                 cn :  [] 
15269             };
15270             if (this.before) {
15271                 inputblock.cn.push({
15272                     tag :'span',
15273                     cls : 'input-group-addon',
15274                     html : this.before
15275                 });
15276             }
15277             inputblock.cn.push(input);
15278             if (this.after) {
15279                 inputblock.cn.push({
15280                     tag :'span',
15281                     cls : 'input-group-addon',
15282                     html : this.after
15283                 });
15284             }
15285             
15286         };
15287         
15288         if (align ==='left' && this.fieldLabel.length) {
15289                 Roo.log("left and has label");
15290                 cfg.cn = [
15291                     
15292                     {
15293                         tag: 'label',
15294                         'for' :  id,
15295                         cls : 'control-label col-md-' + this.labelWidth,
15296                         html : this.fieldLabel
15297                         
15298                     },
15299                     {
15300                         cls : "col-md-" + (12 - this.labelWidth), 
15301                         cn: [
15302                             inputblock
15303                         ]
15304                     }
15305                     
15306                 ];
15307         } else if ( this.fieldLabel.length) {
15308                 Roo.log(" label");
15309                 cfg.cn = [
15310                    
15311                     {
15312                         tag: this.boxLabel ? 'span' : 'label',
15313                         'for': id,
15314                         cls: 'control-label box-input-label',
15315                         //cls : 'input-group-addon',
15316                         html : this.fieldLabel
15317                         
15318                     },
15319                     
15320                     inputblock
15321                     
15322                 ];
15323
15324         } else {
15325             
15326                 Roo.log(" no label && no align");
15327                 cfg.cn = [  inputblock ] ;
15328                 
15329                 
15330         };
15331          if(this.boxLabel){
15332             cfg.cn.push( {
15333                 tag: 'label',
15334                 'for': id,
15335                 cls: 'box-label',
15336                 html: this.boxLabel
15337                 
15338             });
15339         }
15340         
15341         
15342        
15343         return cfg;
15344         
15345     },
15346     
15347     /**
15348      * return the real input element.
15349      */
15350     inputEl: function ()
15351     {
15352         return this.el.select('input.roo-checkbox',true).first();
15353     },
15354     
15355     label: function()
15356     {
15357         return this.el.select('label.control-label',true).first();
15358     },
15359     
15360     initEvents : function()
15361     {
15362 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
15363         
15364         this.inputEl().on('click', this.onClick,  this);
15365         
15366     },
15367     
15368     onClick : function()
15369     {   
15370         this.setChecked(!this.checked);
15371     },
15372     
15373     setChecked : function(state,suppressEvent)
15374     {
15375         this.checked = state;
15376         
15377         this.inputEl().dom.checked = state;
15378         
15379         if(suppressEvent !== true){
15380             this.fireEvent('check', this, state);
15381         }
15382         
15383         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15384         
15385     },
15386     
15387     setValue : function(v,suppressEvent)
15388     {
15389         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
15390     }
15391     
15392 });
15393
15394  
15395 /*
15396  * - LGPL
15397  *
15398  * Radio
15399  * 
15400  */
15401
15402 /**
15403  * @class Roo.bootstrap.Radio
15404  * @extends Roo.bootstrap.CheckBox
15405  * Bootstrap Radio class
15406
15407  * @constructor
15408  * Create a new Radio
15409  * @param {Object} config The config object
15410  */
15411
15412 Roo.bootstrap.Radio = function(config){
15413     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
15414    
15415 };
15416
15417 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
15418     
15419     inputType: 'radio',
15420     inputValue: '',
15421     valueOff: '',
15422     
15423     getAutoCreate : function()
15424     {
15425         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
15426         
15427         var id = Roo.id();
15428         
15429         var cfg = {};
15430         
15431         cfg.cls = 'form-group radio' //input-group
15432         
15433         var input =  {
15434             tag: 'input',
15435             id : id,
15436             type : this.inputType,
15437             value : (!this.checked) ? this.valueOff : this.inputValue,
15438             cls : 'roo-radio',
15439             placeholder : this.placeholder || ''
15440             
15441         };
15442           if (this.weight) { // Validity check?
15443             cfg.cls += " radio-" + this.weight;
15444         }
15445         if (this.disabled) {
15446             input.disabled=true;
15447         }
15448         
15449         if(this.checked){
15450             input.checked = this.checked;
15451         }
15452         
15453         if (this.name) {
15454             input.name = this.name;
15455         }
15456         
15457         if (this.size) {
15458             input.cls += ' input-' + this.size;
15459         }
15460         
15461         var settings=this;
15462         ['xs','sm','md','lg'].map(function(size){
15463             if (settings[size]) {
15464                 cfg.cls += ' col-' + size + '-' + settings[size];
15465             }
15466         });
15467         
15468         var inputblock = input;
15469         
15470         if (this.before || this.after) {
15471             
15472             inputblock = {
15473                 cls : 'input-group',
15474                 cn :  [] 
15475             };
15476             if (this.before) {
15477                 inputblock.cn.push({
15478                     tag :'span',
15479                     cls : 'input-group-addon',
15480                     html : this.before
15481                 });
15482             }
15483             inputblock.cn.push(input);
15484             if (this.after) {
15485                 inputblock.cn.push({
15486                     tag :'span',
15487                     cls : 'input-group-addon',
15488                     html : this.after
15489                 });
15490             }
15491             
15492         };
15493         
15494         if (align ==='left' && this.fieldLabel.length) {
15495                 Roo.log("left and has label");
15496                 cfg.cn = [
15497                     
15498                     {
15499                         tag: 'label',
15500                         'for' :  id,
15501                         cls : 'control-label col-md-' + this.labelWidth,
15502                         html : this.fieldLabel
15503                         
15504                     },
15505                     {
15506                         cls : "col-md-" + (12 - this.labelWidth), 
15507                         cn: [
15508                             inputblock
15509                         ]
15510                     }
15511                     
15512                 ];
15513         } else if ( this.fieldLabel.length) {
15514                 Roo.log(" label");
15515                  cfg.cn = [
15516                    
15517                     {
15518                         tag: 'label',
15519                         'for': id,
15520                         cls: 'control-label box-input-label',
15521                         //cls : 'input-group-addon',
15522                         html : this.fieldLabel
15523                         
15524                     },
15525                     
15526                     inputblock
15527                     
15528                 ];
15529
15530         } else {
15531             
15532                    Roo.log(" no label && no align");
15533                 cfg.cn = [
15534                     
15535                         inputblock
15536                     
15537                 ];
15538                 
15539                 
15540         };
15541         
15542         if(this.boxLabel){
15543             cfg.cn.push({
15544                 tag: 'label',
15545                 'for': id,
15546                 cls: 'box-label',
15547                 html: this.boxLabel
15548             })
15549         }
15550         
15551         return cfg;
15552         
15553     },
15554     inputEl: function ()
15555     {
15556         return this.el.select('input.roo-radio',true).first();
15557     },
15558     onClick : function()
15559     {   
15560         this.setChecked(true);
15561     },
15562     
15563     setChecked : function(state,suppressEvent)
15564     {
15565         if(state){
15566             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15567                 v.dom.checked = false;
15568             });
15569         }
15570         
15571         this.checked = state;
15572         this.inputEl().dom.checked = state;
15573         
15574         if(suppressEvent !== true){
15575             this.fireEvent('check', this, state);
15576         }
15577         
15578         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
15579         
15580     },
15581     
15582     getGroupValue : function()
15583     {
15584         var value = ''
15585         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15586             if(v.dom.checked == true){
15587                 value = v.dom.value;
15588             }
15589         });
15590         
15591         return value;
15592     },
15593     
15594     /**
15595      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
15596      * @return {Mixed} value The field value
15597      */
15598     getValue : function(){
15599         return this.getGroupValue();
15600     }
15601     
15602 });
15603
15604  
15605 //<script type="text/javascript">
15606
15607 /*
15608  * Based  Ext JS Library 1.1.1
15609  * Copyright(c) 2006-2007, Ext JS, LLC.
15610  * LGPL
15611  *
15612  */
15613  
15614 /**
15615  * @class Roo.HtmlEditorCore
15616  * @extends Roo.Component
15617  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15618  *
15619  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15620  */
15621
15622 Roo.HtmlEditorCore = function(config){
15623     
15624     
15625     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15626     this.addEvents({
15627         /**
15628          * @event initialize
15629          * Fires when the editor is fully initialized (including the iframe)
15630          * @param {Roo.HtmlEditorCore} this
15631          */
15632         initialize: true,
15633         /**
15634          * @event activate
15635          * Fires when the editor is first receives the focus. Any insertion must wait
15636          * until after this event.
15637          * @param {Roo.HtmlEditorCore} this
15638          */
15639         activate: true,
15640          /**
15641          * @event beforesync
15642          * Fires before the textarea is updated with content from the editor iframe. Return false
15643          * to cancel the sync.
15644          * @param {Roo.HtmlEditorCore} this
15645          * @param {String} html
15646          */
15647         beforesync: true,
15648          /**
15649          * @event beforepush
15650          * Fires before the iframe editor is updated with content from the textarea. Return false
15651          * to cancel the push.
15652          * @param {Roo.HtmlEditorCore} this
15653          * @param {String} html
15654          */
15655         beforepush: true,
15656          /**
15657          * @event sync
15658          * Fires when the textarea is updated with content from the editor iframe.
15659          * @param {Roo.HtmlEditorCore} this
15660          * @param {String} html
15661          */
15662         sync: true,
15663          /**
15664          * @event push
15665          * Fires when the iframe editor is updated with content from the textarea.
15666          * @param {Roo.HtmlEditorCore} this
15667          * @param {String} html
15668          */
15669         push: true,
15670         
15671         /**
15672          * @event editorevent
15673          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15674          * @param {Roo.HtmlEditorCore} this
15675          */
15676         editorevent: true
15677     });
15678      
15679 };
15680
15681
15682 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
15683
15684
15685      /**
15686      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
15687      */
15688     
15689     owner : false,
15690     
15691      /**
15692      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
15693      *                        Roo.resizable.
15694      */
15695     resizable : false,
15696      /**
15697      * @cfg {Number} height (in pixels)
15698      */   
15699     height: 300,
15700    /**
15701      * @cfg {Number} width (in pixels)
15702      */   
15703     width: 500,
15704     
15705     /**
15706      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15707      * 
15708      */
15709     stylesheets: false,
15710     
15711     // id of frame..
15712     frameId: false,
15713     
15714     // private properties
15715     validationEvent : false,
15716     deferHeight: true,
15717     initialized : false,
15718     activated : false,
15719     sourceEditMode : false,
15720     onFocus : Roo.emptyFn,
15721     iframePad:3,
15722     hideMode:'offsets',
15723     
15724     clearUp: true,
15725     
15726      
15727     
15728
15729     /**
15730      * Protected method that will not generally be called directly. It
15731      * is called when the editor initializes the iframe with HTML contents. Override this method if you
15732      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15733      */
15734     getDocMarkup : function(){
15735         // body styles..
15736         var st = '';
15737         Roo.log(this.stylesheets);
15738         
15739         // inherit styels from page...?? 
15740         if (this.stylesheets === false) {
15741             
15742             Roo.get(document.head).select('style').each(function(node) {
15743                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15744             });
15745             
15746             Roo.get(document.head).select('link').each(function(node) { 
15747                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15748             });
15749             
15750         } else if (!this.stylesheets.length) {
15751                 // simple..
15752                 st = '<style type="text/css">' +
15753                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15754                    '</style>';
15755         } else {
15756             Roo.each(this.stylesheets, function(s) {
15757                 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15758             });
15759             
15760         }
15761         
15762         st +=  '<style type="text/css">' +
15763             'IMG { cursor: pointer } ' +
15764         '</style>';
15765
15766         
15767         return '<html><head>' + st  +
15768             //<style type="text/css">' +
15769             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15770             //'</style>' +
15771             ' </head><body class="roo-htmleditor-body"></body></html>';
15772     },
15773
15774     // private
15775     onRender : function(ct, position)
15776     {
15777         var _t = this;
15778         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15779         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15780         
15781         
15782         this.el.dom.style.border = '0 none';
15783         this.el.dom.setAttribute('tabIndex', -1);
15784         this.el.addClass('x-hidden hide');
15785         
15786         
15787         
15788         if(Roo.isIE){ // fix IE 1px bogus margin
15789             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15790         }
15791        
15792         
15793         this.frameId = Roo.id();
15794         
15795          
15796         
15797         var iframe = this.owner.wrap.createChild({
15798             tag: 'iframe',
15799             cls: 'form-control', // bootstrap..
15800             id: this.frameId,
15801             name: this.frameId,
15802             frameBorder : 'no',
15803             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
15804         }, this.el
15805         );
15806         
15807         
15808         this.iframe = iframe.dom;
15809
15810          this.assignDocWin();
15811         
15812         this.doc.designMode = 'on';
15813        
15814         this.doc.open();
15815         this.doc.write(this.getDocMarkup());
15816         this.doc.close();
15817
15818         
15819         var task = { // must defer to wait for browser to be ready
15820             run : function(){
15821                 //console.log("run task?" + this.doc.readyState);
15822                 this.assignDocWin();
15823                 if(this.doc.body || this.doc.readyState == 'complete'){
15824                     try {
15825                         this.doc.designMode="on";
15826                     } catch (e) {
15827                         return;
15828                     }
15829                     Roo.TaskMgr.stop(task);
15830                     this.initEditor.defer(10, this);
15831                 }
15832             },
15833             interval : 10,
15834             duration: 10000,
15835             scope: this
15836         };
15837         Roo.TaskMgr.start(task);
15838
15839         
15840          
15841     },
15842
15843     // private
15844     onResize : function(w, h)
15845     {
15846          Roo.log('resize: ' +w + ',' + h );
15847         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15848         if(!this.iframe){
15849             return;
15850         }
15851         if(typeof w == 'number'){
15852             
15853             this.iframe.style.width = w + 'px';
15854         }
15855         if(typeof h == 'number'){
15856             
15857             this.iframe.style.height = h + 'px';
15858             if(this.doc){
15859                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15860             }
15861         }
15862         
15863     },
15864
15865     /**
15866      * Toggles the editor between standard and source edit mode.
15867      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15868      */
15869     toggleSourceEdit : function(sourceEditMode){
15870         
15871         this.sourceEditMode = sourceEditMode === true;
15872         
15873         if(this.sourceEditMode){
15874  
15875             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
15876             
15877         }else{
15878             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15879             //this.iframe.className = '';
15880             this.deferFocus();
15881         }
15882         //this.setSize(this.owner.wrap.getSize());
15883         //this.fireEvent('editmodechange', this, this.sourceEditMode);
15884     },
15885
15886     
15887   
15888
15889     /**
15890      * Protected method that will not generally be called directly. If you need/want
15891      * custom HTML cleanup, this is the method you should override.
15892      * @param {String} html The HTML to be cleaned
15893      * return {String} The cleaned HTML
15894      */
15895     cleanHtml : function(html){
15896         html = String(html);
15897         if(html.length > 5){
15898             if(Roo.isSafari){ // strip safari nonsense
15899                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15900             }
15901         }
15902         if(html == '&nbsp;'){
15903             html = '';
15904         }
15905         return html;
15906     },
15907
15908     /**
15909      * HTML Editor -> Textarea
15910      * Protected method that will not generally be called directly. Syncs the contents
15911      * of the editor iframe with the textarea.
15912      */
15913     syncValue : function(){
15914         if(this.initialized){
15915             var bd = (this.doc.body || this.doc.documentElement);
15916             //this.cleanUpPaste(); -- this is done else where and causes havoc..
15917             var html = bd.innerHTML;
15918             if(Roo.isSafari){
15919                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15920                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15921                 if(m && m[1]){
15922                     html = '<div style="'+m[0]+'">' + html + '</div>';
15923                 }
15924             }
15925             html = this.cleanHtml(html);
15926             // fix up the special chars.. normaly like back quotes in word...
15927             // however we do not want to do this with chinese..
15928             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15929                 var cc = b.charCodeAt();
15930                 if (
15931                     (cc >= 0x4E00 && cc < 0xA000 ) ||
15932                     (cc >= 0x3400 && cc < 0x4E00 ) ||
15933                     (cc >= 0xf900 && cc < 0xfb00 )
15934                 ) {
15935                         return b;
15936                 }
15937                 return "&#"+cc+";" 
15938             });
15939             if(this.owner.fireEvent('beforesync', this, html) !== false){
15940                 this.el.dom.value = html;
15941                 this.owner.fireEvent('sync', this, html);
15942             }
15943         }
15944     },
15945
15946     /**
15947      * Protected method that will not generally be called directly. Pushes the value of the textarea
15948      * into the iframe editor.
15949      */
15950     pushValue : function(){
15951         if(this.initialized){
15952             var v = this.el.dom.value.trim();
15953             
15954 //            if(v.length < 1){
15955 //                v = '&#160;';
15956 //            }
15957             
15958             if(this.owner.fireEvent('beforepush', this, v) !== false){
15959                 var d = (this.doc.body || this.doc.documentElement);
15960                 d.innerHTML = v;
15961                 this.cleanUpPaste();
15962                 this.el.dom.value = d.innerHTML;
15963                 this.owner.fireEvent('push', this, v);
15964             }
15965         }
15966     },
15967
15968     // private
15969     deferFocus : function(){
15970         this.focus.defer(10, this);
15971     },
15972
15973     // doc'ed in Field
15974     focus : function(){
15975         if(this.win && !this.sourceEditMode){
15976             this.win.focus();
15977         }else{
15978             this.el.focus();
15979         }
15980     },
15981     
15982     assignDocWin: function()
15983     {
15984         var iframe = this.iframe;
15985         
15986          if(Roo.isIE){
15987             this.doc = iframe.contentWindow.document;
15988             this.win = iframe.contentWindow;
15989         } else {
15990             if (!Roo.get(this.frameId)) {
15991                 return;
15992             }
15993             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15994             this.win = Roo.get(this.frameId).dom.contentWindow;
15995         }
15996     },
15997     
15998     // private
15999     initEditor : function(){
16000         //console.log("INIT EDITOR");
16001         this.assignDocWin();
16002         
16003         
16004         
16005         this.doc.designMode="on";
16006         this.doc.open();
16007         this.doc.write(this.getDocMarkup());
16008         this.doc.close();
16009         
16010         var dbody = (this.doc.body || this.doc.documentElement);
16011         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
16012         // this copies styles from the containing element into thsi one..
16013         // not sure why we need all of this..
16014         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
16015         
16016         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
16017         //ss['background-attachment'] = 'fixed'; // w3c
16018         dbody.bgProperties = 'fixed'; // ie
16019         //Roo.DomHelper.applyStyles(dbody, ss);
16020         Roo.EventManager.on(this.doc, {
16021             //'mousedown': this.onEditorEvent,
16022             'mouseup': this.onEditorEvent,
16023             'dblclick': this.onEditorEvent,
16024             'click': this.onEditorEvent,
16025             'keyup': this.onEditorEvent,
16026             buffer:100,
16027             scope: this
16028         });
16029         if(Roo.isGecko){
16030             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
16031         }
16032         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
16033             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
16034         }
16035         this.initialized = true;
16036
16037         this.owner.fireEvent('initialize', this);
16038         this.pushValue();
16039     },
16040
16041     // private
16042     onDestroy : function(){
16043         
16044         
16045         
16046         if(this.rendered){
16047             
16048             //for (var i =0; i < this.toolbars.length;i++) {
16049             //    // fixme - ask toolbars for heights?
16050             //    this.toolbars[i].onDestroy();
16051            // }
16052             
16053             //this.wrap.dom.innerHTML = '';
16054             //this.wrap.remove();
16055         }
16056     },
16057
16058     // private
16059     onFirstFocus : function(){
16060         
16061         this.assignDocWin();
16062         
16063         
16064         this.activated = true;
16065          
16066     
16067         if(Roo.isGecko){ // prevent silly gecko errors
16068             this.win.focus();
16069             var s = this.win.getSelection();
16070             if(!s.focusNode || s.focusNode.nodeType != 3){
16071                 var r = s.getRangeAt(0);
16072                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
16073                 r.collapse(true);
16074                 this.deferFocus();
16075             }
16076             try{
16077                 this.execCmd('useCSS', true);
16078                 this.execCmd('styleWithCSS', false);
16079             }catch(e){}
16080         }
16081         this.owner.fireEvent('activate', this);
16082     },
16083
16084     // private
16085     adjustFont: function(btn){
16086         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
16087         //if(Roo.isSafari){ // safari
16088         //    adjust *= 2;
16089        // }
16090         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
16091         if(Roo.isSafari){ // safari
16092             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
16093             v =  (v < 10) ? 10 : v;
16094             v =  (v > 48) ? 48 : v;
16095             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
16096             
16097         }
16098         
16099         
16100         v = Math.max(1, v+adjust);
16101         
16102         this.execCmd('FontSize', v  );
16103     },
16104
16105     onEditorEvent : function(e){
16106         this.owner.fireEvent('editorevent', this, e);
16107       //  this.updateToolbar();
16108         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
16109     },
16110
16111     insertTag : function(tg)
16112     {
16113         // could be a bit smarter... -> wrap the current selected tRoo..
16114         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
16115             
16116             range = this.createRange(this.getSelection());
16117             var wrappingNode = this.doc.createElement(tg.toLowerCase());
16118             wrappingNode.appendChild(range.extractContents());
16119             range.insertNode(wrappingNode);
16120
16121             return;
16122             
16123             
16124             
16125         }
16126         this.execCmd("formatblock",   tg);
16127         
16128     },
16129     
16130     insertText : function(txt)
16131     {
16132         
16133         
16134         var range = this.createRange();
16135         range.deleteContents();
16136                //alert(Sender.getAttribute('label'));
16137                
16138         range.insertNode(this.doc.createTextNode(txt));
16139     } ,
16140     
16141      
16142
16143     /**
16144      * Executes a Midas editor command on the editor document and performs necessary focus and
16145      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
16146      * @param {String} cmd The Midas command
16147      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16148      */
16149     relayCmd : function(cmd, value){
16150         this.win.focus();
16151         this.execCmd(cmd, value);
16152         this.owner.fireEvent('editorevent', this);
16153         //this.updateToolbar();
16154         this.owner.deferFocus();
16155     },
16156
16157     /**
16158      * Executes a Midas editor command directly on the editor document.
16159      * For visual commands, you should use {@link #relayCmd} instead.
16160      * <b>This should only be called after the editor is initialized.</b>
16161      * @param {String} cmd The Midas command
16162      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
16163      */
16164     execCmd : function(cmd, value){
16165         this.doc.execCommand(cmd, false, value === undefined ? null : value);
16166         this.syncValue();
16167     },
16168  
16169  
16170    
16171     /**
16172      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
16173      * to insert tRoo.
16174      * @param {String} text | dom node.. 
16175      */
16176     insertAtCursor : function(text)
16177     {
16178         
16179         
16180         
16181         if(!this.activated){
16182             return;
16183         }
16184         /*
16185         if(Roo.isIE){
16186             this.win.focus();
16187             var r = this.doc.selection.createRange();
16188             if(r){
16189                 r.collapse(true);
16190                 r.pasteHTML(text);
16191                 this.syncValue();
16192                 this.deferFocus();
16193             
16194             }
16195             return;
16196         }
16197         */
16198         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
16199             this.win.focus();
16200             
16201             
16202             // from jquery ui (MIT licenced)
16203             var range, node;
16204             var win = this.win;
16205             
16206             if (win.getSelection && win.getSelection().getRangeAt) {
16207                 range = win.getSelection().getRangeAt(0);
16208                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
16209                 range.insertNode(node);
16210             } else if (win.document.selection && win.document.selection.createRange) {
16211                 // no firefox support
16212                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16213                 win.document.selection.createRange().pasteHTML(txt);
16214             } else {
16215                 // no firefox support
16216                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
16217                 this.execCmd('InsertHTML', txt);
16218             } 
16219             
16220             this.syncValue();
16221             
16222             this.deferFocus();
16223         }
16224     },
16225  // private
16226     mozKeyPress : function(e){
16227         if(e.ctrlKey){
16228             var c = e.getCharCode(), cmd;
16229           
16230             if(c > 0){
16231                 c = String.fromCharCode(c).toLowerCase();
16232                 switch(c){
16233                     case 'b':
16234                         cmd = 'bold';
16235                         break;
16236                     case 'i':
16237                         cmd = 'italic';
16238                         break;
16239                     
16240                     case 'u':
16241                         cmd = 'underline';
16242                         break;
16243                     
16244                     case 'v':
16245                         this.cleanUpPaste.defer(100, this);
16246                         return;
16247                         
16248                 }
16249                 if(cmd){
16250                     this.win.focus();
16251                     this.execCmd(cmd);
16252                     this.deferFocus();
16253                     e.preventDefault();
16254                 }
16255                 
16256             }
16257         }
16258     },
16259
16260     // private
16261     fixKeys : function(){ // load time branching for fastest keydown performance
16262         if(Roo.isIE){
16263             return function(e){
16264                 var k = e.getKey(), r;
16265                 if(k == e.TAB){
16266                     e.stopEvent();
16267                     r = this.doc.selection.createRange();
16268                     if(r){
16269                         r.collapse(true);
16270                         r.pasteHTML('&#160;&#160;&#160;&#160;');
16271                         this.deferFocus();
16272                     }
16273                     return;
16274                 }
16275                 
16276                 if(k == e.ENTER){
16277                     r = this.doc.selection.createRange();
16278                     if(r){
16279                         var target = r.parentElement();
16280                         if(!target || target.tagName.toLowerCase() != 'li'){
16281                             e.stopEvent();
16282                             r.pasteHTML('<br />');
16283                             r.collapse(false);
16284                             r.select();
16285                         }
16286                     }
16287                 }
16288                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16289                     this.cleanUpPaste.defer(100, this);
16290                     return;
16291                 }
16292                 
16293                 
16294             };
16295         }else if(Roo.isOpera){
16296             return function(e){
16297                 var k = e.getKey();
16298                 if(k == e.TAB){
16299                     e.stopEvent();
16300                     this.win.focus();
16301                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
16302                     this.deferFocus();
16303                 }
16304                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16305                     this.cleanUpPaste.defer(100, this);
16306                     return;
16307                 }
16308                 
16309             };
16310         }else if(Roo.isSafari){
16311             return function(e){
16312                 var k = e.getKey();
16313                 
16314                 if(k == e.TAB){
16315                     e.stopEvent();
16316                     this.execCmd('InsertText','\t');
16317                     this.deferFocus();
16318                     return;
16319                 }
16320                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
16321                     this.cleanUpPaste.defer(100, this);
16322                     return;
16323                 }
16324                 
16325              };
16326         }
16327     }(),
16328     
16329     getAllAncestors: function()
16330     {
16331         var p = this.getSelectedNode();
16332         var a = [];
16333         if (!p) {
16334             a.push(p); // push blank onto stack..
16335             p = this.getParentElement();
16336         }
16337         
16338         
16339         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
16340             a.push(p);
16341             p = p.parentNode;
16342         }
16343         a.push(this.doc.body);
16344         return a;
16345     },
16346     lastSel : false,
16347     lastSelNode : false,
16348     
16349     
16350     getSelection : function() 
16351     {
16352         this.assignDocWin();
16353         return Roo.isIE ? this.doc.selection : this.win.getSelection();
16354     },
16355     
16356     getSelectedNode: function() 
16357     {
16358         // this may only work on Gecko!!!
16359         
16360         // should we cache this!!!!
16361         
16362         
16363         
16364          
16365         var range = this.createRange(this.getSelection()).cloneRange();
16366         
16367         if (Roo.isIE) {
16368             var parent = range.parentElement();
16369             while (true) {
16370                 var testRange = range.duplicate();
16371                 testRange.moveToElementText(parent);
16372                 if (testRange.inRange(range)) {
16373                     break;
16374                 }
16375                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
16376                     break;
16377                 }
16378                 parent = parent.parentElement;
16379             }
16380             return parent;
16381         }
16382         
16383         // is ancestor a text element.
16384         var ac =  range.commonAncestorContainer;
16385         if (ac.nodeType == 3) {
16386             ac = ac.parentNode;
16387         }
16388         
16389         var ar = ac.childNodes;
16390          
16391         var nodes = [];
16392         var other_nodes = [];
16393         var has_other_nodes = false;
16394         for (var i=0;i<ar.length;i++) {
16395             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
16396                 continue;
16397             }
16398             // fullly contained node.
16399             
16400             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
16401                 nodes.push(ar[i]);
16402                 continue;
16403             }
16404             
16405             // probably selected..
16406             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
16407                 other_nodes.push(ar[i]);
16408                 continue;
16409             }
16410             // outer..
16411             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
16412                 continue;
16413             }
16414             
16415             
16416             has_other_nodes = true;
16417         }
16418         if (!nodes.length && other_nodes.length) {
16419             nodes= other_nodes;
16420         }
16421         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
16422             return false;
16423         }
16424         
16425         return nodes[0];
16426     },
16427     createRange: function(sel)
16428     {
16429         // this has strange effects when using with 
16430         // top toolbar - not sure if it's a great idea.
16431         //this.editor.contentWindow.focus();
16432         if (typeof sel != "undefined") {
16433             try {
16434                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
16435             } catch(e) {
16436                 return this.doc.createRange();
16437             }
16438         } else {
16439             return this.doc.createRange();
16440         }
16441     },
16442     getParentElement: function()
16443     {
16444         
16445         this.assignDocWin();
16446         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
16447         
16448         var range = this.createRange(sel);
16449          
16450         try {
16451             var p = range.commonAncestorContainer;
16452             while (p.nodeType == 3) { // text node
16453                 p = p.parentNode;
16454             }
16455             return p;
16456         } catch (e) {
16457             return null;
16458         }
16459     
16460     },
16461     /***
16462      *
16463      * Range intersection.. the hard stuff...
16464      *  '-1' = before
16465      *  '0' = hits..
16466      *  '1' = after.
16467      *         [ -- selected range --- ]
16468      *   [fail]                        [fail]
16469      *
16470      *    basically..
16471      *      if end is before start or  hits it. fail.
16472      *      if start is after end or hits it fail.
16473      *
16474      *   if either hits (but other is outside. - then it's not 
16475      *   
16476      *    
16477      **/
16478     
16479     
16480     // @see http://www.thismuchiknow.co.uk/?p=64.
16481     rangeIntersectsNode : function(range, node)
16482     {
16483         var nodeRange = node.ownerDocument.createRange();
16484         try {
16485             nodeRange.selectNode(node);
16486         } catch (e) {
16487             nodeRange.selectNodeContents(node);
16488         }
16489     
16490         var rangeStartRange = range.cloneRange();
16491         rangeStartRange.collapse(true);
16492     
16493         var rangeEndRange = range.cloneRange();
16494         rangeEndRange.collapse(false);
16495     
16496         var nodeStartRange = nodeRange.cloneRange();
16497         nodeStartRange.collapse(true);
16498     
16499         var nodeEndRange = nodeRange.cloneRange();
16500         nodeEndRange.collapse(false);
16501     
16502         return rangeStartRange.compareBoundaryPoints(
16503                  Range.START_TO_START, nodeEndRange) == -1 &&
16504                rangeEndRange.compareBoundaryPoints(
16505                  Range.START_TO_START, nodeStartRange) == 1;
16506         
16507          
16508     },
16509     rangeCompareNode : function(range, node)
16510     {
16511         var nodeRange = node.ownerDocument.createRange();
16512         try {
16513             nodeRange.selectNode(node);
16514         } catch (e) {
16515             nodeRange.selectNodeContents(node);
16516         }
16517         
16518         
16519         range.collapse(true);
16520     
16521         nodeRange.collapse(true);
16522      
16523         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
16524         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
16525          
16526         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
16527         
16528         var nodeIsBefore   =  ss == 1;
16529         var nodeIsAfter    = ee == -1;
16530         
16531         if (nodeIsBefore && nodeIsAfter)
16532             return 0; // outer
16533         if (!nodeIsBefore && nodeIsAfter)
16534             return 1; //right trailed.
16535         
16536         if (nodeIsBefore && !nodeIsAfter)
16537             return 2;  // left trailed.
16538         // fully contined.
16539         return 3;
16540     },
16541
16542     // private? - in a new class?
16543     cleanUpPaste :  function()
16544     {
16545         // cleans up the whole document..
16546         Roo.log('cleanuppaste');
16547         
16548         this.cleanUpChildren(this.doc.body);
16549         var clean = this.cleanWordChars(this.doc.body.innerHTML);
16550         if (clean != this.doc.body.innerHTML) {
16551             this.doc.body.innerHTML = clean;
16552         }
16553         
16554     },
16555     
16556     cleanWordChars : function(input) {// change the chars to hex code
16557         var he = Roo.HtmlEditorCore;
16558         
16559         var output = input;
16560         Roo.each(he.swapCodes, function(sw) { 
16561             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
16562             
16563             output = output.replace(swapper, sw[1]);
16564         });
16565         
16566         return output;
16567     },
16568     
16569     
16570     cleanUpChildren : function (n)
16571     {
16572         if (!n.childNodes.length) {
16573             return;
16574         }
16575         for (var i = n.childNodes.length-1; i > -1 ; i--) {
16576            this.cleanUpChild(n.childNodes[i]);
16577         }
16578     },
16579     
16580     
16581         
16582     
16583     cleanUpChild : function (node)
16584     {
16585         var ed = this;
16586         //console.log(node);
16587         if (node.nodeName == "#text") {
16588             // clean up silly Windows -- stuff?
16589             return; 
16590         }
16591         if (node.nodeName == "#comment") {
16592             node.parentNode.removeChild(node);
16593             // clean up silly Windows -- stuff?
16594             return; 
16595         }
16596         
16597         if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16598             // remove node.
16599             node.parentNode.removeChild(node);
16600             return;
16601             
16602         }
16603         
16604         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16605         
16606         // remove <a name=....> as rendering on yahoo mailer is borked with this.
16607         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16608         
16609         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16610         //    remove_keep_children = true;
16611         //}
16612         
16613         if (remove_keep_children) {
16614             this.cleanUpChildren(node);
16615             // inserts everything just before this node...
16616             while (node.childNodes.length) {
16617                 var cn = node.childNodes[0];
16618                 node.removeChild(cn);
16619                 node.parentNode.insertBefore(cn, node);
16620             }
16621             node.parentNode.removeChild(node);
16622             return;
16623         }
16624         
16625         if (!node.attributes || !node.attributes.length) {
16626             this.cleanUpChildren(node);
16627             return;
16628         }
16629         
16630         function cleanAttr(n,v)
16631         {
16632             
16633             if (v.match(/^\./) || v.match(/^\//)) {
16634                 return;
16635             }
16636             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16637                 return;
16638             }
16639             if (v.match(/^#/)) {
16640                 return;
16641             }
16642 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16643             node.removeAttribute(n);
16644             
16645         }
16646         
16647         function cleanStyle(n,v)
16648         {
16649             if (v.match(/expression/)) { //XSS?? should we even bother..
16650                 node.removeAttribute(n);
16651                 return;
16652             }
16653             var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16654             var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16655             
16656             
16657             var parts = v.split(/;/);
16658             var clean = [];
16659             
16660             Roo.each(parts, function(p) {
16661                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16662                 if (!p.length) {
16663                     return true;
16664                 }
16665                 var l = p.split(':').shift().replace(/\s+/g,'');
16666                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16667                 
16668                 if ( cblack.indexOf(l) > -1) {
16669 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16670                     //node.removeAttribute(n);
16671                     return true;
16672                 }
16673                 //Roo.log()
16674                 // only allow 'c whitelisted system attributes'
16675                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
16676 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16677                     //node.removeAttribute(n);
16678                     return true;
16679                 }
16680                 
16681                 
16682                  
16683                 
16684                 clean.push(p);
16685                 return true;
16686             });
16687             if (clean.length) { 
16688                 node.setAttribute(n, clean.join(';'));
16689             } else {
16690                 node.removeAttribute(n);
16691             }
16692             
16693         }
16694         
16695         
16696         for (var i = node.attributes.length-1; i > -1 ; i--) {
16697             var a = node.attributes[i];
16698             //console.log(a);
16699             
16700             if (a.name.toLowerCase().substr(0,2)=='on')  {
16701                 node.removeAttribute(a.name);
16702                 continue;
16703             }
16704             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16705                 node.removeAttribute(a.name);
16706                 continue;
16707             }
16708             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16709                 cleanAttr(a.name,a.value); // fixme..
16710                 continue;
16711             }
16712             if (a.name == 'style') {
16713                 cleanStyle(a.name,a.value);
16714                 continue;
16715             }
16716             /// clean up MS crap..
16717             // tecnically this should be a list of valid class'es..
16718             
16719             
16720             if (a.name == 'class') {
16721                 if (a.value.match(/^Mso/)) {
16722                     node.className = '';
16723                 }
16724                 
16725                 if (a.value.match(/body/)) {
16726                     node.className = '';
16727                 }
16728                 continue;
16729             }
16730             
16731             // style cleanup!?
16732             // class cleanup?
16733             
16734         }
16735         
16736         
16737         this.cleanUpChildren(node);
16738         
16739         
16740     },
16741     /**
16742      * Clean up MS wordisms...
16743      */
16744     cleanWord : function(node)
16745     {
16746         var _t = this;
16747         var cleanWordChildren = function()
16748         {
16749             if (!node.childNodes.length) {
16750                 return;
16751             }
16752             for (var i = node.childNodes.length-1; i > -1 ; i--) {
16753                _t.cleanWord(node.childNodes[i]);
16754             }
16755         }
16756         
16757         
16758         if (!node) {
16759             this.cleanWord(this.doc.body);
16760             return;
16761         }
16762         if (node.nodeName == "#text") {
16763             // clean up silly Windows -- stuff?
16764             return; 
16765         }
16766         if (node.nodeName == "#comment") {
16767             node.parentNode.removeChild(node);
16768             // clean up silly Windows -- stuff?
16769             return; 
16770         }
16771         
16772         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16773             node.parentNode.removeChild(node);
16774             return;
16775         }
16776         
16777         // remove - but keep children..
16778         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16779             while (node.childNodes.length) {
16780                 var cn = node.childNodes[0];
16781                 node.removeChild(cn);
16782                 node.parentNode.insertBefore(cn, node);
16783             }
16784             node.parentNode.removeChild(node);
16785             cleanWordChildren();
16786             return;
16787         }
16788         // clean styles
16789         if (node.className.length) {
16790             
16791             var cn = node.className.split(/\W+/);
16792             var cna = [];
16793             Roo.each(cn, function(cls) {
16794                 if (cls.match(/Mso[a-zA-Z]+/)) {
16795                     return;
16796                 }
16797                 cna.push(cls);
16798             });
16799             node.className = cna.length ? cna.join(' ') : '';
16800             if (!cna.length) {
16801                 node.removeAttribute("class");
16802             }
16803         }
16804         
16805         if (node.hasAttribute("lang")) {
16806             node.removeAttribute("lang");
16807         }
16808         
16809         if (node.hasAttribute("style")) {
16810             
16811             var styles = node.getAttribute("style").split(";");
16812             var nstyle = [];
16813             Roo.each(styles, function(s) {
16814                 if (!s.match(/:/)) {
16815                     return;
16816                 }
16817                 var kv = s.split(":");
16818                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16819                     return;
16820                 }
16821                 // what ever is left... we allow.
16822                 nstyle.push(s);
16823             });
16824             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16825             if (!nstyle.length) {
16826                 node.removeAttribute('style');
16827             }
16828         }
16829         
16830         cleanWordChildren();
16831         
16832         
16833     },
16834     domToHTML : function(currentElement, depth, nopadtext) {
16835         
16836             depth = depth || 0;
16837             nopadtext = nopadtext || false;
16838         
16839             if (!currentElement) {
16840                 return this.domToHTML(this.doc.body);
16841             }
16842             
16843             //Roo.log(currentElement);
16844             var j;
16845             var allText = false;
16846             var nodeName = currentElement.nodeName;
16847             var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16848             
16849             if  (nodeName == '#text') {
16850                 return currentElement.nodeValue;
16851             }
16852             
16853             
16854             var ret = '';
16855             if (nodeName != 'BODY') {
16856                  
16857                 var i = 0;
16858                 // Prints the node tagName, such as <A>, <IMG>, etc
16859                 if (tagName) {
16860                     var attr = [];
16861                     for(i = 0; i < currentElement.attributes.length;i++) {
16862                         // quoting?
16863                         var aname = currentElement.attributes.item(i).name;
16864                         if (!currentElement.attributes.item(i).value.length) {
16865                             continue;
16866                         }
16867                         attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16868                     }
16869                     
16870                     ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16871                 } 
16872                 else {
16873                     
16874                     // eack
16875                 }
16876             } else {
16877                 tagName = false;
16878             }
16879             if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16880                 return ret;
16881             }
16882             if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16883                 nopadtext = true;
16884             }
16885             
16886             
16887             // Traverse the tree
16888             i = 0;
16889             var currentElementChild = currentElement.childNodes.item(i);
16890             var allText = true;
16891             var innerHTML  = '';
16892             lastnode = '';
16893             while (currentElementChild) {
16894                 // Formatting code (indent the tree so it looks nice on the screen)
16895                 var nopad = nopadtext;
16896                 if (lastnode == 'SPAN') {
16897                     nopad  = true;
16898                 }
16899                 // text
16900                 if  (currentElementChild.nodeName == '#text') {
16901                     var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16902                     if (!nopad && toadd.length > 80) {
16903                         innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
16904                     }
16905                     innerHTML  += toadd;
16906                     
16907                     i++;
16908                     currentElementChild = currentElement.childNodes.item(i);
16909                     lastNode = '';
16910                     continue;
16911                 }
16912                 allText = false;
16913                 
16914                 innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
16915                     
16916                 // Recursively traverse the tree structure of the child node
16917                 innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
16918                 lastnode = currentElementChild.nodeName;
16919                 i++;
16920                 currentElementChild=currentElement.childNodes.item(i);
16921             }
16922             
16923             ret += innerHTML;
16924             
16925             if (!allText) {
16926                     // The remaining code is mostly for formatting the tree
16927                 ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
16928             }
16929             
16930             
16931             if (tagName) {
16932                 ret+= "</"+tagName+">";
16933             }
16934             return ret;
16935             
16936         }
16937     
16938     // hide stuff that is not compatible
16939     /**
16940      * @event blur
16941      * @hide
16942      */
16943     /**
16944      * @event change
16945      * @hide
16946      */
16947     /**
16948      * @event focus
16949      * @hide
16950      */
16951     /**
16952      * @event specialkey
16953      * @hide
16954      */
16955     /**
16956      * @cfg {String} fieldClass @hide
16957      */
16958     /**
16959      * @cfg {String} focusClass @hide
16960      */
16961     /**
16962      * @cfg {String} autoCreate @hide
16963      */
16964     /**
16965      * @cfg {String} inputType @hide
16966      */
16967     /**
16968      * @cfg {String} invalidClass @hide
16969      */
16970     /**
16971      * @cfg {String} invalidText @hide
16972      */
16973     /**
16974      * @cfg {String} msgFx @hide
16975      */
16976     /**
16977      * @cfg {String} validateOnBlur @hide
16978      */
16979 });
16980
16981 Roo.HtmlEditorCore.white = [
16982         'area', 'br', 'img', 'input', 'hr', 'wbr',
16983         
16984        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
16985        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
16986        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
16987        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
16988        'table',   'ul',         'xmp', 
16989        
16990        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
16991       'thead',   'tr', 
16992      
16993       'dir', 'menu', 'ol', 'ul', 'dl',
16994        
16995       'embed',  'object'
16996 ];
16997
16998
16999 Roo.HtmlEditorCore.black = [
17000     //    'embed',  'object', // enable - backend responsiblity to clean thiese
17001         'applet', // 
17002         'base',   'basefont', 'bgsound', 'blink',  'body', 
17003         'frame',  'frameset', 'head',    'html',   'ilayer', 
17004         'iframe', 'layer',  'link',     'meta',    'object',   
17005         'script', 'style' ,'title',  'xml' // clean later..
17006 ];
17007 Roo.HtmlEditorCore.clean = [
17008     'script', 'style', 'title', 'xml'
17009 ];
17010 Roo.HtmlEditorCore.remove = [
17011     'font'
17012 ];
17013 // attributes..
17014
17015 Roo.HtmlEditorCore.ablack = [
17016     'on'
17017 ];
17018     
17019 Roo.HtmlEditorCore.aclean = [ 
17020     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
17021 ];
17022
17023 // protocols..
17024 Roo.HtmlEditorCore.pwhite= [
17025         'http',  'https',  'mailto'
17026 ];
17027
17028 // white listed style attributes.
17029 Roo.HtmlEditorCore.cwhite= [
17030       //  'text-align', /// default is to allow most things..
17031       
17032          
17033 //        'font-size'//??
17034 ];
17035
17036 // black listed style attributes.
17037 Roo.HtmlEditorCore.cblack= [
17038       //  'font-size' -- this can be set by the project 
17039 ];
17040
17041
17042 Roo.HtmlEditorCore.swapCodes   =[ 
17043     [    8211, "--" ], 
17044     [    8212, "--" ], 
17045     [    8216,  "'" ],  
17046     [    8217, "'" ],  
17047     [    8220, '"' ],  
17048     [    8221, '"' ],  
17049     [    8226, "*" ],  
17050     [    8230, "..." ]
17051 ]; 
17052
17053     /*
17054  * - LGPL
17055  *
17056  * HtmlEditor
17057  * 
17058  */
17059
17060 /**
17061  * @class Roo.bootstrap.HtmlEditor
17062  * @extends Roo.bootstrap.TextArea
17063  * Bootstrap HtmlEditor class
17064
17065  * @constructor
17066  * Create a new HtmlEditor
17067  * @param {Object} config The config object
17068  */
17069
17070 Roo.bootstrap.HtmlEditor = function(config){
17071     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
17072     if (!this.toolbars) {
17073         this.toolbars = [];
17074     }
17075     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
17076     this.addEvents({
17077             /**
17078              * @event initialize
17079              * Fires when the editor is fully initialized (including the iframe)
17080              * @param {HtmlEditor} this
17081              */
17082             initialize: true,
17083             /**
17084              * @event activate
17085              * Fires when the editor is first receives the focus. Any insertion must wait
17086              * until after this event.
17087              * @param {HtmlEditor} this
17088              */
17089             activate: true,
17090              /**
17091              * @event beforesync
17092              * Fires before the textarea is updated with content from the editor iframe. Return false
17093              * to cancel the sync.
17094              * @param {HtmlEditor} this
17095              * @param {String} html
17096              */
17097             beforesync: true,
17098              /**
17099              * @event beforepush
17100              * Fires before the iframe editor is updated with content from the textarea. Return false
17101              * to cancel the push.
17102              * @param {HtmlEditor} this
17103              * @param {String} html
17104              */
17105             beforepush: true,
17106              /**
17107              * @event sync
17108              * Fires when the textarea is updated with content from the editor iframe.
17109              * @param {HtmlEditor} this
17110              * @param {String} html
17111              */
17112             sync: true,
17113              /**
17114              * @event push
17115              * Fires when the iframe editor is updated with content from the textarea.
17116              * @param {HtmlEditor} this
17117              * @param {String} html
17118              */
17119             push: true,
17120              /**
17121              * @event editmodechange
17122              * Fires when the editor switches edit modes
17123              * @param {HtmlEditor} this
17124              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
17125              */
17126             editmodechange: true,
17127             /**
17128              * @event editorevent
17129              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17130              * @param {HtmlEditor} this
17131              */
17132             editorevent: true,
17133             /**
17134              * @event firstfocus
17135              * Fires when on first focus - needed by toolbars..
17136              * @param {HtmlEditor} this
17137              */
17138             firstfocus: true,
17139             /**
17140              * @event autosave
17141              * Auto save the htmlEditor value as a file into Events
17142              * @param {HtmlEditor} this
17143              */
17144             autosave: true,
17145             /**
17146              * @event savedpreview
17147              * preview the saved version of htmlEditor
17148              * @param {HtmlEditor} this
17149              */
17150             savedpreview: true
17151         });
17152 };
17153
17154
17155 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
17156     
17157     
17158       /**
17159      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
17160      */
17161     toolbars : false,
17162    
17163      /**
17164      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17165      *                        Roo.resizable.
17166      */
17167     resizable : false,
17168      /**
17169      * @cfg {Number} height (in pixels)
17170      */   
17171     height: 300,
17172    /**
17173      * @cfg {Number} width (in pixels)
17174      */   
17175     width: false,
17176     
17177     /**
17178      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17179      * 
17180      */
17181     stylesheets: false,
17182     
17183     // id of frame..
17184     frameId: false,
17185     
17186     // private properties
17187     validationEvent : false,
17188     deferHeight: true,
17189     initialized : false,
17190     activated : false,
17191     
17192     onFocus : Roo.emptyFn,
17193     iframePad:3,
17194     hideMode:'offsets',
17195     
17196     
17197     tbContainer : false,
17198     
17199     toolbarContainer :function() {
17200         return this.wrap.select('.x-html-editor-tb',true).first();
17201     },
17202
17203     /**
17204      * Protected method that will not generally be called directly. It
17205      * is called when the editor creates its toolbar. Override this method if you need to
17206      * add custom toolbar buttons.
17207      * @param {HtmlEditor} editor
17208      */
17209     createToolbar : function(){
17210         
17211         Roo.log("create toolbars");
17212         
17213         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
17214         this.toolbars[0].render(this.toolbarContainer());
17215         
17216         return;
17217         
17218 //        if (!editor.toolbars || !editor.toolbars.length) {
17219 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
17220 //        }
17221 //        
17222 //        for (var i =0 ; i < editor.toolbars.length;i++) {
17223 //            editor.toolbars[i] = Roo.factory(
17224 //                    typeof(editor.toolbars[i]) == 'string' ?
17225 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
17226 //                Roo.bootstrap.HtmlEditor);
17227 //            editor.toolbars[i].init(editor);
17228 //        }
17229     },
17230
17231      
17232     // private
17233     onRender : function(ct, position)
17234     {
17235        // Roo.log("Call onRender: " + this.xtype);
17236         var _t = this;
17237         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
17238       
17239         this.wrap = this.inputEl().wrap({
17240             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
17241         });
17242         
17243         this.editorcore.onRender(ct, position);
17244          
17245         if (this.resizable) {
17246             this.resizeEl = new Roo.Resizable(this.wrap, {
17247                 pinned : true,
17248                 wrap: true,
17249                 dynamic : true,
17250                 minHeight : this.height,
17251                 height: this.height,
17252                 handles : this.resizable,
17253                 width: this.width,
17254                 listeners : {
17255                     resize : function(r, w, h) {
17256                         _t.onResize(w,h); // -something
17257                     }
17258                 }
17259             });
17260             
17261         }
17262         this.createToolbar(this);
17263        
17264         
17265         if(!this.width && this.resizable){
17266             this.setSize(this.wrap.getSize());
17267         }
17268         if (this.resizeEl) {
17269             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
17270             // should trigger onReize..
17271         }
17272         
17273     },
17274
17275     // private
17276     onResize : function(w, h)
17277     {
17278         Roo.log('resize: ' +w + ',' + h );
17279         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
17280         var ew = false;
17281         var eh = false;
17282         
17283         if(this.inputEl() ){
17284             if(typeof w == 'number'){
17285                 var aw = w - this.wrap.getFrameWidth('lr');
17286                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
17287                 ew = aw;
17288             }
17289             if(typeof h == 'number'){
17290                  var tbh = -11;  // fixme it needs to tool bar size!
17291                 for (var i =0; i < this.toolbars.length;i++) {
17292                     // fixme - ask toolbars for heights?
17293                     tbh += this.toolbars[i].el.getHeight();
17294                     //if (this.toolbars[i].footer) {
17295                     //    tbh += this.toolbars[i].footer.el.getHeight();
17296                     //}
17297                 }
17298               
17299                 
17300                 
17301                 
17302                 
17303                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
17304                 ah -= 5; // knock a few pixes off for look..
17305                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
17306                 var eh = ah;
17307             }
17308         }
17309         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
17310         this.editorcore.onResize(ew,eh);
17311         
17312     },
17313
17314     /**
17315      * Toggles the editor between standard and source edit mode.
17316      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17317      */
17318     toggleSourceEdit : function(sourceEditMode)
17319     {
17320         this.editorcore.toggleSourceEdit(sourceEditMode);
17321         
17322         if(this.editorcore.sourceEditMode){
17323             Roo.log('editor - showing textarea');
17324             
17325 //            Roo.log('in');
17326 //            Roo.log(this.syncValue());
17327             this.syncValue();
17328             this.inputEl().removeClass(['hide', 'x-hidden']);
17329             this.inputEl().dom.removeAttribute('tabIndex');
17330             this.inputEl().focus();
17331         }else{
17332             Roo.log('editor - hiding textarea');
17333 //            Roo.log('out')
17334 //            Roo.log(this.pushValue()); 
17335             this.pushValue();
17336             
17337             this.inputEl().addClass(['hide', 'x-hidden']);
17338             this.inputEl().dom.setAttribute('tabIndex', -1);
17339             //this.deferFocus();
17340         }
17341          
17342         if(this.resizable){
17343             this.setSize(this.wrap.getSize());
17344         }
17345         
17346         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
17347     },
17348  
17349     // private (for BoxComponent)
17350     adjustSize : Roo.BoxComponent.prototype.adjustSize,
17351
17352     // private (for BoxComponent)
17353     getResizeEl : function(){
17354         return this.wrap;
17355     },
17356
17357     // private (for BoxComponent)
17358     getPositionEl : function(){
17359         return this.wrap;
17360     },
17361
17362     // private
17363     initEvents : function(){
17364         this.originalValue = this.getValue();
17365     },
17366
17367 //    /**
17368 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17369 //     * @method
17370 //     */
17371 //    markInvalid : Roo.emptyFn,
17372 //    /**
17373 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
17374 //     * @method
17375 //     */
17376 //    clearInvalid : Roo.emptyFn,
17377
17378     setValue : function(v){
17379         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
17380         this.editorcore.pushValue();
17381     },
17382
17383      
17384     // private
17385     deferFocus : function(){
17386         this.focus.defer(10, this);
17387     },
17388
17389     // doc'ed in Field
17390     focus : function(){
17391         this.editorcore.focus();
17392         
17393     },
17394       
17395
17396     // private
17397     onDestroy : function(){
17398         
17399         
17400         
17401         if(this.rendered){
17402             
17403             for (var i =0; i < this.toolbars.length;i++) {
17404                 // fixme - ask toolbars for heights?
17405                 this.toolbars[i].onDestroy();
17406             }
17407             
17408             this.wrap.dom.innerHTML = '';
17409             this.wrap.remove();
17410         }
17411     },
17412
17413     // private
17414     onFirstFocus : function(){
17415         //Roo.log("onFirstFocus");
17416         this.editorcore.onFirstFocus();
17417          for (var i =0; i < this.toolbars.length;i++) {
17418             this.toolbars[i].onFirstFocus();
17419         }
17420         
17421     },
17422     
17423     // private
17424     syncValue : function()
17425     {   
17426         this.editorcore.syncValue();
17427     },
17428     
17429     pushValue : function()
17430     {   
17431         this.editorcore.pushValue();
17432     }
17433      
17434     
17435     // hide stuff that is not compatible
17436     /**
17437      * @event blur
17438      * @hide
17439      */
17440     /**
17441      * @event change
17442      * @hide
17443      */
17444     /**
17445      * @event focus
17446      * @hide
17447      */
17448     /**
17449      * @event specialkey
17450      * @hide
17451      */
17452     /**
17453      * @cfg {String} fieldClass @hide
17454      */
17455     /**
17456      * @cfg {String} focusClass @hide
17457      */
17458     /**
17459      * @cfg {String} autoCreate @hide
17460      */
17461     /**
17462      * @cfg {String} inputType @hide
17463      */
17464     /**
17465      * @cfg {String} invalidClass @hide
17466      */
17467     /**
17468      * @cfg {String} invalidText @hide
17469      */
17470     /**
17471      * @cfg {String} msgFx @hide
17472      */
17473     /**
17474      * @cfg {String} validateOnBlur @hide
17475      */
17476 });
17477  
17478     
17479    
17480    
17481    
17482       
17483 Roo.namespace('Roo.bootstrap.htmleditor');
17484 /**
17485  * @class Roo.bootstrap.HtmlEditorToolbar1
17486  * Basic Toolbar
17487  * 
17488  * Usage:
17489  *
17490  new Roo.bootstrap.HtmlEditor({
17491     ....
17492     toolbars : [
17493         new Roo.bootstrap.HtmlEditorToolbar1({
17494             disable : { fonts: 1 , format: 1, ..., ... , ...],
17495             btns : [ .... ]
17496         })
17497     }
17498      
17499  * 
17500  * @cfg {Object} disable List of elements to disable..
17501  * @cfg {Array} btns List of additional buttons.
17502  * 
17503  * 
17504  * NEEDS Extra CSS? 
17505  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
17506  */
17507  
17508 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
17509 {
17510     
17511     Roo.apply(this, config);
17512     
17513     // default disabled, based on 'good practice'..
17514     this.disable = this.disable || {};
17515     Roo.applyIf(this.disable, {
17516         fontSize : true,
17517         colors : true,
17518         specialElements : true
17519     });
17520     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
17521     
17522     this.editor = config.editor;
17523     this.editorcore = config.editor.editorcore;
17524     
17525     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
17526     
17527     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
17528     // dont call parent... till later.
17529 }
17530 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
17531      
17532     bar : true,
17533     
17534     editor : false,
17535     editorcore : false,
17536     
17537     
17538     formats : [
17539         "p" ,  
17540         "h1","h2","h3","h4","h5","h6", 
17541         "pre", "code", 
17542         "abbr", "acronym", "address", "cite", "samp", "var",
17543         'div','span'
17544     ],
17545     
17546     onRender : function(ct, position)
17547     {
17548        // Roo.log("Call onRender: " + this.xtype);
17549         
17550        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
17551        Roo.log(this.el);
17552        this.el.dom.style.marginBottom = '0';
17553        var _this = this;
17554        var editorcore = this.editorcore;
17555        var editor= this.editor;
17556        
17557        var children = [];
17558        var btn = function(id,cmd , toggle, handler){
17559        
17560             var  event = toggle ? 'toggle' : 'click';
17561        
17562             var a = {
17563                 size : 'sm',
17564                 xtype: 'Button',
17565                 xns: Roo.bootstrap,
17566                 glyphicon : id,
17567                 cmd : id || cmd,
17568                 enableToggle:toggle !== false,
17569                 //html : 'submit'
17570                 pressed : toggle ? false : null,
17571                 listeners : {}
17572             }
17573             a.listeners[toggle ? 'toggle' : 'click'] = function() {
17574                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
17575             }
17576             children.push(a);
17577             return a;
17578        }
17579         
17580         var style = {
17581                 xtype: 'Button',
17582                 size : 'sm',
17583                 xns: Roo.bootstrap,
17584                 glyphicon : 'font',
17585                 //html : 'submit'
17586                 menu : {
17587                     xtype: 'Menu',
17588                     xns: Roo.bootstrap,
17589                     items:  []
17590                 }
17591         };
17592         Roo.each(this.formats, function(f) {
17593             style.menu.items.push({
17594                 xtype :'MenuItem',
17595                 xns: Roo.bootstrap,
17596                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17597                 tagname : f,
17598                 listeners : {
17599                     click : function()
17600                     {
17601                         editorcore.insertTag(this.tagname);
17602                         editor.focus();
17603                     }
17604                 }
17605                 
17606             });
17607         });
17608          children.push(style);   
17609             
17610             
17611         btn('bold',false,true);
17612         btn('italic',false,true);
17613         btn('align-left', 'justifyleft',true);
17614         btn('align-center', 'justifycenter',true);
17615         btn('align-right' , 'justifyright',true);
17616         btn('link', false, false, function(btn) {
17617             //Roo.log("create link?");
17618             var url = prompt(this.createLinkText, this.defaultLinkValue);
17619             if(url && url != 'http:/'+'/'){
17620                 this.editorcore.relayCmd('createlink', url);
17621             }
17622         }),
17623         btn('list','insertunorderedlist',true);
17624         btn('pencil', false,true, function(btn){
17625                 Roo.log(this);
17626                 
17627                 this.toggleSourceEdit(btn.pressed);
17628         });
17629         /*
17630         var cog = {
17631                 xtype: 'Button',
17632                 size : 'sm',
17633                 xns: Roo.bootstrap,
17634                 glyphicon : 'cog',
17635                 //html : 'submit'
17636                 menu : {
17637                     xtype: 'Menu',
17638                     xns: Roo.bootstrap,
17639                     items:  []
17640                 }
17641         };
17642         
17643         cog.menu.items.push({
17644             xtype :'MenuItem',
17645             xns: Roo.bootstrap,
17646             html : Clean styles,
17647             tagname : f,
17648             listeners : {
17649                 click : function()
17650                 {
17651                     editorcore.insertTag(this.tagname);
17652                     editor.focus();
17653                 }
17654             }
17655             
17656         });
17657        */
17658         
17659          
17660        this.xtype = 'NavSimplebar';
17661         
17662         for(var i=0;i< children.length;i++) {
17663             
17664             this.buttons.add(this.addxtypeChild(children[i]));
17665             
17666         }
17667         
17668         editor.on('editorevent', this.updateToolbar, this);
17669     },
17670     onBtnClick : function(id)
17671     {
17672        this.editorcore.relayCmd(id);
17673        this.editorcore.focus();
17674     },
17675     
17676     /**
17677      * Protected method that will not generally be called directly. It triggers
17678      * a toolbar update by reading the markup state of the current selection in the editor.
17679      */
17680     updateToolbar: function(){
17681
17682         if(!this.editorcore.activated){
17683             this.editor.onFirstFocus(); // is this neeed?
17684             return;
17685         }
17686
17687         var btns = this.buttons; 
17688         var doc = this.editorcore.doc;
17689         btns.get('bold').setActive(doc.queryCommandState('bold'));
17690         btns.get('italic').setActive(doc.queryCommandState('italic'));
17691         //btns.get('underline').setActive(doc.queryCommandState('underline'));
17692         
17693         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17694         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17695         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17696         
17697         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17698         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17699          /*
17700         
17701         var ans = this.editorcore.getAllAncestors();
17702         if (this.formatCombo) {
17703             
17704             
17705             var store = this.formatCombo.store;
17706             this.formatCombo.setValue("");
17707             for (var i =0; i < ans.length;i++) {
17708                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17709                     // select it..
17710                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17711                     break;
17712                 }
17713             }
17714         }
17715         
17716         
17717         
17718         // hides menus... - so this cant be on a menu...
17719         Roo.bootstrap.MenuMgr.hideAll();
17720         */
17721         Roo.bootstrap.MenuMgr.hideAll();
17722         //this.editorsyncValue();
17723     },
17724     onFirstFocus: function() {
17725         this.buttons.each(function(item){
17726            item.enable();
17727         });
17728     },
17729     toggleSourceEdit : function(sourceEditMode){
17730         
17731           
17732         if(sourceEditMode){
17733             Roo.log("disabling buttons");
17734            this.buttons.each( function(item){
17735                 if(item.cmd != 'pencil'){
17736                     item.disable();
17737                 }
17738             });
17739           
17740         }else{
17741             Roo.log("enabling buttons");
17742             if(this.editorcore.initialized){
17743                 this.buttons.each( function(item){
17744                     item.enable();
17745                 });
17746             }
17747             
17748         }
17749         Roo.log("calling toggole on editor");
17750         // tell the editor that it's been pressed..
17751         this.editor.toggleSourceEdit(sourceEditMode);
17752        
17753     }
17754 });
17755
17756
17757
17758
17759
17760 /**
17761  * @class Roo.bootstrap.Table.AbstractSelectionModel
17762  * @extends Roo.util.Observable
17763  * Abstract base class for grid SelectionModels.  It provides the interface that should be
17764  * implemented by descendant classes.  This class should not be directly instantiated.
17765  * @constructor
17766  */
17767 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17768     this.locked = false;
17769     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17770 };
17771
17772
17773 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
17774     /** @ignore Called by the grid automatically. Do not call directly. */
17775     init : function(grid){
17776         this.grid = grid;
17777         this.initEvents();
17778     },
17779
17780     /**
17781      * Locks the selections.
17782      */
17783     lock : function(){
17784         this.locked = true;
17785     },
17786
17787     /**
17788      * Unlocks the selections.
17789      */
17790     unlock : function(){
17791         this.locked = false;
17792     },
17793
17794     /**
17795      * Returns true if the selections are locked.
17796      * @return {Boolean}
17797      */
17798     isLocked : function(){
17799         return this.locked;
17800     }
17801 });
17802 /**
17803  * @extends Roo.bootstrap.Table.AbstractSelectionModel
17804  * @class Roo.bootstrap.Table.RowSelectionModel
17805  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17806  * It supports multiple selections and keyboard selection/navigation. 
17807  * @constructor
17808  * @param {Object} config
17809  */
17810
17811 Roo.bootstrap.Table.RowSelectionModel = function(config){
17812     Roo.apply(this, config);
17813     this.selections = new Roo.util.MixedCollection(false, function(o){
17814         return o.id;
17815     });
17816
17817     this.last = false;
17818     this.lastActive = false;
17819
17820     this.addEvents({
17821         /**
17822              * @event selectionchange
17823              * Fires when the selection changes
17824              * @param {SelectionModel} this
17825              */
17826             "selectionchange" : true,
17827         /**
17828              * @event afterselectionchange
17829              * Fires after the selection changes (eg. by key press or clicking)
17830              * @param {SelectionModel} this
17831              */
17832             "afterselectionchange" : true,
17833         /**
17834              * @event beforerowselect
17835              * Fires when a row is selected being selected, return false to cancel.
17836              * @param {SelectionModel} this
17837              * @param {Number} rowIndex The selected index
17838              * @param {Boolean} keepExisting False if other selections will be cleared
17839              */
17840             "beforerowselect" : true,
17841         /**
17842              * @event rowselect
17843              * Fires when a row is selected.
17844              * @param {SelectionModel} this
17845              * @param {Number} rowIndex The selected index
17846              * @param {Roo.data.Record} r The record
17847              */
17848             "rowselect" : true,
17849         /**
17850              * @event rowdeselect
17851              * Fires when a row is deselected.
17852              * @param {SelectionModel} this
17853              * @param {Number} rowIndex The selected index
17854              */
17855         "rowdeselect" : true
17856     });
17857     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17858     this.locked = false;
17859 };
17860
17861 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
17862     /**
17863      * @cfg {Boolean} singleSelect
17864      * True to allow selection of only one row at a time (defaults to false)
17865      */
17866     singleSelect : false,
17867
17868     // private
17869     initEvents : function(){
17870
17871         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17872             this.grid.on("mousedown", this.handleMouseDown, this);
17873         }else{ // allow click to work like normal
17874             this.grid.on("rowclick", this.handleDragableRowClick, this);
17875         }
17876
17877         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17878             "up" : function(e){
17879                 if(!e.shiftKey){
17880                     this.selectPrevious(e.shiftKey);
17881                 }else if(this.last !== false && this.lastActive !== false){
17882                     var last = this.last;
17883                     this.selectRange(this.last,  this.lastActive-1);
17884                     this.grid.getView().focusRow(this.lastActive);
17885                     if(last !== false){
17886                         this.last = last;
17887                     }
17888                 }else{
17889                     this.selectFirstRow();
17890                 }
17891                 this.fireEvent("afterselectionchange", this);
17892             },
17893             "down" : function(e){
17894                 if(!e.shiftKey){
17895                     this.selectNext(e.shiftKey);
17896                 }else if(this.last !== false && this.lastActive !== false){
17897                     var last = this.last;
17898                     this.selectRange(this.last,  this.lastActive+1);
17899                     this.grid.getView().focusRow(this.lastActive);
17900                     if(last !== false){
17901                         this.last = last;
17902                     }
17903                 }else{
17904                     this.selectFirstRow();
17905                 }
17906                 this.fireEvent("afterselectionchange", this);
17907             },
17908             scope: this
17909         });
17910
17911         var view = this.grid.view;
17912         view.on("refresh", this.onRefresh, this);
17913         view.on("rowupdated", this.onRowUpdated, this);
17914         view.on("rowremoved", this.onRemove, this);
17915     },
17916
17917     // private
17918     onRefresh : function(){
17919         var ds = this.grid.dataSource, i, v = this.grid.view;
17920         var s = this.selections;
17921         s.each(function(r){
17922             if((i = ds.indexOfId(r.id)) != -1){
17923                 v.onRowSelect(i);
17924             }else{
17925                 s.remove(r);
17926             }
17927         });
17928     },
17929
17930     // private
17931     onRemove : function(v, index, r){
17932         this.selections.remove(r);
17933     },
17934
17935     // private
17936     onRowUpdated : function(v, index, r){
17937         if(this.isSelected(r)){
17938             v.onRowSelect(index);
17939         }
17940     },
17941
17942     /**
17943      * Select records.
17944      * @param {Array} records The records to select
17945      * @param {Boolean} keepExisting (optional) True to keep existing selections
17946      */
17947     selectRecords : function(records, keepExisting){
17948         if(!keepExisting){
17949             this.clearSelections();
17950         }
17951         var ds = this.grid.dataSource;
17952         for(var i = 0, len = records.length; i < len; i++){
17953             this.selectRow(ds.indexOf(records[i]), true);
17954         }
17955     },
17956
17957     /**
17958      * Gets the number of selected rows.
17959      * @return {Number}
17960      */
17961     getCount : function(){
17962         return this.selections.length;
17963     },
17964
17965     /**
17966      * Selects the first row in the grid.
17967      */
17968     selectFirstRow : function(){
17969         this.selectRow(0);
17970     },
17971
17972     /**
17973      * Select the last row.
17974      * @param {Boolean} keepExisting (optional) True to keep existing selections
17975      */
17976     selectLastRow : function(keepExisting){
17977         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17978     },
17979
17980     /**
17981      * Selects the row immediately following the last selected row.
17982      * @param {Boolean} keepExisting (optional) True to keep existing selections
17983      */
17984     selectNext : function(keepExisting){
17985         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17986             this.selectRow(this.last+1, keepExisting);
17987             this.grid.getView().focusRow(this.last);
17988         }
17989     },
17990
17991     /**
17992      * Selects the row that precedes the last selected row.
17993      * @param {Boolean} keepExisting (optional) True to keep existing selections
17994      */
17995     selectPrevious : function(keepExisting){
17996         if(this.last){
17997             this.selectRow(this.last-1, keepExisting);
17998             this.grid.getView().focusRow(this.last);
17999         }
18000     },
18001
18002     /**
18003      * Returns the selected records
18004      * @return {Array} Array of selected records
18005      */
18006     getSelections : function(){
18007         return [].concat(this.selections.items);
18008     },
18009
18010     /**
18011      * Returns the first selected record.
18012      * @return {Record}
18013      */
18014     getSelected : function(){
18015         return this.selections.itemAt(0);
18016     },
18017
18018
18019     /**
18020      * Clears all selections.
18021      */
18022     clearSelections : function(fast){
18023         if(this.locked) return;
18024         if(fast !== true){
18025             var ds = this.grid.dataSource;
18026             var s = this.selections;
18027             s.each(function(r){
18028                 this.deselectRow(ds.indexOfId(r.id));
18029             }, this);
18030             s.clear();
18031         }else{
18032             this.selections.clear();
18033         }
18034         this.last = false;
18035     },
18036
18037
18038     /**
18039      * Selects all rows.
18040      */
18041     selectAll : function(){
18042         if(this.locked) return;
18043         this.selections.clear();
18044         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
18045             this.selectRow(i, true);
18046         }
18047     },
18048
18049     /**
18050      * Returns True if there is a selection.
18051      * @return {Boolean}
18052      */
18053     hasSelection : function(){
18054         return this.selections.length > 0;
18055     },
18056
18057     /**
18058      * Returns True if the specified row is selected.
18059      * @param {Number/Record} record The record or index of the record to check
18060      * @return {Boolean}
18061      */
18062     isSelected : function(index){
18063         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
18064         return (r && this.selections.key(r.id) ? true : false);
18065     },
18066
18067     /**
18068      * Returns True if the specified record id is selected.
18069      * @param {String} id The id of record to check
18070      * @return {Boolean}
18071      */
18072     isIdSelected : function(id){
18073         return (this.selections.key(id) ? true : false);
18074     },
18075
18076     // private
18077     handleMouseDown : function(e, t){
18078         var view = this.grid.getView(), rowIndex;
18079         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
18080             return;
18081         };
18082         if(e.shiftKey && this.last !== false){
18083             var last = this.last;
18084             this.selectRange(last, rowIndex, e.ctrlKey);
18085             this.last = last; // reset the last
18086             view.focusRow(rowIndex);
18087         }else{
18088             var isSelected = this.isSelected(rowIndex);
18089             if(e.button !== 0 && isSelected){
18090                 view.focusRow(rowIndex);
18091             }else if(e.ctrlKey && isSelected){
18092                 this.deselectRow(rowIndex);
18093             }else if(!isSelected){
18094                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
18095                 view.focusRow(rowIndex);
18096             }
18097         }
18098         this.fireEvent("afterselectionchange", this);
18099     },
18100     // private
18101     handleDragableRowClick :  function(grid, rowIndex, e) 
18102     {
18103         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
18104             this.selectRow(rowIndex, false);
18105             grid.view.focusRow(rowIndex);
18106              this.fireEvent("afterselectionchange", this);
18107         }
18108     },
18109     
18110     /**
18111      * Selects multiple rows.
18112      * @param {Array} rows Array of the indexes of the row to select
18113      * @param {Boolean} keepExisting (optional) True to keep existing selections
18114      */
18115     selectRows : function(rows, keepExisting){
18116         if(!keepExisting){
18117             this.clearSelections();
18118         }
18119         for(var i = 0, len = rows.length; i < len; i++){
18120             this.selectRow(rows[i], true);
18121         }
18122     },
18123
18124     /**
18125      * Selects a range of rows. All rows in between startRow and endRow are also selected.
18126      * @param {Number} startRow The index of the first row in the range
18127      * @param {Number} endRow The index of the last row in the range
18128      * @param {Boolean} keepExisting (optional) True to retain existing selections
18129      */
18130     selectRange : function(startRow, endRow, keepExisting){
18131         if(this.locked) return;
18132         if(!keepExisting){
18133             this.clearSelections();
18134         }
18135         if(startRow <= endRow){
18136             for(var i = startRow; i <= endRow; i++){
18137                 this.selectRow(i, true);
18138             }
18139         }else{
18140             for(var i = startRow; i >= endRow; i--){
18141                 this.selectRow(i, true);
18142             }
18143         }
18144     },
18145
18146     /**
18147      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
18148      * @param {Number} startRow The index of the first row in the range
18149      * @param {Number} endRow The index of the last row in the range
18150      */
18151     deselectRange : function(startRow, endRow, preventViewNotify){
18152         if(this.locked) return;
18153         for(var i = startRow; i <= endRow; i++){
18154             this.deselectRow(i, preventViewNotify);
18155         }
18156     },
18157
18158     /**
18159      * Selects a row.
18160      * @param {Number} row The index of the row to select
18161      * @param {Boolean} keepExisting (optional) True to keep existing selections
18162      */
18163     selectRow : function(index, keepExisting, preventViewNotify){
18164         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
18165         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
18166             if(!keepExisting || this.singleSelect){
18167                 this.clearSelections();
18168             }
18169             var r = this.grid.dataSource.getAt(index);
18170             this.selections.add(r);
18171             this.last = this.lastActive = index;
18172             if(!preventViewNotify){
18173                 this.grid.getView().onRowSelect(index);
18174             }
18175             this.fireEvent("rowselect", this, index, r);
18176             this.fireEvent("selectionchange", this);
18177         }
18178     },
18179
18180     /**
18181      * Deselects a row.
18182      * @param {Number} row The index of the row to deselect
18183      */
18184     deselectRow : function(index, preventViewNotify){
18185         if(this.locked) return;
18186         if(this.last == index){
18187             this.last = false;
18188         }
18189         if(this.lastActive == index){
18190             this.lastActive = false;
18191         }
18192         var r = this.grid.dataSource.getAt(index);
18193         this.selections.remove(r);
18194         if(!preventViewNotify){
18195             this.grid.getView().onRowDeselect(index);
18196         }
18197         this.fireEvent("rowdeselect", this, index);
18198         this.fireEvent("selectionchange", this);
18199     },
18200
18201     // private
18202     restoreLast : function(){
18203         if(this._last){
18204             this.last = this._last;
18205         }
18206     },
18207
18208     // private
18209     acceptsNav : function(row, col, cm){
18210         return !cm.isHidden(col) && cm.isCellEditable(col, row);
18211     },
18212
18213     // private
18214     onEditorKey : function(field, e){
18215         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
18216         if(k == e.TAB){
18217             e.stopEvent();
18218             ed.completeEdit();
18219             if(e.shiftKey){
18220                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
18221             }else{
18222                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
18223             }
18224         }else if(k == e.ENTER && !e.ctrlKey){
18225             e.stopEvent();
18226             ed.completeEdit();
18227             if(e.shiftKey){
18228                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
18229             }else{
18230                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
18231             }
18232         }else if(k == e.ESC){
18233             ed.cancelEdit();
18234         }
18235         if(newCell){
18236             g.startEditing(newCell[0], newCell[1]);
18237         }
18238     }
18239 });/*
18240  * Based on:
18241  * Ext JS Library 1.1.1
18242  * Copyright(c) 2006-2007, Ext JS, LLC.
18243  *
18244  * Originally Released Under LGPL - original licence link has changed is not relivant.
18245  *
18246  * Fork - LGPL
18247  * <script type="text/javascript">
18248  */
18249  
18250 /**
18251  * @class Roo.bootstrap.PagingToolbar
18252  * @extends Roo.Row
18253  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
18254  * @constructor
18255  * Create a new PagingToolbar
18256  * @param {Object} config The config object
18257  */
18258 Roo.bootstrap.PagingToolbar = function(config)
18259 {
18260     // old args format still supported... - xtype is prefered..
18261         // created from xtype...
18262     var ds = config.dataSource;
18263     this.toolbarItems = [];
18264     if (config.items) {
18265         this.toolbarItems = config.items;
18266 //        config.items = [];
18267     }
18268     
18269     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
18270     this.ds = ds;
18271     this.cursor = 0;
18272     if (ds) { 
18273         this.bind(ds);
18274     }
18275     
18276     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
18277     
18278 };
18279
18280 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
18281     /**
18282      * @cfg {Roo.data.Store} dataSource
18283      * The underlying data store providing the paged data
18284      */
18285     /**
18286      * @cfg {String/HTMLElement/Element} container
18287      * container The id or element that will contain the toolbar
18288      */
18289     /**
18290      * @cfg {Boolean} displayInfo
18291      * True to display the displayMsg (defaults to false)
18292      */
18293     /**
18294      * @cfg {Number} pageSize
18295      * The number of records to display per page (defaults to 20)
18296      */
18297     pageSize: 20,
18298     /**
18299      * @cfg {String} displayMsg
18300      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
18301      */
18302     displayMsg : 'Displaying {0} - {1} of {2}',
18303     /**
18304      * @cfg {String} emptyMsg
18305      * The message to display when no records are found (defaults to "No data to display")
18306      */
18307     emptyMsg : 'No data to display',
18308     /**
18309      * Customizable piece of the default paging text (defaults to "Page")
18310      * @type String
18311      */
18312     beforePageText : "Page",
18313     /**
18314      * Customizable piece of the default paging text (defaults to "of %0")
18315      * @type String
18316      */
18317     afterPageText : "of {0}",
18318     /**
18319      * Customizable piece of the default paging text (defaults to "First Page")
18320      * @type String
18321      */
18322     firstText : "First Page",
18323     /**
18324      * Customizable piece of the default paging text (defaults to "Previous Page")
18325      * @type String
18326      */
18327     prevText : "Previous Page",
18328     /**
18329      * Customizable piece of the default paging text (defaults to "Next Page")
18330      * @type String
18331      */
18332     nextText : "Next Page",
18333     /**
18334      * Customizable piece of the default paging text (defaults to "Last Page")
18335      * @type String
18336      */
18337     lastText : "Last Page",
18338     /**
18339      * Customizable piece of the default paging text (defaults to "Refresh")
18340      * @type String
18341      */
18342     refreshText : "Refresh",
18343
18344     buttons : false,
18345     // private
18346     onRender : function(ct, position) 
18347     {
18348         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
18349         this.navgroup.parentId = this.id;
18350         this.navgroup.onRender(this.el, null);
18351         // add the buttons to the navgroup
18352         
18353         if(this.displayInfo){
18354             Roo.log(this.el.select('ul.navbar-nav',true).first());
18355             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
18356             this.displayEl = this.el.select('.x-paging-info', true).first();
18357 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
18358 //            this.displayEl = navel.el.select('span',true).first();
18359         }
18360         
18361         var _this = this;
18362         
18363         if(this.buttons){
18364             Roo.each(_this.buttons, function(e){
18365                Roo.factory(e).onRender(_this.el, null);
18366             });
18367         }
18368             
18369         Roo.each(_this.toolbarItems, function(e) {
18370             _this.navgroup.addItem(e);
18371         });
18372         
18373         this.first = this.navgroup.addItem({
18374             tooltip: this.firstText,
18375             cls: "prev",
18376             icon : 'fa fa-backward',
18377             disabled: true,
18378             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
18379         });
18380         
18381         this.prev =  this.navgroup.addItem({
18382             tooltip: this.prevText,
18383             cls: "prev",
18384             icon : 'fa fa-step-backward',
18385             disabled: true,
18386             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
18387         });
18388     //this.addSeparator();
18389         
18390         
18391         var field = this.navgroup.addItem( {
18392             tagtype : 'span',
18393             cls : 'x-paging-position',
18394             
18395             html : this.beforePageText  +
18396                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
18397                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
18398          } ); //?? escaped?
18399         
18400         this.field = field.el.select('input', true).first();
18401         this.field.on("keydown", this.onPagingKeydown, this);
18402         this.field.on("focus", function(){this.dom.select();});
18403     
18404     
18405         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
18406         //this.field.setHeight(18);
18407         //this.addSeparator();
18408         this.next = this.navgroup.addItem({
18409             tooltip: this.nextText,
18410             cls: "next",
18411             html : ' <i class="fa fa-step-forward">',
18412             disabled: true,
18413             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
18414         });
18415         this.last = this.navgroup.addItem({
18416             tooltip: this.lastText,
18417             icon : 'fa fa-forward',
18418             cls: "next",
18419             disabled: true,
18420             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
18421         });
18422     //this.addSeparator();
18423         this.loading = this.navgroup.addItem({
18424             tooltip: this.refreshText,
18425             icon: 'fa fa-refresh',
18426             
18427             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
18428         });
18429
18430     },
18431
18432     // private
18433     updateInfo : function(){
18434         if(this.displayEl){
18435             var count = this.ds.getCount();
18436             var msg = count == 0 ?
18437                 this.emptyMsg :
18438                 String.format(
18439                     this.displayMsg,
18440                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
18441                 );
18442             this.displayEl.update(msg);
18443         }
18444     },
18445
18446     // private
18447     onLoad : function(ds, r, o){
18448        this.cursor = o.params ? o.params.start : 0;
18449        var d = this.getPageData(),
18450             ap = d.activePage,
18451             ps = d.pages;
18452         
18453        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
18454        this.field.dom.value = ap;
18455        this.first.setDisabled(ap == 1);
18456        this.prev.setDisabled(ap == 1);
18457        this.next.setDisabled(ap == ps);
18458        this.last.setDisabled(ap == ps);
18459        this.loading.enable();
18460        this.updateInfo();
18461     },
18462
18463     // private
18464     getPageData : function(){
18465         var total = this.ds.getTotalCount();
18466         return {
18467             total : total,
18468             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
18469             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
18470         };
18471     },
18472
18473     // private
18474     onLoadError : function(){
18475         this.loading.enable();
18476     },
18477
18478     // private
18479     onPagingKeydown : function(e){
18480         var k = e.getKey();
18481         var d = this.getPageData();
18482         if(k == e.RETURN){
18483             var v = this.field.dom.value, pageNum;
18484             if(!v || isNaN(pageNum = parseInt(v, 10))){
18485                 this.field.dom.value = d.activePage;
18486                 return;
18487             }
18488             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
18489             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18490             e.stopEvent();
18491         }
18492         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))
18493         {
18494           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
18495           this.field.dom.value = pageNum;
18496           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
18497           e.stopEvent();
18498         }
18499         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18500         {
18501           var v = this.field.dom.value, pageNum; 
18502           var increment = (e.shiftKey) ? 10 : 1;
18503           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
18504             increment *= -1;
18505           if(!v || isNaN(pageNum = parseInt(v, 10))) {
18506             this.field.dom.value = d.activePage;
18507             return;
18508           }
18509           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
18510           {
18511             this.field.dom.value = parseInt(v, 10) + increment;
18512             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
18513             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
18514           }
18515           e.stopEvent();
18516         }
18517     },
18518
18519     // private
18520     beforeLoad : function(){
18521         if(this.loading){
18522             this.loading.disable();
18523         }
18524     },
18525
18526     // private
18527     onClick : function(which){
18528         var ds = this.ds;
18529         if (!ds) {
18530             return;
18531         }
18532         switch(which){
18533             case "first":
18534                 ds.load({params:{start: 0, limit: this.pageSize}});
18535             break;
18536             case "prev":
18537                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
18538             break;
18539             case "next":
18540                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
18541             break;
18542             case "last":
18543                 var total = ds.getTotalCount();
18544                 var extra = total % this.pageSize;
18545                 var lastStart = extra ? (total - extra) : total-this.pageSize;
18546                 ds.load({params:{start: lastStart, limit: this.pageSize}});
18547             break;
18548             case "refresh":
18549                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
18550             break;
18551         }
18552     },
18553
18554     /**
18555      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
18556      * @param {Roo.data.Store} store The data store to unbind
18557      */
18558     unbind : function(ds){
18559         ds.un("beforeload", this.beforeLoad, this);
18560         ds.un("load", this.onLoad, this);
18561         ds.un("loadexception", this.onLoadError, this);
18562         ds.un("remove", this.updateInfo, this);
18563         ds.un("add", this.updateInfo, this);
18564         this.ds = undefined;
18565     },
18566
18567     /**
18568      * Binds the paging toolbar to the specified {@link Roo.data.Store}
18569      * @param {Roo.data.Store} store The data store to bind
18570      */
18571     bind : function(ds){
18572         ds.on("beforeload", this.beforeLoad, this);
18573         ds.on("load", this.onLoad, this);
18574         ds.on("loadexception", this.onLoadError, this);
18575         ds.on("remove", this.updateInfo, this);
18576         ds.on("add", this.updateInfo, this);
18577         this.ds = ds;
18578     }
18579 });/*
18580  * - LGPL
18581  *
18582  * element
18583  * 
18584  */
18585
18586 /**
18587  * @class Roo.bootstrap.MessageBar
18588  * @extends Roo.bootstrap.Component
18589  * Bootstrap MessageBar class
18590  * @cfg {String} html contents of the MessageBar
18591  * @cfg {String} weight (info | success | warning | danger) default info
18592  * @cfg {String} beforeClass insert the bar before the given class
18593  * @cfg {Boolean} closable (true | false) default false
18594  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18595  * 
18596  * @constructor
18597  * Create a new Element
18598  * @param {Object} config The config object
18599  */
18600
18601 Roo.bootstrap.MessageBar = function(config){
18602     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18603 };
18604
18605 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
18606     
18607     html: '',
18608     weight: 'info',
18609     closable: false,
18610     fixed: false,
18611     beforeClass: 'bootstrap-sticky-wrap',
18612     
18613     getAutoCreate : function(){
18614         
18615         var cfg = {
18616             tag: 'div',
18617             cls: 'alert alert-dismissable alert-' + this.weight,
18618             cn: [
18619                 {
18620                     tag: 'span',
18621                     cls: 'message',
18622                     html: this.html || ''
18623                 }
18624             ]
18625         }
18626         
18627         if(this.fixed){
18628             cfg.cls += ' alert-messages-fixed';
18629         }
18630         
18631         if(this.closable){
18632             cfg.cn.push({
18633                 tag: 'button',
18634                 cls: 'close',
18635                 html: 'x'
18636             });
18637         }
18638         
18639         return cfg;
18640     },
18641     
18642     onRender : function(ct, position)
18643     {
18644         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18645         
18646         if(!this.el){
18647             var cfg = Roo.apply({},  this.getAutoCreate());
18648             cfg.id = Roo.id();
18649             
18650             if (this.cls) {
18651                 cfg.cls += ' ' + this.cls;
18652             }
18653             if (this.style) {
18654                 cfg.style = this.style;
18655             }
18656             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18657             
18658             this.el.setVisibilityMode(Roo.Element.DISPLAY);
18659         }
18660         
18661         this.el.select('>button.close').on('click', this.hide, this);
18662         
18663     },
18664     
18665     show : function()
18666     {
18667         if (!this.rendered) {
18668             this.render();
18669         }
18670         
18671         this.el.show();
18672         
18673         this.fireEvent('show', this);
18674         
18675     },
18676     
18677     hide : function()
18678     {
18679         if (!this.rendered) {
18680             this.render();
18681         }
18682         
18683         this.el.hide();
18684         
18685         this.fireEvent('hide', this);
18686     },
18687     
18688     update : function()
18689     {
18690 //        var e = this.el.dom.firstChild;
18691 //        
18692 //        if(this.closable){
18693 //            e = e.nextSibling;
18694 //        }
18695 //        
18696 //        e.data = this.html || '';
18697
18698         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18699     }
18700    
18701 });
18702
18703  
18704
18705      /*
18706  * - LGPL
18707  *
18708  * Graph
18709  * 
18710  */
18711
18712
18713 /**
18714  * @class Roo.bootstrap.Graph
18715  * @extends Roo.bootstrap.Component
18716  * Bootstrap Graph class
18717 > Prameters
18718  -sm {number} sm 4
18719  -md {number} md 5
18720  @cfg {String} graphtype  bar | vbar | pie
18721  @cfg {number} g_x coodinator | centre x (pie)
18722  @cfg {number} g_y coodinator | centre y (pie)
18723  @cfg {number} g_r radius (pie)
18724  @cfg {number} g_height height of the chart (respected by all elements in the set)
18725  @cfg {number} g_width width of the chart (respected by all elements in the set)
18726  @cfg {Object} title The title of the chart
18727     
18728  -{Array}  values
18729  -opts (object) options for the chart 
18730      o {
18731      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18732      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18733      o vgutter (number)
18734      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.
18735      o stacked (boolean) whether or not to tread values as in a stacked bar chart
18736      o to
18737      o stretch (boolean)
18738      o }
18739  -opts (object) options for the pie
18740      o{
18741      o cut
18742      o startAngle (number)
18743      o endAngle (number)
18744      } 
18745  *
18746  * @constructor
18747  * Create a new Input
18748  * @param {Object} config The config object
18749  */
18750
18751 Roo.bootstrap.Graph = function(config){
18752     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18753     
18754     this.addEvents({
18755         // img events
18756         /**
18757          * @event click
18758          * The img click event for the img.
18759          * @param {Roo.EventObject} e
18760          */
18761         "click" : true
18762     });
18763 };
18764
18765 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
18766     
18767     sm: 4,
18768     md: 5,
18769     graphtype: 'bar',
18770     g_height: 250,
18771     g_width: 400,
18772     g_x: 50,
18773     g_y: 50,
18774     g_r: 30,
18775     opts:{
18776         //g_colors: this.colors,
18777         g_type: 'soft',
18778         g_gutter: '20%'
18779
18780     },
18781     title : false,
18782
18783     getAutoCreate : function(){
18784         
18785         var cfg = {
18786             tag: 'div',
18787             html : null
18788         }
18789         
18790         
18791         return  cfg;
18792     },
18793
18794     onRender : function(ct,position){
18795         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18796         this.raphael = Raphael(this.el.dom);
18797         
18798                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18799                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18800                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18801                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18802                 /*
18803                 r.text(160, 10, "Single Series Chart").attr(txtattr);
18804                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18805                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18806                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18807                 
18808                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18809                 r.barchart(330, 10, 300, 220, data1);
18810                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18811                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18812                 */
18813                 
18814                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18815                 // r.barchart(30, 30, 560, 250,  xdata, {
18816                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18817                 //     axis : "0 0 1 1",
18818                 //     axisxlabels :  xdata
18819                 //     //yvalues : cols,
18820                    
18821                 // });
18822 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18823 //        
18824 //        this.load(null,xdata,{
18825 //                axis : "0 0 1 1",
18826 //                axisxlabels :  xdata
18827 //                });
18828
18829     },
18830
18831     load : function(graphtype,xdata,opts){
18832         this.raphael.clear();
18833         if(!graphtype) {
18834             graphtype = this.graphtype;
18835         }
18836         if(!opts){
18837             opts = this.opts;
18838         }
18839         var r = this.raphael,
18840             fin = function () {
18841                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18842             },
18843             fout = function () {
18844                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18845             },
18846             pfin = function() {
18847                 this.sector.stop();
18848                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
18849
18850                 if (this.label) {
18851                     this.label[0].stop();
18852                     this.label[0].attr({ r: 7.5 });
18853                     this.label[1].attr({ "font-weight": 800 });
18854                 }
18855             },
18856             pfout = function() {
18857                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
18858
18859                 if (this.label) {
18860                     this.label[0].animate({ r: 5 }, 500, "bounce");
18861                     this.label[1].attr({ "font-weight": 400 });
18862                 }
18863             };
18864
18865         switch(graphtype){
18866             case 'bar':
18867                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18868                 break;
18869             case 'hbar':
18870                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18871                 break;
18872             case 'pie':
18873 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
18874 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18875 //            
18876                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
18877                 
18878                 break;
18879
18880         }
18881         
18882         if(this.title){
18883             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18884         }
18885         
18886     },
18887     
18888     setTitle: function(o)
18889     {
18890         this.title = o;
18891     },
18892     
18893     initEvents: function() {
18894         
18895         if(!this.href){
18896             this.el.on('click', this.onClick, this);
18897         }
18898     },
18899     
18900     onClick : function(e)
18901     {
18902         Roo.log('img onclick');
18903         this.fireEvent('click', this, e);
18904     }
18905    
18906 });
18907
18908  
18909 /*
18910  * - LGPL
18911  *
18912  * numberBox
18913  * 
18914  */
18915 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18916
18917 /**
18918  * @class Roo.bootstrap.dash.NumberBox
18919  * @extends Roo.bootstrap.Component
18920  * Bootstrap NumberBox class
18921  * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18922  * @cfg {String} headline Box headline
18923  * @cfg {String} content Box content
18924  * @cfg {String} icon Box icon
18925  * @cfg {String} footer Footer text
18926  * @cfg {String} fhref Footer href
18927  * 
18928  * @constructor
18929  * Create a new NumberBox
18930  * @param {Object} config The config object
18931  */
18932
18933
18934 Roo.bootstrap.dash.NumberBox = function(config){
18935     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18936     
18937 };
18938
18939 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
18940     
18941     bgcolor : 'aqua',
18942     headline : '',
18943     content : '',
18944     icon : '',
18945     footer : '',
18946     fhref : '',
18947     ficon : '',
18948     
18949     getAutoCreate : function(){
18950         
18951         var cfg = {
18952             tag : 'div',
18953             cls : 'small-box bg-' + this.bgcolor,
18954             cn : [
18955                 {
18956                     tag : 'div',
18957                     cls : 'inner',
18958                     cn :[
18959                         {
18960                             tag : 'h3',
18961                             cls : 'roo-headline',
18962                             html : this.headline
18963                         },
18964                         {
18965                             tag : 'p',
18966                             cls : 'roo-content',
18967                             html : this.content
18968                         }
18969                     ]
18970                 }
18971             ]
18972         }
18973         
18974         if(this.icon){
18975             cfg.cn.push({
18976                 tag : 'div',
18977                 cls : 'icon',
18978                 cn :[
18979                     {
18980                         tag : 'i',
18981                         cls : 'ion ' + this.icon
18982                     }
18983                 ]
18984             });
18985         }
18986         
18987         if(this.footer){
18988             var footer = {
18989                 tag : 'a',
18990                 cls : 'small-box-footer',
18991                 href : this.fhref || '#',
18992                 html : this.footer
18993             };
18994             
18995             cfg.cn.push(footer);
18996             
18997         }
18998         
18999         return  cfg;
19000     },
19001
19002     onRender : function(ct,position){
19003         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
19004
19005
19006        
19007                 
19008     },
19009
19010     setHeadline: function (value)
19011     {
19012         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
19013     },
19014     
19015     setFooter: function (value, href)
19016     {
19017         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
19018         
19019         if(href){
19020             this.el.select('a.small-box-footer',true).first().attr('href', href);
19021         }
19022         
19023     },
19024
19025     setContent: function (value)
19026     {
19027         this.el.select('.roo-content',true).first().dom.innerHTML = value;
19028     },
19029
19030     initEvents: function() 
19031     {   
19032         
19033     }
19034     
19035 });
19036
19037  
19038 /*
19039  * - LGPL
19040  *
19041  * TabBox
19042  * 
19043  */
19044 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19045
19046 /**
19047  * @class Roo.bootstrap.dash.TabBox
19048  * @extends Roo.bootstrap.Component
19049  * Bootstrap TabBox class
19050  * @cfg {String} title Title of the TabBox
19051  * @cfg {String} icon Icon of the TabBox
19052  * 
19053  * @constructor
19054  * Create a new TabBox
19055  * @param {Object} config The config object
19056  */
19057
19058
19059 Roo.bootstrap.dash.TabBox = function(config){
19060     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
19061     
19062 };
19063
19064 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
19065
19066     title : '',
19067     icon : false,
19068     
19069     getChildContainer : function()
19070     {
19071         return this.el.select('.tab-content', true).first();
19072     },
19073     
19074     getAutoCreate : function(){
19075         
19076         var header = {
19077             tag: 'li',
19078             cls: 'pull-left header',
19079             html: this.title,
19080             cn : []
19081         };
19082         
19083         if(this.icon){
19084             header.cn.push({
19085                 tag: 'i',
19086                 cls: 'fa ' + this.icon
19087             });
19088         }
19089         
19090         
19091         var cfg = {
19092             tag: 'div',
19093             cls: 'nav-tabs-custom',
19094             cn: [
19095                 {
19096                     tag: 'ul',
19097                     cls: 'nav nav-tabs pull-right',
19098                     cn: [
19099                         header
19100                     ]
19101                 },
19102                 {
19103                     tag: 'div',
19104                     cls: 'tab-content no-padding',
19105                     cn: []
19106                 }
19107             ]
19108         }
19109
19110         return  cfg;
19111     },
19112     
19113     setTitle : function(value)
19114     {
19115         this.el.select('.header', true).first().dom.innerHTML = value;
19116     }
19117     
19118 });
19119
19120  
19121 /*
19122  * - LGPL
19123  *
19124  * Tab pane
19125  * 
19126  */
19127 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
19128 /**
19129  * @class Roo.bootstrap.TabPane
19130  * @extends Roo.bootstrap.Component
19131  * Bootstrap TabPane class
19132  * @cfg {Boolean} active (false | true) Default false
19133
19134  * 
19135  * @constructor
19136  * Create a new TabPane
19137  * @param {Object} config The config object
19138  */
19139
19140 Roo.bootstrap.dash.TabPane = function(config){
19141     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
19142     
19143 };
19144
19145 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
19146     
19147     active : false,
19148 //    
19149 //    getBox : function()
19150 //    {
19151 //        return this.el.findParent('.nav-tabs-custom', false, true);
19152 //    },
19153     
19154     getAutoCreate : function() 
19155     {
19156         var cfg = {
19157             tag: 'div',
19158             cls: 'tab-pane'
19159         }
19160         
19161         if(this.active){
19162             cfg.cls += ' active';
19163         }
19164         
19165         return cfg;
19166     }
19167     
19168     
19169 });
19170
19171  
19172
19173
19174  /*
19175  * - LGPL
19176  *
19177  * menu
19178  * 
19179  */
19180 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19181
19182 /**
19183  * @class Roo.bootstrap.menu.Menu
19184  * @extends Roo.bootstrap.Component
19185  * Bootstrap Menu class - container for Menu
19186  * @cfg {String} html Text of the menu
19187  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
19188  * @cfg {String} icon Font awesome icon
19189  * @cfg {String} pos Menu align to (top | bottom) default bottom
19190  * 
19191  * 
19192  * @constructor
19193  * Create a new Menu
19194  * @param {Object} config The config object
19195  */
19196
19197
19198 Roo.bootstrap.menu.Menu = function(config){
19199     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
19200     
19201     this.addEvents({
19202         /**
19203          * @event beforeshow
19204          * Fires before this menu is displayed
19205          * @param {Roo.bootstrap.menu.Menu} this
19206          */
19207         beforeshow : true,
19208         /**
19209          * @event beforehide
19210          * Fires before this menu is hidden
19211          * @param {Roo.bootstrap.menu.Menu} this
19212          */
19213         beforehide : true,
19214         /**
19215          * @event show
19216          * Fires after this menu is displayed
19217          * @param {Roo.bootstrap.menu.Menu} this
19218          */
19219         show : true,
19220         /**
19221          * @event hide
19222          * Fires after this menu is hidden
19223          * @param {Roo.bootstrap.menu.Menu} this
19224          */
19225         hide : true,
19226         /**
19227          * @event click
19228          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19229          * @param {Roo.bootstrap.menu.Menu} this
19230          * @param {Roo.EventObject} e
19231          */
19232         click : true
19233     });
19234     
19235 };
19236
19237 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
19238     
19239     submenu : false,
19240     html : '',
19241     weight : 'default',
19242     icon : false,
19243     pos : 'bottom',
19244     
19245     
19246     getChildContainer : function() {
19247         if(this.isSubMenu){
19248             return this.el;
19249         }
19250         
19251         return this.el.select('ul.dropdown-menu', true).first();  
19252     },
19253     
19254     getAutoCreate : function()
19255     {
19256         var text = [
19257             {
19258                 tag : 'span',
19259                 cls : 'roo-menu-text',
19260                 html : this.html
19261             }
19262         ];
19263         
19264         if(this.icon){
19265             text.unshift({
19266                 tag : 'i',
19267                 cls : 'fa ' + this.icon
19268             })
19269         }
19270         
19271         
19272         var cfg = {
19273             tag : 'div',
19274             cls : 'btn-group',
19275             cn : [
19276                 {
19277                     tag : 'button',
19278                     cls : 'dropdown-button btn btn-' + this.weight,
19279                     cn : text
19280                 },
19281                 {
19282                     tag : 'button',
19283                     cls : 'dropdown-toggle btn btn-' + this.weight,
19284                     cn : [
19285                         {
19286                             tag : 'span',
19287                             cls : 'caret'
19288                         }
19289                     ]
19290                 },
19291                 {
19292                     tag : 'ul',
19293                     cls : 'dropdown-menu'
19294                 }
19295             ]
19296             
19297         };
19298         
19299         if(this.pos == 'top'){
19300             cfg.cls += ' dropup';
19301         }
19302         
19303         if(this.isSubMenu){
19304             cfg = {
19305                 tag : 'ul',
19306                 cls : 'dropdown-menu'
19307             }
19308         }
19309         
19310         return cfg;
19311     },
19312     
19313     onRender : function(ct, position)
19314     {
19315         this.isSubMenu = ct.hasClass('dropdown-submenu');
19316         
19317         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
19318     },
19319     
19320     initEvents : function() 
19321     {
19322         if(this.isSubMenu){
19323             return;
19324         }
19325         
19326         this.hidden = true;
19327         
19328         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
19329         this.triggerEl.on('click', this.onTriggerPress, this);
19330         
19331         this.buttonEl = this.el.select('button.dropdown-button', true).first();
19332         this.buttonEl.on('click', this.onClick, this);
19333         
19334     },
19335     
19336     list : function()
19337     {
19338         if(this.isSubMenu){
19339             return this.el;
19340         }
19341         
19342         return this.el.select('ul.dropdown-menu', true).first();
19343     },
19344     
19345     onClick : function(e)
19346     {
19347         this.fireEvent("click", this, e);
19348     },
19349     
19350     onTriggerPress  : function(e)
19351     {   
19352         if (this.isVisible()) {
19353             this.hide();
19354         } else {
19355             this.show();
19356         }
19357     },
19358     
19359     isVisible : function(){
19360         return !this.hidden;
19361     },
19362     
19363     show : function()
19364     {
19365         this.fireEvent("beforeshow", this);
19366         
19367         this.hidden = false;
19368         this.el.addClass('open');
19369         
19370         Roo.get(document).on("mouseup", this.onMouseUp, this);
19371         
19372         this.fireEvent("show", this);
19373         
19374         
19375     },
19376     
19377     hide : function()
19378     {
19379         this.fireEvent("beforehide", this);
19380         
19381         this.hidden = true;
19382         this.el.removeClass('open');
19383         
19384         Roo.get(document).un("mouseup", this.onMouseUp);
19385         
19386         this.fireEvent("hide", this);
19387     },
19388     
19389     onMouseUp : function()
19390     {
19391         this.hide();
19392     }
19393     
19394 });
19395
19396  
19397  /*
19398  * - LGPL
19399  *
19400  * menu item
19401  * 
19402  */
19403 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19404
19405 /**
19406  * @class Roo.bootstrap.menu.Item
19407  * @extends Roo.bootstrap.Component
19408  * Bootstrap MenuItem class
19409  * @cfg {Boolean} submenu (true | false) default false
19410  * @cfg {String} html text of the item
19411  * @cfg {String} href the link
19412  * @cfg {Boolean} disable (true | false) default false
19413  * @cfg {Boolean} preventDefault (true | false) default true
19414  * @cfg {String} icon Font awesome icon
19415  * @cfg {String} pos Submenu align to (left | right) default right 
19416  * 
19417  * 
19418  * @constructor
19419  * Create a new Item
19420  * @param {Object} config The config object
19421  */
19422
19423
19424 Roo.bootstrap.menu.Item = function(config){
19425     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
19426     this.addEvents({
19427         /**
19428          * @event mouseover
19429          * Fires when the mouse is hovering over this menu
19430          * @param {Roo.bootstrap.menu.Item} this
19431          * @param {Roo.EventObject} e
19432          */
19433         mouseover : true,
19434         /**
19435          * @event mouseout
19436          * Fires when the mouse exits this menu
19437          * @param {Roo.bootstrap.menu.Item} this
19438          * @param {Roo.EventObject} e
19439          */
19440         mouseout : true,
19441         // raw events
19442         /**
19443          * @event click
19444          * The raw click event for the entire grid.
19445          * @param {Roo.EventObject} e
19446          */
19447         click : true
19448     });
19449 };
19450
19451 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
19452     
19453     submenu : false,
19454     href : '',
19455     html : '',
19456     preventDefault: true,
19457     disable : false,
19458     icon : false,
19459     pos : 'right',
19460     
19461     getAutoCreate : function()
19462     {
19463         var text = [
19464             {
19465                 tag : 'span',
19466                 cls : 'roo-menu-item-text',
19467                 html : this.html
19468             }
19469         ];
19470         
19471         if(this.icon){
19472             text.unshift({
19473                 tag : 'i',
19474                 cls : 'fa ' + this.icon
19475             })
19476         }
19477         
19478         var cfg = {
19479             tag : 'li',
19480             cn : [
19481                 {
19482                     tag : 'a',
19483                     href : this.href || '#',
19484                     cn : text
19485                 }
19486             ]
19487         };
19488         
19489         if(this.disable){
19490             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
19491         }
19492         
19493         if(this.submenu){
19494             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
19495             
19496             if(this.pos == 'left'){
19497                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
19498             }
19499         }
19500         
19501         return cfg;
19502     },
19503     
19504     initEvents : function() 
19505     {
19506         this.el.on('mouseover', this.onMouseOver, this);
19507         this.el.on('mouseout', this.onMouseOut, this);
19508         
19509         this.el.select('a', true).first().on('click', this.onClick, this);
19510         
19511     },
19512     
19513     onClick : function(e)
19514     {
19515         if(this.preventDefault){
19516             e.preventDefault();
19517         }
19518         
19519         this.fireEvent("click", this, e);
19520     },
19521     
19522     onMouseOver : function(e)
19523     {
19524         if(this.submenu && this.pos == 'left'){
19525             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
19526         }
19527         
19528         this.fireEvent("mouseover", this, e);
19529     },
19530     
19531     onMouseOut : function(e)
19532     {
19533         this.fireEvent("mouseout", this, e);
19534     }
19535 });
19536
19537  
19538
19539  /*
19540  * - LGPL
19541  *
19542  * menu separator
19543  * 
19544  */
19545 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
19546
19547 /**
19548  * @class Roo.bootstrap.menu.Separator
19549  * @extends Roo.bootstrap.Component
19550  * Bootstrap Separator class
19551  * 
19552  * @constructor
19553  * Create a new Separator
19554  * @param {Object} config The config object
19555  */
19556
19557
19558 Roo.bootstrap.menu.Separator = function(config){
19559     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
19560 };
19561
19562 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
19563     
19564     getAutoCreate : function(){
19565         var cfg = {
19566             tag : 'li',
19567             cls: 'divider'
19568         };
19569         
19570         return cfg;
19571     }
19572    
19573 });
19574
19575  
19576
19577