Roo/bootstrap/CheckBox.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 };
32
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
34     
35     
36     allowDomMove : false, // to stop relocations in parent onRender...
37     
38     cls : false,
39     
40     style : false,
41     
42     autoCreate : false,
43     
44     tooltip : null,
45     /**
46      * Initialize Events for the element
47      */
48     initEvents : function() { },
49     
50     xattr : false,
51     
52     parentId : false,
53     
54     can_build_overlaid : true,
55     
56     container_method : false,
57     
58     dataId : false,
59     
60     name : false,
61     
62     parent: function() {
63         // returns the parent component..
64         return Roo.ComponentMgr.get(this.parentId)
65         
66         
67     },
68     
69     // private
70     onRender : function(ct, position)
71     {
72        // Roo.log("Call onRender: " + this.xtype);
73         
74         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
75         
76         if(this.el){
77             if (this.el.attr('xtype')) {
78                 this.el.attr('xtypex', this.el.attr('xtype'));
79                 this.el.dom.removeAttribute('xtype');
80                 
81                 this.initEvents();
82             }
83             
84             return;
85         }
86         
87          
88         
89         var cfg = Roo.apply({},  this.getAutoCreate());
90         cfg.id = Roo.id();
91         
92         // fill in the extra attributes 
93         if (this.xattr && typeof(this.xattr) =='object') {
94             for (var i in this.xattr) {
95                 cfg[i] = this.xattr[i];
96             }
97         }
98         
99         if(this.dataId){
100             cfg.dataId = this.dataId;
101         }
102         
103         if (this.cls) {
104             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
105         }
106         
107         if (this.style) { // fixme needs to support more complex style data.
108             cfg.style = this.style;
109         }
110         
111         if(this.name){
112             cfg.name = this.name;
113         }
114         
115        
116         
117         this.el = ct.createChild(cfg, position);
118         
119         if (this.tooltip) {
120             this.tooltipEl().attr('tooltip', this.tooltip);
121         }
122         
123         if(this.tabIndex !== undefined){
124             this.el.dom.setAttribute('tabIndex', this.tabIndex);
125         }
126         this.initEvents();
127         
128         
129     },
130     /**
131      * Fetch the element to add children to
132      * @return {Roo.Element} defaults to this.el
133      */
134     getChildContainer : function()
135     {
136         return this.el;
137     },
138     /**
139      * Fetch the element to display the tooltip on.
140      * @return {Roo.Element} defaults to this.el
141      */
142     tooltipEl : function()
143     {
144         return this.el;
145     },
146         
147     addxtype  : function(tree,cntr)
148     {
149         var cn = this;
150         
151         cn = Roo.factory(tree);
152            
153         cn.parentType = this.xtype; //??
154         cn.parentId = this.id;
155         
156         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157         if (typeof(cn.container_method) == 'string') {
158             cntr = cn.container_method;
159         }
160         
161         
162         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
163         
164         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
165         
166         var build_from_html =  Roo.XComponent.build_from_html;
167           
168         var is_body  = (tree.xtype == 'Body') ;
169           
170         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
171           
172         var self_cntr_el = Roo.get(this[cntr](false));
173         
174         // do not try and build conditional elements 
175         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
176             return false;
177         }
178         
179         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181                 return this.addxtypeChild(tree,cntr);
182             }
183             
184             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
185                 
186             if(echild){
187                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
188             }
189             
190             Roo.log('skipping render');
191             return cn;
192             
193         }
194         
195         var ret = false;
196         
197         while (true) {
198             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
199             
200             if (!echild) {
201                 break;
202             }
203             
204             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
205                 break;
206             }
207             
208             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
209         }
210         return ret;
211     },
212     
213     addxtypeChild : function (tree, cntr)
214     {
215         Roo.debug && Roo.log('addxtypeChild:' + cntr);
216         var cn = this;
217         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
218         
219         
220         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221                     (typeof(tree['flexy:foreach']) != 'undefined');
222           
223         
224         
225          skip_children = false;
226         // render the element if it's not BODY.
227         if (tree.xtype != 'Body') {
228            
229             cn = Roo.factory(tree);
230            
231             cn.parentType = this.xtype; //??
232             cn.parentId = this.id;
233             
234             var build_from_html =  Roo.XComponent.build_from_html;
235             
236             
237             // does the container contain child eleemnts with 'xtype' attributes.
238             // that match this xtype..
239             // note - when we render we create these as well..
240             // so we should check to see if body has xtype set.
241             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
242                
243                 var self_cntr_el = Roo.get(this[cntr](false));
244                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
245                 
246                 
247                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248                 // and are not displayed -this causes this to use up the wrong element when matching.
249                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
250                 
251                 
252                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
254                   
255                   
256                   
257                     cn.el = echild;
258                   //  Roo.log("GOT");
259                     //echild.dom.removeAttribute('xtype');
260                 } else {
261                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262                     Roo.debug && Roo.log(self_cntr_el);
263                     Roo.debug && Roo.log(echild);
264                     Roo.debug && Roo.log(cn);
265                 }
266             }
267            
268             
269            
270             // if object has flexy:if - then it may or may not be rendered.
271             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
272                 // skip a flexy if element.
273                 Roo.debug && Roo.log('skipping render');
274                 Roo.debug && Roo.log(tree);
275                 if (!cn.el) {
276                     Roo.debug && Roo.log('skipping all children');
277                     skip_children = true;
278                 }
279                 
280              } else {
281                  
282                 // actually if flexy:foreach is found, we really want to create 
283                 // multiple copies here...
284                 //Roo.log('render');
285                 //Roo.log(this[cntr]());
286                 cn.render(this[cntr](true));
287              }
288             // then add the element..
289         }
290         
291         
292         // handle the kids..
293         
294         var nitems = [];
295         /*
296         if (typeof (tree.menu) != 'undefined') {
297             tree.menu.parentType = cn.xtype;
298             tree.menu.triggerEl = cn.el;
299             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
300             
301         }
302         */
303         if (!tree.items || !tree.items.length) {
304             cn.items = nitems;
305             return cn;
306         }
307         var items = tree.items;
308         delete tree.items;
309         
310         //Roo.log(items.length);
311             // add the items..
312         if (!skip_children) {    
313             for(var i =0;i < items.length;i++) {
314                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
315             }
316         }
317         
318         cn.items = nitems;
319         
320         return cn;
321     }
322     
323     
324     
325     
326 });
327
328  /*
329  * - LGPL
330  *
331  * Body
332  * 
333  */
334
335 /**
336  * @class Roo.bootstrap.Body
337  * @extends Roo.bootstrap.Component
338  * Bootstrap Body class
339  * 
340  * @constructor
341  * Create a new body
342  * @param {Object} config The config object
343  */
344
345 Roo.bootstrap.Body = function(config){
346     Roo.bootstrap.Body.superclass.constructor.call(this, config);
347     this.el = Roo.get(document.body);
348     if (this.cls && this.cls.length) {
349         Roo.get(document.body).addClass(this.cls);
350     }
351 };
352
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
354       
355         autoCreate : {
356         cls: 'container'
357     },
358     onRender : function(ct, position)
359     {
360        /* Roo.log("Roo.bootstrap.Body - onRender");
361         if (this.cls && this.cls.length) {
362             Roo.get(document.body).addClass(this.cls);
363         }
364         // style??? xttr???
365         */
366     }
367     
368     
369  
370    
371 });
372
373  /*
374  * - LGPL
375  *
376  * button group
377  * 
378  */
379
380
381 /**
382  * @class Roo.bootstrap.ButtonGroup
383  * @extends Roo.bootstrap.Component
384  * Bootstrap ButtonGroup class
385  * @cfg {String} size lg | sm | xs (default empty normal)
386  * @cfg {String} align vertical | justified  (default none)
387  * @cfg {String} direction up | down (default down)
388  * @cfg {Boolean} toolbar false | true
389  * @cfg {Boolean} btn true | false
390  * 
391  * 
392  * @constructor
393  * Create a new Input
394  * @param {Object} config The config object
395  */
396
397 Roo.bootstrap.ButtonGroup = function(config){
398     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
399 };
400
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
402     
403     size: '',
404     align: '',
405     direction: '',
406     toolbar: false,
407     btn: true,
408
409     getAutoCreate : function(){
410         var cfg = {
411             cls: 'btn-group',
412             html : null
413         }
414         
415         cfg.html = this.html || cfg.html;
416         
417         if (this.toolbar) {
418             cfg = {
419                 cls: 'btn-toolbar',
420                 html: null
421             }
422             
423             return cfg;
424         }
425         
426         if (['vertical','justified'].indexOf(this.align)!==-1) {
427             cfg.cls = 'btn-group-' + this.align;
428             
429             if (this.align == 'justified') {
430                 console.log(this.items);
431             }
432         }
433         
434         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435             cfg.cls += ' btn-group-' + this.size;
436         }
437         
438         if (this.direction == 'up') {
439             cfg.cls += ' dropup' ;
440         }
441         
442         return cfg;
443     }
444    
445 });
446
447  /*
448  * - LGPL
449  *
450  * button
451  * 
452  */
453
454 /**
455  * @class Roo.bootstrap.Button
456  * @extends Roo.bootstrap.Component
457  * Bootstrap Button class
458  * @cfg {String} html The button content
459  * @cfg {String} weight (  primary | success | info | warning | danger | link ) default 
460  * @cfg {String} size ( lg | sm | xs)
461  * @cfg {String} tag ( a | input | submit)
462  * @cfg {String} href empty or href
463  * @cfg {Boolean} disabled default false;
464  * @cfg {Boolean} isClose default false;
465  * @cfg {String} glyphicon (| 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)
466  * @cfg {String} badge text for badge
467  * @cfg {String} theme default 
468  * @cfg {Boolean} inverse 
469  * @cfg {Boolean} toggle 
470  * @cfg {String} ontext text for on toggle state
471  * @cfg {String} offtext text for off toggle state
472  * @cfg {Boolean} defaulton 
473  * @cfg {Boolean} preventDefault  default true
474  * @cfg {Boolean} removeClass remove the standard class..
475  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
476  * 
477  * @constructor
478  * Create a new button
479  * @param {Object} config The config object
480  */
481
482
483 Roo.bootstrap.Button = function(config){
484     Roo.bootstrap.Button.superclass.constructor.call(this, config);
485     this.addEvents({
486         // raw events
487         /**
488          * @event click
489          * When a butotn is pressed
490          * @param {Roo.EventObject} e
491          */
492         "click" : true,
493          /**
494          * @event toggle
495          * After the button has been toggles
496          * @param {Roo.EventObject} e
497          * @param {boolean} pressed (also available as button.pressed)
498          */
499         "toggle" : true
500     });
501 };
502
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
504     html: false,
505     active: false,
506     weight: '',
507     size: '',
508     tag: 'button',
509     href: '',
510     disabled: false,
511     isClose: false,
512     glyphicon: '',
513     badge: '',
514     theme: 'default',
515     inverse: false,
516     
517     toggle: false,
518     ontext: 'ON',
519     offtext: 'OFF',
520     defaulton: true,
521     preventDefault: true,
522     removeClass: false,
523     name: false,
524     target: false,
525     
526     
527     pressed : null,
528      
529     
530     getAutoCreate : function(){
531         
532         var cfg = {
533             tag : 'button',
534             cls : 'roo-button',
535             html: ''
536         };
537         
538         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
540             this.tag = 'button';
541         } else {
542             cfg.tag = this.tag;
543         }
544         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
545         
546         if (this.toggle == true) {
547             cfg={
548                 tag: 'div',
549                 cls: 'slider-frame roo-button',
550                 cn: [
551                     {
552                         tag: 'span',
553                         'data-on-text':'ON',
554                         'data-off-text':'OFF',
555                         cls: 'slider-button',
556                         html: this.offtext
557                     }
558                 ]
559             };
560             
561             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562                 cfg.cls += ' '+this.weight;
563             }
564             
565             return cfg;
566         }
567         
568         if (this.isClose) {
569             cfg.cls += ' close';
570             
571             cfg["aria-hidden"] = true;
572             
573             cfg.html = "&times;";
574             
575             return cfg;
576         }
577         
578          
579         if (this.theme==='default') {
580             cfg.cls = 'btn roo-button';
581             
582             //if (this.parentType != 'Navbar') {
583             this.weight = this.weight.length ?  this.weight : 'default';
584             //}
585             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
586                 
587                 cfg.cls += ' btn-' + this.weight;
588             }
589         } else if (this.theme==='glow') {
590             
591             cfg.tag = 'a';
592             cfg.cls = 'btn-glow roo-button';
593             
594             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
595                 
596                 cfg.cls += ' ' + this.weight;
597             }
598         }
599    
600         
601         if (this.inverse) {
602             this.cls += ' inverse';
603         }
604         
605         
606         if (this.active) {
607             cfg.cls += ' active';
608         }
609         
610         if (this.disabled) {
611             cfg.disabled = 'disabled';
612         }
613         
614         if (this.items) {
615             Roo.log('changing to ul' );
616             cfg.tag = 'ul';
617             this.glyphicon = 'caret';
618         }
619         
620         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
621          
622         //gsRoo.log(this.parentType);
623         if (this.parentType === 'Navbar' && !this.parent().bar) {
624             Roo.log('changing to li?');
625             
626             cfg.tag = 'li';
627             
628             cfg.cls = '';
629             cfg.cn =  [{
630                 tag : 'a',
631                 cls : 'roo-button',
632                 html : this.html,
633                 href : this.href || '#'
634             }];
635             if (this.menu) {
636                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
637                 cfg.cls += ' dropdown';
638             }   
639             
640             delete cfg.html;
641             
642         }
643         
644        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
645         
646         if (this.glyphicon) {
647             cfg.html = ' ' + cfg.html;
648             
649             cfg.cn = [
650                 {
651                     tag: 'span',
652                     cls: 'glyphicon glyphicon-' + this.glyphicon
653                 }
654             ];
655         }
656         
657         if (this.badge) {
658             cfg.html += ' ';
659             
660             cfg.tag = 'a';
661             
662 //            cfg.cls='btn roo-button';
663             
664             cfg.href=this.href;
665             
666             var value = cfg.html;
667             
668             if(this.glyphicon){
669                 value = {
670                             tag: 'span',
671                             cls: 'glyphicon glyphicon-' + this.glyphicon,
672                             html: this.html
673                         };
674                 
675             }
676             
677             cfg.cn = [
678                 value,
679                 {
680                     tag: 'span',
681                     cls: 'badge',
682                     html: this.badge
683                 }
684             ];
685             
686             cfg.html='';
687         }
688         
689         if (this.menu) {
690             cfg.cls += ' dropdown';
691             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
692         }
693         
694         if (cfg.tag !== 'a' && this.href !== '') {
695             throw "Tag must be a to set href.";
696         } else if (this.href.length > 0) {
697             cfg.href = this.href;
698         }
699         
700         if(this.removeClass){
701             cfg.cls = '';
702         }
703         
704         if(this.target){
705             cfg.target = this.target;
706         }
707         
708         return cfg;
709     },
710     initEvents: function() {
711        // Roo.log('init events?');
712 //        Roo.log(this.el.dom);
713         // add the menu...
714         
715         if (typeof (this.menu) != 'undefined') {
716             this.menu.parentType = this.xtype;
717             this.menu.triggerEl = this.el;
718             this.addxtype(Roo.apply({}, this.menu));
719         }
720
721
722        if (this.el.hasClass('roo-button')) {
723             this.el.on('click', this.onClick, this);
724        } else {
725             this.el.select('.roo-button').on('click', this.onClick, this);
726        }
727        
728        if(this.removeClass){
729            this.el.on('click', this.onClick, this);
730        }
731        
732        this.el.enableDisplayMode();
733         
734     },
735     onClick : function(e)
736     {
737         if (this.disabled) {
738             return;
739         }
740         
741         
742         Roo.log('button on click ');
743         if(this.preventDefault){
744             e.preventDefault();
745         }
746         if (this.pressed === true || this.pressed === false) {
747             this.pressed = !this.pressed;
748             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749             this.fireEvent('toggle', this, e, this.pressed);
750         }
751         
752         
753         this.fireEvent('click', this, e);
754     },
755     
756     /**
757      * Enables this button
758      */
759     enable : function()
760     {
761         this.disabled = false;
762         this.el.removeClass('disabled');
763     },
764     
765     /**
766      * Disable this button
767      */
768     disable : function()
769     {
770         this.disabled = true;
771         this.el.addClass('disabled');
772     },
773      /**
774      * sets the active state on/off, 
775      * @param {Boolean} state (optional) Force a particular state
776      */
777     setActive : function(v) {
778         
779         this.el[v ? 'addClass' : 'removeClass']('active');
780     },
781      /**
782      * toggles the current active state 
783      */
784     toggleActive : function()
785     {
786        var active = this.el.hasClass('active');
787        this.setActive(!active);
788        
789         
790     },
791     setText : function(str)
792     {
793         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
794     },
795     getText : function()
796     {
797         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
798     },
799     hide: function() {
800        
801      
802         this.el.hide();   
803     },
804     show: function() {
805        
806         this.el.show();   
807     }
808     
809     
810 });
811
812  /*
813  * - LGPL
814  *
815  * column
816  * 
817  */
818
819 /**
820  * @class Roo.bootstrap.Column
821  * @extends Roo.bootstrap.Component
822  * Bootstrap Column class
823  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
831  *
832  * 
833  * @cfg {Boolean} hidden (true|false) hide the element
834  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835  * @cfg {String} fa (ban|check|...) font awesome icon
836  * @cfg {Number} fasize (1|2|....) font awsome size
837
838  * @cfg {String} icon (info-sign|check|...) glyphicon name
839
840  * @cfg {String} html content of column.
841  * 
842  * @constructor
843  * Create a new Column
844  * @param {Object} config The config object
845  */
846
847 Roo.bootstrap.Column = function(config){
848     Roo.bootstrap.Column.superclass.constructor.call(this, config);
849 };
850
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
852     
853     xs: false,
854     sm: false,
855     md: false,
856     lg: false,
857     xsoff: false,
858     smoff: false,
859     mdoff: false,
860     lgoff: false,
861     html: '',
862     offset: 0,
863     alert: false,
864     fa: false,
865     icon : false,
866     hidden : false,
867     fasize : 1,
868     
869     getAutoCreate : function(){
870         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
871         
872         cfg = {
873             tag: 'div',
874             cls: 'column'
875         };
876         
877         var settings=this;
878         ['xs','sm','md','lg'].map(function(size){
879             //Roo.log( size + ':' + settings[size]);
880             
881             if (settings[size+'off'] !== false) {
882                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
883             }
884             
885             if (settings[size] === false) {
886                 return;
887             }
888             Roo.log(settings[size]);
889             if (!settings[size]) { // 0 = hidden
890                 cfg.cls += ' hidden-' + size;
891                 return;
892             }
893             cfg.cls += ' col-' + size + '-' + settings[size];
894             
895         });
896         
897         if (this.hidden) {
898             cfg.cls += ' hidden';
899         }
900         
901         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902             cfg.cls +=' alert alert-' + this.alert;
903         }
904         
905         
906         if (this.html.length) {
907             cfg.html = this.html;
908         }
909         if (this.fa) {
910             var fasize = '';
911             if (this.fasize > 1) {
912                 fasize = ' fa-' + this.fasize + 'x';
913             }
914             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
915             
916             
917         }
918         if (this.icon) {
919             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
920         }
921         
922         return cfg;
923     }
924    
925 });
926
927  
928
929  /*
930  * - LGPL
931  *
932  * page container.
933  * 
934  */
935
936
937 /**
938  * @class Roo.bootstrap.Container
939  * @extends Roo.bootstrap.Component
940  * Bootstrap Container class
941  * @cfg {Boolean} jumbotron is it a jumbotron element
942  * @cfg {String} html content of element
943  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945  * @cfg {String} header content of header (for panel)
946  * @cfg {String} footer content of footer (for panel)
947  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948  * @cfg {String} tag (header|aside|section) type of HTML tag.
949  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950  * @cfg {String} fa (ban|check|...) font awesome icon
951  * @cfg {String} icon (info-sign|check|...) glyphicon name
952  * @cfg {Boolean} hidden (true|false) hide the element
953
954  *     
955  * @constructor
956  * Create a new Container
957  * @param {Object} config The config object
958  */
959
960 Roo.bootstrap.Container = function(config){
961     Roo.bootstrap.Container.superclass.constructor.call(this, config);
962 };
963
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
965     
966     jumbotron : false,
967     well: '',
968     panel : '',
969     header: '',
970     footer : '',
971     sticky: '',
972     tag : false,
973     alert : false,
974     fa: false,
975     icon : false,
976   
977      
978     getChildContainer : function() {
979         
980         if(!this.el){
981             return false;
982         }
983         
984         if (this.panel.length) {
985             return this.el.select('.panel-body',true).first();
986         }
987         
988         return this.el;
989     },
990     
991     
992     getAutoCreate : function(){
993         
994         var cfg = {
995             tag : this.tag || 'div',
996             html : '',
997             cls : ''
998         };
999         if (this.jumbotron) {
1000             cfg.cls = 'jumbotron';
1001         }
1002         
1003         
1004         
1005         // - this is applied by the parent..
1006         //if (this.cls) {
1007         //    cfg.cls = this.cls + '';
1008         //}
1009         
1010         if (this.sticky.length) {
1011             
1012             var bd = Roo.get(document.body);
1013             if (!bd.hasClass('bootstrap-sticky')) {
1014                 bd.addClass('bootstrap-sticky');
1015                 Roo.select('html',true).setStyle('height', '100%');
1016             }
1017              
1018             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1019         }
1020         
1021         
1022         if (this.well.length) {
1023             switch (this.well) {
1024                 case 'lg':
1025                 case 'sm':
1026                     cfg.cls +=' well well-' +this.well;
1027                     break;
1028                 default:
1029                     cfg.cls +=' well';
1030                     break;
1031             }
1032         }
1033         
1034         if (this.hidden) {
1035             cfg.cls += ' hidden';
1036         }
1037         
1038         
1039         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040             cfg.cls +=' alert alert-' + this.alert;
1041         }
1042         
1043         var body = cfg;
1044         
1045         if (this.panel.length) {
1046             cfg.cls += ' panel panel-' + this.panel;
1047             cfg.cn = [];
1048             if (this.header.length) {
1049                 cfg.cn.push({
1050                     
1051                     cls : 'panel-heading',
1052                     cn : [{
1053                         tag: 'h3',
1054                         cls : 'panel-title',
1055                         html : this.header
1056                     }]
1057                     
1058                 });
1059             }
1060             body = false;
1061             cfg.cn.push({
1062                 cls : 'panel-body',
1063                 html : this.html
1064             });
1065             
1066             
1067             if (this.footer.length) {
1068                 cfg.cn.push({
1069                     cls : 'panel-footer',
1070                     html : this.footer
1071                     
1072                 });
1073             }
1074             
1075         }
1076         
1077         if (body) {
1078             body.html = this.html || cfg.html;
1079             // prefix with the icons..
1080             if (this.fa) {
1081                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1082             }
1083             if (this.icon) {
1084                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1085             }
1086             
1087             
1088         }
1089         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090             cfg.cls =  'container';
1091         }
1092         
1093         return cfg;
1094     },
1095     
1096     titleEl : function()
1097     {
1098         if(!this.el || !this.panel.length || !this.header.length){
1099             return;
1100         }
1101         
1102         return this.el.select('.panel-title',true).first();
1103     },
1104     
1105     setTitle : function(v)
1106     {
1107         var titleEl = this.titleEl();
1108         
1109         if(!titleEl){
1110             return;
1111         }
1112         
1113         titleEl.dom.innerHTML = v;
1114     },
1115     
1116     getTitle : function()
1117     {
1118         
1119         var titleEl = this.titleEl();
1120         
1121         if(!titleEl){
1122             return '';
1123         }
1124         
1125         return titleEl.dom.innerHTML;
1126     },
1127     
1128     show : function() {
1129         this.el.removeClass('hidden');
1130     },
1131     hide: function() {
1132         if (!this.el.hasClass('hidden')) {
1133             this.el.addClass('hidden');
1134         }
1135         
1136     }
1137    
1138 });
1139
1140  /*
1141  * - LGPL
1142  *
1143  * image
1144  * 
1145  */
1146
1147
1148 /**
1149  * @class Roo.bootstrap.Img
1150  * @extends Roo.bootstrap.Component
1151  * Bootstrap Img class
1152  * @cfg {Boolean} imgResponsive false | true
1153  * @cfg {String} border rounded | circle | thumbnail
1154  * @cfg {String} src image source
1155  * @cfg {String} alt image alternative text
1156  * @cfg {String} href a tag href
1157  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1158  * 
1159  * @constructor
1160  * Create a new Input
1161  * @param {Object} config The config object
1162  */
1163
1164 Roo.bootstrap.Img = function(config){
1165     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1166     
1167     this.addEvents({
1168         // img events
1169         /**
1170          * @event click
1171          * The img click event for the img.
1172          * @param {Roo.EventObject} e
1173          */
1174         "click" : true
1175     });
1176 };
1177
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1179     
1180     imgResponsive: true,
1181     border: '',
1182     src: '',
1183     href: false,
1184     target: false,
1185
1186     getAutoCreate : function(){
1187         
1188         var cfg = {
1189             tag: 'img',
1190             cls: (this.imgResponsive) ? 'img-responsive' : '',
1191             html : null
1192         }
1193         
1194         cfg.html = this.html || cfg.html;
1195         
1196         cfg.src = this.src || cfg.src;
1197         
1198         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199             cfg.cls += ' img-' + this.border;
1200         }
1201         
1202         if(this.alt){
1203             cfg.alt = this.alt;
1204         }
1205         
1206         if(this.href){
1207             var a = {
1208                 tag: 'a',
1209                 href: this.href,
1210                 cn: [
1211                     cfg
1212                 ]
1213             }
1214             
1215             if(this.target){
1216                 a.target = this.target;
1217             }
1218             
1219         }
1220         
1221         
1222         return (this.href) ? a : cfg;
1223     },
1224     
1225     initEvents: function() {
1226         
1227         if(!this.href){
1228             this.el.on('click', this.onClick, this);
1229         }
1230     },
1231     
1232     onClick : function(e)
1233     {
1234         Roo.log('img onclick');
1235         this.fireEvent('click', this, e);
1236     }
1237    
1238 });
1239
1240  /*
1241  * - LGPL
1242  *
1243  * image
1244  * 
1245  */
1246
1247
1248 /**
1249  * @class Roo.bootstrap.Link
1250  * @extends Roo.bootstrap.Component
1251  * Bootstrap Link Class
1252  * @cfg {String} alt image alternative text
1253  * @cfg {String} href a tag href
1254  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255  * @cfg {String} html the content of the link.
1256  * @cfg {String} anchor name for the anchor link
1257
1258  * @cfg {Boolean} preventDefault (true | false) default false
1259
1260  * 
1261  * @constructor
1262  * Create a new Input
1263  * @param {Object} config The config object
1264  */
1265
1266 Roo.bootstrap.Link = function(config){
1267     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1268     
1269     this.addEvents({
1270         // img events
1271         /**
1272          * @event click
1273          * The img click event for the img.
1274          * @param {Roo.EventObject} e
1275          */
1276         "click" : true
1277     });
1278 };
1279
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1281     
1282     href: false,
1283     target: false,
1284     preventDefault: false,
1285     anchor : false,
1286     alt : false,
1287
1288     getAutoCreate : function()
1289     {
1290         
1291         var cfg = {
1292             tag: 'a'
1293         };
1294         // anchor's do not require html/href...
1295         if (this.anchor === false) {
1296             cfg.html = this.html || 'html-missing';
1297             cfg.href = this.href || '#';
1298         } else {
1299             cfg.name = this.anchor;
1300             if (this.html !== false) {
1301                 cfg.html = this.html;
1302             }
1303             if (this.href !== false) {
1304                 cfg.href = this.href;
1305             }
1306         }
1307         
1308         if(this.alt !== false){
1309             cfg.alt = this.alt;
1310         }
1311         
1312         
1313         if(this.target !== false) {
1314             cfg.target = this.target;
1315         }
1316         
1317         return cfg;
1318     },
1319     
1320     initEvents: function() {
1321         
1322         if(!this.href || this.preventDefault){
1323             this.el.on('click', this.onClick, this);
1324         }
1325     },
1326     
1327     onClick : function(e)
1328     {
1329         if(this.preventDefault){
1330             e.preventDefault();
1331         }
1332         //Roo.log('img onclick');
1333         this.fireEvent('click', this, e);
1334     }
1335    
1336 });
1337
1338  /*
1339  * - LGPL
1340  *
1341  * header
1342  * 
1343  */
1344
1345 /**
1346  * @class Roo.bootstrap.Header
1347  * @extends Roo.bootstrap.Component
1348  * Bootstrap Header class
1349  * @cfg {String} html content of header
1350  * @cfg {Number} level (1|2|3|4|5|6) default 1
1351  * 
1352  * @constructor
1353  * Create a new Header
1354  * @param {Object} config The config object
1355  */
1356
1357
1358 Roo.bootstrap.Header  = function(config){
1359     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1360 };
1361
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1363     
1364     //href : false,
1365     html : false,
1366     level : 1,
1367     
1368     
1369     
1370     getAutoCreate : function(){
1371         
1372         var cfg = {
1373             tag: 'h' + (1 *this.level),
1374             html: this.html || 'fill in html'
1375         } ;
1376         
1377         return cfg;
1378     }
1379    
1380 });
1381
1382  
1383
1384  /*
1385  * Based on:
1386  * Ext JS Library 1.1.1
1387  * Copyright(c) 2006-2007, Ext JS, LLC.
1388  *
1389  * Originally Released Under LGPL - original licence link has changed is not relivant.
1390  *
1391  * Fork - LGPL
1392  * <script type="text/javascript">
1393  */
1394  
1395 /**
1396  * @class Roo.bootstrap.MenuMgr
1397  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1398  * @singleton
1399  */
1400 Roo.bootstrap.MenuMgr = function(){
1401    var menus, active, groups = {}, attached = false, lastShow = new Date();
1402
1403    // private - called when first menu is created
1404    function init(){
1405        menus = {};
1406        active = new Roo.util.MixedCollection();
1407        Roo.get(document).addKeyListener(27, function(){
1408            if(active.length > 0){
1409                hideAll();
1410            }
1411        });
1412    }
1413
1414    // private
1415    function hideAll(){
1416        if(active && active.length > 0){
1417            var c = active.clone();
1418            c.each(function(m){
1419                m.hide();
1420            });
1421        }
1422    }
1423
1424    // private
1425    function onHide(m){
1426        active.remove(m);
1427        if(active.length < 1){
1428            Roo.get(document).un("mouseup", onMouseDown);
1429             
1430            attached = false;
1431        }
1432    }
1433
1434    // private
1435    function onShow(m){
1436        var last = active.last();
1437        lastShow = new Date();
1438        active.add(m);
1439        if(!attached){
1440           Roo.get(document).on("mouseup", onMouseDown);
1441            
1442            attached = true;
1443        }
1444        if(m.parentMenu){
1445           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1446           m.parentMenu.activeChild = m;
1447        }else if(last && last.isVisible()){
1448           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1449        }
1450    }
1451
1452    // private
1453    function onBeforeHide(m){
1454        if(m.activeChild){
1455            m.activeChild.hide();
1456        }
1457        if(m.autoHideTimer){
1458            clearTimeout(m.autoHideTimer);
1459            delete m.autoHideTimer;
1460        }
1461    }
1462
1463    // private
1464    function onBeforeShow(m){
1465        var pm = m.parentMenu;
1466        if(!pm && !m.allowOtherMenus){
1467            hideAll();
1468        }else if(pm && pm.activeChild && active != m){
1469            pm.activeChild.hide();
1470        }
1471    }
1472
1473    // private
1474    function onMouseDown(e){
1475         Roo.log("on MouseDown");
1476         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1477            hideAll();
1478         }
1479         
1480         
1481    }
1482
1483    // private
1484    function onBeforeCheck(mi, state){
1485        if(state){
1486            var g = groups[mi.group];
1487            for(var i = 0, l = g.length; i < l; i++){
1488                if(g[i] != mi){
1489                    g[i].setChecked(false);
1490                }
1491            }
1492        }
1493    }
1494
1495    return {
1496
1497        /**
1498         * Hides all menus that are currently visible
1499         */
1500        hideAll : function(){
1501             hideAll();  
1502        },
1503
1504        // private
1505        register : function(menu){
1506            if(!menus){
1507                init();
1508            }
1509            menus[menu.id] = menu;
1510            menu.on("beforehide", onBeforeHide);
1511            menu.on("hide", onHide);
1512            menu.on("beforeshow", onBeforeShow);
1513            menu.on("show", onShow);
1514            var g = menu.group;
1515            if(g && menu.events["checkchange"]){
1516                if(!groups[g]){
1517                    groups[g] = [];
1518                }
1519                groups[g].push(menu);
1520                menu.on("checkchange", onCheck);
1521            }
1522        },
1523
1524         /**
1525          * Returns a {@link Roo.menu.Menu} object
1526          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1527          * be used to generate and return a new Menu instance.
1528          */
1529        get : function(menu){
1530            if(typeof menu == "string"){ // menu id
1531                return menus[menu];
1532            }else if(menu.events){  // menu instance
1533                return menu;
1534            }
1535            /*else if(typeof menu.length == 'number'){ // array of menu items?
1536                return new Roo.bootstrap.Menu({items:menu});
1537            }else{ // otherwise, must be a config
1538                return new Roo.bootstrap.Menu(menu);
1539            }
1540            */
1541            return false;
1542        },
1543
1544        // private
1545        unregister : function(menu){
1546            delete menus[menu.id];
1547            menu.un("beforehide", onBeforeHide);
1548            menu.un("hide", onHide);
1549            menu.un("beforeshow", onBeforeShow);
1550            menu.un("show", onShow);
1551            var g = menu.group;
1552            if(g && menu.events["checkchange"]){
1553                groups[g].remove(menu);
1554                menu.un("checkchange", onCheck);
1555            }
1556        },
1557
1558        // private
1559        registerCheckable : function(menuItem){
1560            var g = menuItem.group;
1561            if(g){
1562                if(!groups[g]){
1563                    groups[g] = [];
1564                }
1565                groups[g].push(menuItem);
1566                menuItem.on("beforecheckchange", onBeforeCheck);
1567            }
1568        },
1569
1570        // private
1571        unregisterCheckable : function(menuItem){
1572            var g = menuItem.group;
1573            if(g){
1574                groups[g].remove(menuItem);
1575                menuItem.un("beforecheckchange", onBeforeCheck);
1576            }
1577        }
1578    };
1579 }();/*
1580  * - LGPL
1581  *
1582  * menu
1583  * 
1584  */
1585
1586 /**
1587  * @class Roo.bootstrap.Menu
1588  * @extends Roo.bootstrap.Component
1589  * Bootstrap Menu class - container for MenuItems
1590  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1591  * 
1592  * @constructor
1593  * Create a new Menu
1594  * @param {Object} config The config object
1595  */
1596
1597
1598 Roo.bootstrap.Menu = function(config){
1599     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1600     if (this.registerMenu) {
1601         Roo.bootstrap.MenuMgr.register(this);
1602     }
1603     this.addEvents({
1604         /**
1605          * @event beforeshow
1606          * Fires before this menu is displayed
1607          * @param {Roo.menu.Menu} this
1608          */
1609         beforeshow : true,
1610         /**
1611          * @event beforehide
1612          * Fires before this menu is hidden
1613          * @param {Roo.menu.Menu} this
1614          */
1615         beforehide : true,
1616         /**
1617          * @event show
1618          * Fires after this menu is displayed
1619          * @param {Roo.menu.Menu} this
1620          */
1621         show : true,
1622         /**
1623          * @event hide
1624          * Fires after this menu is hidden
1625          * @param {Roo.menu.Menu} this
1626          */
1627         hide : true,
1628         /**
1629          * @event click
1630          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1631          * @param {Roo.menu.Menu} this
1632          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1633          * @param {Roo.EventObject} e
1634          */
1635         click : true,
1636         /**
1637          * @event mouseover
1638          * Fires when the mouse is hovering over this menu
1639          * @param {Roo.menu.Menu} this
1640          * @param {Roo.EventObject} e
1641          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1642          */
1643         mouseover : true,
1644         /**
1645          * @event mouseout
1646          * Fires when the mouse exits this menu
1647          * @param {Roo.menu.Menu} this
1648          * @param {Roo.EventObject} e
1649          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1650          */
1651         mouseout : true,
1652         /**
1653          * @event itemclick
1654          * Fires when a menu item contained in this menu is clicked
1655          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1656          * @param {Roo.EventObject} e
1657          */
1658         itemclick: true
1659     });
1660     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1661 };
1662
1663 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1664     
1665    /// html : false,
1666     //align : '',
1667     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1668     type: false,
1669     /**
1670      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1671      */
1672     registerMenu : true,
1673     
1674     menuItems :false, // stores the menu items..
1675     
1676     hidden:true,
1677     
1678     parentMenu : false,
1679     
1680     getChildContainer : function() {
1681         return this.el;  
1682     },
1683     
1684     getAutoCreate : function(){
1685          
1686         //if (['right'].indexOf(this.align)!==-1) {
1687         //    cfg.cn[1].cls += ' pull-right'
1688         //}
1689         
1690         
1691         var cfg = {
1692             tag : 'ul',
1693             cls : 'dropdown-menu' ,
1694             style : 'z-index:1000'
1695             
1696         }
1697         
1698         if (this.type === 'submenu') {
1699             cfg.cls = 'submenu active';
1700         }
1701         if (this.type === 'treeview') {
1702             cfg.cls = 'treeview-menu';
1703         }
1704         
1705         return cfg;
1706     },
1707     initEvents : function() {
1708         
1709        // Roo.log("ADD event");
1710        // Roo.log(this.triggerEl.dom);
1711         this.triggerEl.on('click', this.onTriggerPress, this);
1712         this.triggerEl.addClass('dropdown-toggle');
1713         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1714
1715         this.el.on("mouseover", this.onMouseOver, this);
1716         this.el.on("mouseout", this.onMouseOut, this);
1717         
1718         
1719     },
1720     findTargetItem : function(e){
1721         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1722         if(!t){
1723             return false;
1724         }
1725         //Roo.log(t);         Roo.log(t.id);
1726         if(t && t.id){
1727             //Roo.log(this.menuitems);
1728             return this.menuitems.get(t.id);
1729             
1730             //return this.items.get(t.menuItemId);
1731         }
1732         
1733         return false;
1734     },
1735     onClick : function(e){
1736         Roo.log("menu.onClick");
1737         var t = this.findTargetItem(e);
1738         if(!t || t.isContainer){
1739             return;
1740         }
1741         Roo.log(e);
1742         /*
1743         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1744             if(t == this.activeItem && t.shouldDeactivate(e)){
1745                 this.activeItem.deactivate();
1746                 delete this.activeItem;
1747                 return;
1748             }
1749             if(t.canActivate){
1750                 this.setActiveItem(t, true);
1751             }
1752             return;
1753             
1754             
1755         }
1756         */
1757        
1758         Roo.log('pass click event');
1759         
1760         t.onClick(e);
1761         
1762         this.fireEvent("click", this, t, e);
1763         
1764         this.hide();
1765     },
1766      onMouseOver : function(e){
1767         var t  = this.findTargetItem(e);
1768         //Roo.log(t);
1769         //if(t){
1770         //    if(t.canActivate && !t.disabled){
1771         //        this.setActiveItem(t, true);
1772         //    }
1773         //}
1774         
1775         this.fireEvent("mouseover", this, e, t);
1776     },
1777     isVisible : function(){
1778         return !this.hidden;
1779     },
1780      onMouseOut : function(e){
1781         var t  = this.findTargetItem(e);
1782         
1783         //if(t ){
1784         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1785         //        this.activeItem.deactivate();
1786         //        delete this.activeItem;
1787         //    }
1788         //}
1789         this.fireEvent("mouseout", this, e, t);
1790     },
1791     
1792     
1793     /**
1794      * Displays this menu relative to another element
1795      * @param {String/HTMLElement/Roo.Element} element The element to align to
1796      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1797      * the element (defaults to this.defaultAlign)
1798      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1799      */
1800     show : function(el, pos, parentMenu){
1801         this.parentMenu = parentMenu;
1802         if(!this.el){
1803             this.render();
1804         }
1805         this.fireEvent("beforeshow", this);
1806         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1807     },
1808      /**
1809      * Displays this menu at a specific xy position
1810      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1811      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1812      */
1813     showAt : function(xy, parentMenu, /* private: */_e){
1814         this.parentMenu = parentMenu;
1815         if(!this.el){
1816             this.render();
1817         }
1818         if(_e !== false){
1819             this.fireEvent("beforeshow", this);
1820             
1821             //xy = this.el.adjustForConstraints(xy);
1822         }
1823         //this.el.setXY(xy);
1824         //this.el.show();
1825         this.hideMenuItems();
1826         this.hidden = false;
1827         this.triggerEl.addClass('open');
1828         this.focus();
1829         this.fireEvent("show", this);
1830     },
1831     
1832     focus : function(){
1833         return;
1834         if(!this.hidden){
1835             this.doFocus.defer(50, this);
1836         }
1837     },
1838
1839     doFocus : function(){
1840         if(!this.hidden){
1841             this.focusEl.focus();
1842         }
1843     },
1844
1845     /**
1846      * Hides this menu and optionally all parent menus
1847      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1848      */
1849     hide : function(deep){
1850         
1851         this.hideMenuItems();
1852         if(this.el && this.isVisible()){
1853             this.fireEvent("beforehide", this);
1854             if(this.activeItem){
1855                 this.activeItem.deactivate();
1856                 this.activeItem = null;
1857             }
1858             this.triggerEl.removeClass('open');;
1859             this.hidden = true;
1860             this.fireEvent("hide", this);
1861         }
1862         if(deep === true && this.parentMenu){
1863             this.parentMenu.hide(true);
1864         }
1865     },
1866     
1867     onTriggerPress  : function(e)
1868     {
1869         
1870         Roo.log('trigger press');
1871         //Roo.log(e.getTarget());
1872        // Roo.log(this.triggerEl.dom);
1873         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1874             return;
1875         }
1876         if (this.isVisible()) {
1877             Roo.log('hide');
1878             this.hide();
1879         } else {
1880             this.show(this.triggerEl, false, false);
1881         }
1882         
1883         
1884     },
1885     
1886          
1887        
1888     
1889     hideMenuItems : function()
1890     {
1891         //$(backdrop).remove()
1892         Roo.select('.open',true).each(function(aa) {
1893             
1894             aa.removeClass('open');
1895           //var parent = getParent($(this))
1896           //var relatedTarget = { relatedTarget: this }
1897           
1898            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1899           //if (e.isDefaultPrevented()) return
1900            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1901         })
1902     },
1903     addxtypeChild : function (tree, cntr) {
1904         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1905           
1906         this.menuitems.add(comp);
1907         return comp;
1908
1909     },
1910     getEl : function()
1911     {
1912         Roo.log(this.el);
1913         return this.el;
1914     }
1915 });
1916
1917  
1918  /*
1919  * - LGPL
1920  *
1921  * menu item
1922  * 
1923  */
1924
1925
1926 /**
1927  * @class Roo.bootstrap.MenuItem
1928  * @extends Roo.bootstrap.Component
1929  * Bootstrap MenuItem class
1930  * @cfg {String} html the menu label
1931  * @cfg {String} href the link
1932  * @cfg {Boolean} preventDefault (true | false) default true
1933  * @cfg {Boolean} isContainer (true | false) default false
1934  * 
1935  * 
1936  * @constructor
1937  * Create a new MenuItem
1938  * @param {Object} config The config object
1939  */
1940
1941
1942 Roo.bootstrap.MenuItem = function(config){
1943     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1944     this.addEvents({
1945         // raw events
1946         /**
1947          * @event click
1948          * The raw click event for the entire grid.
1949          * @param {Roo.EventObject} e
1950          */
1951         "click" : true
1952     });
1953 };
1954
1955 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1956     
1957     href : false,
1958     html : false,
1959     preventDefault: true,
1960     isContainer : false,
1961     
1962     getAutoCreate : function(){
1963         
1964         if(this.isContainer){
1965             return {
1966                 tag: 'li',
1967                 cls: 'dropdown-menu-item'
1968             };
1969         }
1970         
1971         var cfg= {
1972             tag: 'li',
1973             cls: 'dropdown-menu-item',
1974             cn: [
1975                     {
1976                         tag : 'a',
1977                         href : '#',
1978                         html : 'Link'
1979                     }
1980                 ]
1981         };
1982         if (this.parent().type == 'treeview') {
1983             cfg.cls = 'treeview-menu';
1984         }
1985         
1986         cfg.cn[0].href = this.href || cfg.cn[0].href ;
1987         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1988         return cfg;
1989     },
1990     
1991     initEvents: function() {
1992         
1993         //this.el.select('a').on('click', this.onClick, this);
1994         
1995     },
1996     onClick : function(e)
1997     {
1998         Roo.log('item on click ');
1999         //if(this.preventDefault){
2000         //    e.preventDefault();
2001         //}
2002         //this.parent().hideMenuItems();
2003         
2004         this.fireEvent('click', this, e);
2005     },
2006     getEl : function()
2007     {
2008         return this.el;
2009     }
2010 });
2011
2012  
2013
2014  /*
2015  * - LGPL
2016  *
2017  * menu separator
2018  * 
2019  */
2020
2021
2022 /**
2023  * @class Roo.bootstrap.MenuSeparator
2024  * @extends Roo.bootstrap.Component
2025  * Bootstrap MenuSeparator class
2026  * 
2027  * @constructor
2028  * Create a new MenuItem
2029  * @param {Object} config The config object
2030  */
2031
2032
2033 Roo.bootstrap.MenuSeparator = function(config){
2034     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2035 };
2036
2037 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2038     
2039     getAutoCreate : function(){
2040         var cfg = {
2041             cls: 'divider',
2042             tag : 'li'
2043         };
2044         
2045         return cfg;
2046     }
2047    
2048 });
2049
2050  
2051
2052  
2053 /*
2054 <div class="modal fade">
2055   <div class="modal-dialog">
2056     <div class="modal-content">
2057       <div class="modal-header">
2058         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
2059         <h4 class="modal-title">Modal title</h4>
2060       </div>
2061       <div class="modal-body">
2062         <p>One fine body&hellip;</p>
2063       </div>
2064       <div class="modal-footer">
2065         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2066         <button type="button" class="btn btn-primary">Save changes</button>
2067       </div>
2068     </div><!-- /.modal-content -->
2069   </div><!-- /.modal-dialog -->
2070 </div><!-- /.modal -->
2071 */
2072 /*
2073  * - LGPL
2074  *
2075  * page contgainer.
2076  * 
2077  */
2078
2079 /**
2080  * @class Roo.bootstrap.Modal
2081  * @extends Roo.bootstrap.Component
2082  * Bootstrap Modal class
2083  * @cfg {String} title Title of dialog
2084  * @cfg {Boolean} specificTitle default false
2085  * @cfg {Array} buttons Array of buttons or standard button set..
2086  * @cfg {String} buttonPosition (left|right|center) default right
2087  * @cfg {Boolean} animate default true
2088  * @cfg {Boolean} allow_close default true
2089  * 
2090  * @constructor
2091  * Create a new Modal Dialog
2092  * @param {Object} config The config object
2093  */
2094
2095 Roo.bootstrap.Modal = function(config){
2096     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2097     this.addEvents({
2098         // raw events
2099         /**
2100          * @event btnclick
2101          * The raw btnclick event for the button
2102          * @param {Roo.EventObject} e
2103          */
2104         "btnclick" : true
2105     });
2106     this.buttons = this.buttons || [];
2107 };
2108
2109 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2110     
2111     title : 'test dialog',
2112    
2113     buttons : false,
2114     
2115     // set on load...
2116     body:  false,
2117     
2118     specificTitle: false,
2119     
2120     buttonPosition: 'right',
2121     
2122     allow_close : true,
2123     
2124     animate : true,
2125     
2126     onRender : function(ct, position)
2127     {
2128         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2129      
2130         if(!this.el){
2131             var cfg = Roo.apply({},  this.getAutoCreate());
2132             cfg.id = Roo.id();
2133             //if(!cfg.name){
2134             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2135             //}
2136             //if (!cfg.name.length) {
2137             //    delete cfg.name;
2138            // }
2139             if (this.cls) {
2140                 cfg.cls += ' ' + this.cls;
2141             }
2142             if (this.style) {
2143                 cfg.style = this.style;
2144             }
2145             this.el = Roo.get(document.body).createChild(cfg, position);
2146         }
2147         //var type = this.el.dom.type;
2148         
2149         if(this.tabIndex !== undefined){
2150             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2151         }
2152         
2153         
2154         
2155         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2156         this.maskEl.enableDisplayMode("block");
2157         this.maskEl.hide();
2158         //this.el.addClass("x-dlg-modal");
2159     
2160         if (this.buttons.length) {
2161             Roo.each(this.buttons, function(bb) {
2162                 b = Roo.apply({}, bb);
2163                 b.xns = b.xns || Roo.bootstrap;
2164                 b.xtype = b.xtype || 'Button';
2165                 if (typeof(b.listeners) == 'undefined') {
2166                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2167                 }
2168                 
2169                 var btn = Roo.factory(b);
2170                 
2171                 btn.onRender(this.el.select('.modal-footer div').first());
2172                 
2173             },this);
2174         }
2175         // render the children.
2176         var nitems = [];
2177         
2178         if(typeof(this.items) != 'undefined'){
2179             var items = this.items;
2180             delete this.items;
2181
2182             for(var i =0;i < items.length;i++) {
2183                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2184             }
2185         }
2186         
2187         this.items = nitems;
2188         
2189         this.body = this.el.select('.modal-body',true).first();
2190         this.close = this.el.select('.modal-header .close', true).first();
2191         this.footer = this.el.select('.modal-footer',true).first();
2192         this.initEvents();
2193         //this.el.addClass([this.fieldClass, this.cls]);
2194         
2195     },
2196     getAutoCreate : function(){
2197         
2198         
2199         var bdy = {
2200                 cls : 'modal-body',
2201                 html : this.html || ''
2202         };
2203         
2204         var title = {
2205             tag: 'h4',
2206             cls : 'modal-title',
2207             html : this.title
2208         };
2209         
2210         if(this.specificTitle){
2211             title = this.title;
2212             
2213         };
2214         
2215         var header = [];
2216         if (this.allow_close) {
2217             header.push({
2218                 tag: 'button',
2219                 cls : 'close',
2220                 html : '&times'
2221             });
2222         }
2223         header.push(title);
2224         
2225         var modal = {
2226             cls: "modal",
2227             style : 'display: none',
2228             cn : [
2229                 {
2230                     cls: "modal-dialog",
2231                     cn : [
2232                         {
2233                             cls : "modal-content",
2234                             cn : [
2235                                 {
2236                                     cls : 'modal-header',
2237                                     cn : header
2238                                 },
2239                                 bdy,
2240                                 {
2241                                     cls : 'modal-footer',
2242                                     cn : [
2243                                         {
2244                                             tag: 'div',
2245                                             cls: 'btn-' + this.buttonPosition
2246                                         }
2247                                     ]
2248                                     
2249                                 }
2250                                 
2251                                 
2252                             ]
2253                             
2254                         }
2255                     ]
2256                         
2257                 }
2258             ]
2259         };
2260         
2261         if(this.animate){
2262             modal.cls += ' fade';
2263         }
2264         
2265         return modal;
2266           
2267     },
2268     getChildContainer : function() {
2269          
2270          return this.el.select('.modal-body',true).first();
2271         
2272     },
2273     getButtonContainer : function() {
2274          return this.el.select('.modal-footer div',true).first();
2275         
2276     },
2277     initEvents : function()
2278     {
2279         this.el.select('.modal-header .close').on('click', this.hide, this);
2280 //        
2281 //        this.addxtype(this);
2282     },
2283     show : function() {
2284         
2285         if (!this.rendered) {
2286             this.render();
2287         }
2288         
2289         this.el.setStyle('display', 'block');
2290         
2291         if(this.animate){
2292             var _this = this;
2293             (function(){ _this.el.addClass('in'); }).defer(50);
2294         }else{
2295             this.el.addClass('in');
2296         }
2297         
2298         Roo.get(document.body).addClass("x-body-masked");
2299         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2300         this.maskEl.show();
2301         this.el.setStyle('zIndex', '10001');
2302        
2303         this.fireEvent('show', this);
2304         
2305         
2306     },
2307     hide : function()
2308     {
2309         this.maskEl.hide();
2310         Roo.get(document.body).removeClass("x-body-masked");
2311         this.el.removeClass('in');
2312         
2313         if(this.animate){
2314             var _this = this;
2315             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2316         }else{
2317             this.el.setStyle('display', 'none');
2318         }
2319         
2320         this.fireEvent('hide', this);
2321     },
2322     
2323     addButton : function(str, cb)
2324     {
2325          
2326         
2327         var b = Roo.apply({}, { html : str } );
2328         b.xns = b.xns || Roo.bootstrap;
2329         b.xtype = b.xtype || 'Button';
2330         if (typeof(b.listeners) == 'undefined') {
2331             b.listeners = { click : cb.createDelegate(this)  };
2332         }
2333         
2334         var btn = Roo.factory(b);
2335            
2336         btn.onRender(this.el.select('.modal-footer div').first());
2337         
2338         return btn;   
2339        
2340     },
2341     
2342     setDefaultButton : function(btn)
2343     {
2344         //this.el.select('.modal-footer').()
2345     },
2346     resizeTo: function(w,h)
2347     {
2348         // skip..
2349     },
2350     setContentSize  : function(w, h)
2351     {
2352         
2353     },
2354     onButtonClick: function(btn,e)
2355     {
2356         //Roo.log([a,b,c]);
2357         this.fireEvent('btnclick', btn.name, e);
2358     },
2359     setTitle: function(str) {
2360         this.el.select('.modal-title',true).first().dom.innerHTML = str;
2361         
2362     }
2363 });
2364
2365
2366 Roo.apply(Roo.bootstrap.Modal,  {
2367     /**
2368          * Button config that displays a single OK button
2369          * @type Object
2370          */
2371         OK :  [{
2372             name : 'ok',
2373             weight : 'primary',
2374             html : 'OK'
2375         }], 
2376         /**
2377          * Button config that displays Yes and No buttons
2378          * @type Object
2379          */
2380         YESNO : [
2381             {
2382                 name  : 'no',
2383                 html : 'No'
2384             },
2385             {
2386                 name  :'yes',
2387                 weight : 'primary',
2388                 html : 'Yes'
2389             }
2390         ],
2391         
2392         /**
2393          * Button config that displays OK and Cancel buttons
2394          * @type Object
2395          */
2396         OKCANCEL : [
2397             {
2398                name : 'cancel',
2399                 html : 'Cancel'
2400             },
2401             {
2402                 name : 'ok',
2403                 weight : 'primary',
2404                 html : 'OK'
2405             }
2406         ],
2407         /**
2408          * Button config that displays Yes, No and Cancel buttons
2409          * @type Object
2410          */
2411         YESNOCANCEL : [
2412             {
2413                 name : 'yes',
2414                 weight : 'primary',
2415                 html : 'Yes'
2416             },
2417             {
2418                 name : 'no',
2419                 html : 'No'
2420             },
2421             {
2422                 name : 'cancel',
2423                 html : 'Cancel'
2424             }
2425         ]
2426 });
2427  /*
2428  * - LGPL
2429  *
2430  * messagebox - can be used as a replace
2431  * 
2432  */
2433 /**
2434  * @class Roo.MessageBox
2435  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2436  * Example usage:
2437  *<pre><code>
2438 // Basic alert:
2439 Roo.Msg.alert('Status', 'Changes saved successfully.');
2440
2441 // Prompt for user data:
2442 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2443     if (btn == 'ok'){
2444         // process text value...
2445     }
2446 });
2447
2448 // Show a dialog using config options:
2449 Roo.Msg.show({
2450    title:'Save Changes?',
2451    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2452    buttons: Roo.Msg.YESNOCANCEL,
2453    fn: processResult,
2454    animEl: 'elId'
2455 });
2456 </code></pre>
2457  * @singleton
2458  */
2459 Roo.bootstrap.MessageBox = function(){
2460     var dlg, opt, mask, waitTimer;
2461     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2462     var buttons, activeTextEl, bwidth;
2463
2464     
2465     // private
2466     var handleButton = function(button){
2467         dlg.hide();
2468         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2469     };
2470
2471     // private
2472     var handleHide = function(){
2473         if(opt && opt.cls){
2474             dlg.el.removeClass(opt.cls);
2475         }
2476         //if(waitTimer){
2477         //    Roo.TaskMgr.stop(waitTimer);
2478         //    waitTimer = null;
2479         //}
2480     };
2481
2482     // private
2483     var updateButtons = function(b){
2484         var width = 0;
2485         if(!b){
2486             buttons["ok"].hide();
2487             buttons["cancel"].hide();
2488             buttons["yes"].hide();
2489             buttons["no"].hide();
2490             //dlg.footer.dom.style.display = 'none';
2491             return width;
2492         }
2493         dlg.footer.dom.style.display = '';
2494         for(var k in buttons){
2495             if(typeof buttons[k] != "function"){
2496                 if(b[k]){
2497                     buttons[k].show();
2498                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2499                     width += buttons[k].el.getWidth()+15;
2500                 }else{
2501                     buttons[k].hide();
2502                 }
2503             }
2504         }
2505         return width;
2506     };
2507
2508     // private
2509     var handleEsc = function(d, k, e){
2510         if(opt && opt.closable !== false){
2511             dlg.hide();
2512         }
2513         if(e){
2514             e.stopEvent();
2515         }
2516     };
2517
2518     return {
2519         /**
2520          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2521          * @return {Roo.BasicDialog} The BasicDialog element
2522          */
2523         getDialog : function(){
2524            if(!dlg){
2525                 dlg = new Roo.bootstrap.Modal( {
2526                     //draggable: true,
2527                     //resizable:false,
2528                     //constraintoviewport:false,
2529                     //fixedcenter:true,
2530                     //collapsible : false,
2531                     //shim:true,
2532                     //modal: true,
2533                   //  width:400,
2534                   //  height:100,
2535                     //buttonAlign:"center",
2536                     closeClick : function(){
2537                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2538                             handleButton("no");
2539                         }else{
2540                             handleButton("cancel");
2541                         }
2542                     }
2543                 });
2544                 dlg.render();
2545                 dlg.on("hide", handleHide);
2546                 mask = dlg.mask;
2547                 //dlg.addKeyListener(27, handleEsc);
2548                 buttons = {};
2549                 this.buttons = buttons;
2550                 var bt = this.buttonText;
2551                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2552                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2553                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2554                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2555                 Roo.log(buttons)
2556                 bodyEl = dlg.body.createChild({
2557
2558                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2559                         '<textarea class="roo-mb-textarea"></textarea>' +
2560                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2561                 });
2562                 msgEl = bodyEl.dom.firstChild;
2563                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2564                 textboxEl.enableDisplayMode();
2565                 textboxEl.addKeyListener([10,13], function(){
2566                     if(dlg.isVisible() && opt && opt.buttons){
2567                         if(opt.buttons.ok){
2568                             handleButton("ok");
2569                         }else if(opt.buttons.yes){
2570                             handleButton("yes");
2571                         }
2572                     }
2573                 });
2574                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2575                 textareaEl.enableDisplayMode();
2576                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2577                 progressEl.enableDisplayMode();
2578                 var pf = progressEl.dom.firstChild;
2579                 if (pf) {
2580                     pp = Roo.get(pf.firstChild);
2581                     pp.setHeight(pf.offsetHeight);
2582                 }
2583                 
2584             }
2585             return dlg;
2586         },
2587
2588         /**
2589          * Updates the message box body text
2590          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2591          * the XHTML-compliant non-breaking space character '&amp;#160;')
2592          * @return {Roo.MessageBox} This message box
2593          */
2594         updateText : function(text){
2595             if(!dlg.isVisible() && !opt.width){
2596                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2597             }
2598             msgEl.innerHTML = text || '&#160;';
2599       
2600             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2601             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2602             var w = Math.max(
2603                     Math.min(opt.width || cw , this.maxWidth), 
2604                     Math.max(opt.minWidth || this.minWidth, bwidth)
2605             );
2606             if(opt.prompt){
2607                 activeTextEl.setWidth(w);
2608             }
2609             if(dlg.isVisible()){
2610                 dlg.fixedcenter = false;
2611             }
2612             // to big, make it scroll. = But as usual stupid IE does not support
2613             // !important..
2614             
2615             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2616                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2617                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2618             } else {
2619                 bodyEl.dom.style.height = '';
2620                 bodyEl.dom.style.overflowY = '';
2621             }
2622             if (cw > w) {
2623                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2624             } else {
2625                 bodyEl.dom.style.overflowX = '';
2626             }
2627             
2628             dlg.setContentSize(w, bodyEl.getHeight());
2629             if(dlg.isVisible()){
2630                 dlg.fixedcenter = true;
2631             }
2632             return this;
2633         },
2634
2635         /**
2636          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2637          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2638          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2639          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2640          * @return {Roo.MessageBox} This message box
2641          */
2642         updateProgress : function(value, text){
2643             if(text){
2644                 this.updateText(text);
2645             }
2646             if (pp) { // weird bug on my firefox - for some reason this is not defined
2647                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2648             }
2649             return this;
2650         },        
2651
2652         /**
2653          * Returns true if the message box is currently displayed
2654          * @return {Boolean} True if the message box is visible, else false
2655          */
2656         isVisible : function(){
2657             return dlg && dlg.isVisible();  
2658         },
2659
2660         /**
2661          * Hides the message box if it is displayed
2662          */
2663         hide : function(){
2664             if(this.isVisible()){
2665                 dlg.hide();
2666             }  
2667         },
2668
2669         /**
2670          * Displays a new message box, or reinitializes an existing message box, based on the config options
2671          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2672          * The following config object properties are supported:
2673          * <pre>
2674 Property    Type             Description
2675 ----------  ---------------  ------------------------------------------------------------------------------------
2676 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2677                                    closes (defaults to undefined)
2678 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2679                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2680 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2681                                    progress and wait dialogs will ignore this property and always hide the
2682                                    close button as they can only be closed programmatically.
2683 cls               String           A custom CSS class to apply to the message box element
2684 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2685                                    displayed (defaults to 75)
2686 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2687                                    function will be btn (the name of the button that was clicked, if applicable,
2688                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2689                                    Progress and wait dialogs will ignore this option since they do not respond to
2690                                    user actions and can only be closed programmatically, so any required function
2691                                    should be called by the same code after it closes the dialog.
2692 icon              String           A CSS class that provides a background image to be used as an icon for
2693                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2694 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2695 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2696 modal             Boolean          False to allow user interaction with the page while the message box is
2697                                    displayed (defaults to true)
2698 msg               String           A string that will replace the existing message box body text (defaults
2699                                    to the XHTML-compliant non-breaking space character '&#160;')
2700 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2701 progress          Boolean          True to display a progress bar (defaults to false)
2702 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2703 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2704 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2705 title             String           The title text
2706 value             String           The string value to set into the active textbox element if displayed
2707 wait              Boolean          True to display a progress bar (defaults to false)
2708 width             Number           The width of the dialog in pixels
2709 </pre>
2710          *
2711          * Example usage:
2712          * <pre><code>
2713 Roo.Msg.show({
2714    title: 'Address',
2715    msg: 'Please enter your address:',
2716    width: 300,
2717    buttons: Roo.MessageBox.OKCANCEL,
2718    multiline: true,
2719    fn: saveAddress,
2720    animEl: 'addAddressBtn'
2721 });
2722 </code></pre>
2723          * @param {Object} config Configuration options
2724          * @return {Roo.MessageBox} This message box
2725          */
2726         show : function(options)
2727         {
2728             
2729             // this causes nightmares if you show one dialog after another
2730             // especially on callbacks..
2731              
2732             if(this.isVisible()){
2733                 
2734                 this.hide();
2735                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2736                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2737                 Roo.log("New Dialog Message:" +  options.msg )
2738                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2739                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2740                 
2741             }
2742             var d = this.getDialog();
2743             opt = options;
2744             d.setTitle(opt.title || "&#160;");
2745             d.close.setDisplayed(opt.closable !== false);
2746             activeTextEl = textboxEl;
2747             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2748             if(opt.prompt){
2749                 if(opt.multiline){
2750                     textboxEl.hide();
2751                     textareaEl.show();
2752                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2753                         opt.multiline : this.defaultTextHeight);
2754                     activeTextEl = textareaEl;
2755                 }else{
2756                     textboxEl.show();
2757                     textareaEl.hide();
2758                 }
2759             }else{
2760                 textboxEl.hide();
2761                 textareaEl.hide();
2762             }
2763             progressEl.setDisplayed(opt.progress === true);
2764             this.updateProgress(0);
2765             activeTextEl.dom.value = opt.value || "";
2766             if(opt.prompt){
2767                 dlg.setDefaultButton(activeTextEl);
2768             }else{
2769                 var bs = opt.buttons;
2770                 var db = null;
2771                 if(bs && bs.ok){
2772                     db = buttons["ok"];
2773                 }else if(bs && bs.yes){
2774                     db = buttons["yes"];
2775                 }
2776                 dlg.setDefaultButton(db);
2777             }
2778             bwidth = updateButtons(opt.buttons);
2779             this.updateText(opt.msg);
2780             if(opt.cls){
2781                 d.el.addClass(opt.cls);
2782             }
2783             d.proxyDrag = opt.proxyDrag === true;
2784             d.modal = opt.modal !== false;
2785             d.mask = opt.modal !== false ? mask : false;
2786             if(!d.isVisible()){
2787                 // force it to the end of the z-index stack so it gets a cursor in FF
2788                 document.body.appendChild(dlg.el.dom);
2789                 d.animateTarget = null;
2790                 d.show(options.animEl);
2791             }
2792             return this;
2793         },
2794
2795         /**
2796          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2797          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2798          * and closing the message box when the process is complete.
2799          * @param {String} title The title bar text
2800          * @param {String} msg The message box body text
2801          * @return {Roo.MessageBox} This message box
2802          */
2803         progress : function(title, msg){
2804             this.show({
2805                 title : title,
2806                 msg : msg,
2807                 buttons: false,
2808                 progress:true,
2809                 closable:false,
2810                 minWidth: this.minProgressWidth,
2811                 modal : true
2812             });
2813             return this;
2814         },
2815
2816         /**
2817          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2818          * If a callback function is passed it will be called after the user clicks the button, and the
2819          * id of the button that was clicked will be passed as the only parameter to the callback
2820          * (could also be the top-right close button).
2821          * @param {String} title The title bar text
2822          * @param {String} msg The message box body text
2823          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2824          * @param {Object} scope (optional) The scope of the callback function
2825          * @return {Roo.MessageBox} This message box
2826          */
2827         alert : function(title, msg, fn, scope){
2828             this.show({
2829                 title : title,
2830                 msg : msg,
2831                 buttons: this.OK,
2832                 fn: fn,
2833                 scope : scope,
2834                 modal : true
2835             });
2836             return this;
2837         },
2838
2839         /**
2840          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2841          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2842          * You are responsible for closing the message box when the process is complete.
2843          * @param {String} msg The message box body text
2844          * @param {String} title (optional) The title bar text
2845          * @return {Roo.MessageBox} This message box
2846          */
2847         wait : function(msg, title){
2848             this.show({
2849                 title : title,
2850                 msg : msg,
2851                 buttons: false,
2852                 closable:false,
2853                 progress:true,
2854                 modal:true,
2855                 width:300,
2856                 wait:true
2857             });
2858             waitTimer = Roo.TaskMgr.start({
2859                 run: function(i){
2860                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2861                 },
2862                 interval: 1000
2863             });
2864             return this;
2865         },
2866
2867         /**
2868          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2869          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2870          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2871          * @param {String} title The title bar text
2872          * @param {String} msg The message box body text
2873          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2874          * @param {Object} scope (optional) The scope of the callback function
2875          * @return {Roo.MessageBox} This message box
2876          */
2877         confirm : function(title, msg, fn, scope){
2878             this.show({
2879                 title : title,
2880                 msg : msg,
2881                 buttons: this.YESNO,
2882                 fn: fn,
2883                 scope : scope,
2884                 modal : true
2885             });
2886             return this;
2887         },
2888
2889         /**
2890          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2891          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2892          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2893          * (could also be the top-right close button) and the text that was entered will be passed as the two
2894          * parameters to the callback.
2895          * @param {String} title The title bar text
2896          * @param {String} msg The message box body text
2897          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2898          * @param {Object} scope (optional) The scope of the callback function
2899          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2900          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2901          * @return {Roo.MessageBox} This message box
2902          */
2903         prompt : function(title, msg, fn, scope, multiline){
2904             this.show({
2905                 title : title,
2906                 msg : msg,
2907                 buttons: this.OKCANCEL,
2908                 fn: fn,
2909                 minWidth:250,
2910                 scope : scope,
2911                 prompt:true,
2912                 multiline: multiline,
2913                 modal : true
2914             });
2915             return this;
2916         },
2917
2918         /**
2919          * Button config that displays a single OK button
2920          * @type Object
2921          */
2922         OK : {ok:true},
2923         /**
2924          * Button config that displays Yes and No buttons
2925          * @type Object
2926          */
2927         YESNO : {yes:true, no:true},
2928         /**
2929          * Button config that displays OK and Cancel buttons
2930          * @type Object
2931          */
2932         OKCANCEL : {ok:true, cancel:true},
2933         /**
2934          * Button config that displays Yes, No and Cancel buttons
2935          * @type Object
2936          */
2937         YESNOCANCEL : {yes:true, no:true, cancel:true},
2938
2939         /**
2940          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2941          * @type Number
2942          */
2943         defaultTextHeight : 75,
2944         /**
2945          * The maximum width in pixels of the message box (defaults to 600)
2946          * @type Number
2947          */
2948         maxWidth : 600,
2949         /**
2950          * The minimum width in pixels of the message box (defaults to 100)
2951          * @type Number
2952          */
2953         minWidth : 100,
2954         /**
2955          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
2956          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2957          * @type Number
2958          */
2959         minProgressWidth : 250,
2960         /**
2961          * An object containing the default button text strings that can be overriden for localized language support.
2962          * Supported properties are: ok, cancel, yes and no.
2963          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2964          * @type Object
2965          */
2966         buttonText : {
2967             ok : "OK",
2968             cancel : "Cancel",
2969             yes : "Yes",
2970             no : "No"
2971         }
2972     };
2973 }();
2974
2975 /**
2976  * Shorthand for {@link Roo.MessageBox}
2977  */
2978 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
2979 Roo.Msg = Roo.Msg || Roo.MessageBox;
2980 /*
2981  * - LGPL
2982  *
2983  * navbar
2984  * 
2985  */
2986
2987 /**
2988  * @class Roo.bootstrap.Navbar
2989  * @extends Roo.bootstrap.Component
2990  * Bootstrap Navbar class
2991
2992  * @constructor
2993  * Create a new Navbar
2994  * @param {Object} config The config object
2995  */
2996
2997
2998 Roo.bootstrap.Navbar = function(config){
2999     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3000     
3001 };
3002
3003 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3004     
3005     
3006    
3007     // private
3008     navItems : false,
3009     loadMask : false,
3010     
3011     
3012     getAutoCreate : function(){
3013         
3014         
3015         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3016         
3017     },
3018     
3019     initEvents :function ()
3020     {
3021         //Roo.log(this.el.select('.navbar-toggle',true));
3022         this.el.select('.navbar-toggle',true).on('click', function() {
3023            // Roo.log('click');
3024             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3025         }, this);
3026         
3027         var mark = {
3028             tag: "div",
3029             cls:"x-dlg-mask"
3030         }
3031         
3032         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3033         
3034         var size = this.el.getSize();
3035         this.maskEl.setSize(size.width, size.height);
3036         this.maskEl.enableDisplayMode("block");
3037         this.maskEl.hide();
3038         
3039         if(this.loadMask){
3040             this.maskEl.show();
3041         }
3042     },
3043     
3044     
3045     getChildContainer : function()
3046     {
3047         if (this.el.select('.collapse').getCount()) {
3048             return this.el.select('.collapse',true).first();
3049         }
3050         
3051         return this.el;
3052     },
3053     
3054     mask : function()
3055     {
3056         this.maskEl.show();
3057     },
3058     
3059     unmask : function()
3060     {
3061         this.maskEl.hide();
3062     } 
3063     
3064     
3065     
3066     
3067 });
3068
3069
3070
3071  
3072
3073  /*
3074  * - LGPL
3075  *
3076  * navbar
3077  * 
3078  */
3079
3080 /**
3081  * @class Roo.bootstrap.NavSimplebar
3082  * @extends Roo.bootstrap.Navbar
3083  * Bootstrap Sidebar class
3084  *
3085  * @cfg {Boolean} inverse is inverted color
3086  * 
3087  * @cfg {String} type (nav | pills | tabs)
3088  * @cfg {Boolean} arrangement stacked | justified
3089  * @cfg {String} align (left | right) alignment
3090  * 
3091  * @cfg {Boolean} main (true|false) main nav bar? default false
3092  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3093  * 
3094  * @cfg {String} tag (header|footer|nav|div) default is nav 
3095
3096  * 
3097  * 
3098  * 
3099  * @constructor
3100  * Create a new Sidebar
3101  * @param {Object} config The config object
3102  */
3103
3104
3105 Roo.bootstrap.NavSimplebar = function(config){
3106     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3107 };
3108
3109 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3110     
3111     inverse: false,
3112     
3113     type: false,
3114     arrangement: '',
3115     align : false,
3116     
3117     
3118     
3119     main : false,
3120     
3121     
3122     tag : false,
3123     
3124     
3125     getAutoCreate : function(){
3126         
3127         
3128         var cfg = {
3129             tag : this.tag || 'div',
3130             cls : 'navbar'
3131         };
3132           
3133         
3134         cfg.cn = [
3135             {
3136                 cls: 'nav',
3137                 tag : 'ul'
3138             }
3139         ];
3140         
3141          
3142         this.type = this.type || 'nav';
3143         if (['tabs','pills'].indexOf(this.type)!==-1) {
3144             cfg.cn[0].cls += ' nav-' + this.type
3145         
3146         
3147         } else {
3148             if (this.type!=='nav') {
3149                 Roo.log('nav type must be nav/tabs/pills')
3150             }
3151             cfg.cn[0].cls += ' navbar-nav'
3152         }
3153         
3154         
3155         
3156         
3157         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3158             cfg.cn[0].cls += ' nav-' + this.arrangement;
3159         }
3160         
3161         
3162         if (this.align === 'right') {
3163             cfg.cn[0].cls += ' navbar-right';
3164         }
3165         
3166         if (this.inverse) {
3167             cfg.cls += ' navbar-inverse';
3168             
3169         }
3170         
3171         
3172         return cfg;
3173     
3174         
3175     }
3176     
3177     
3178     
3179 });
3180
3181
3182
3183  
3184
3185  
3186        /*
3187  * - LGPL
3188  *
3189  * navbar
3190  * 
3191  */
3192
3193 /**
3194  * @class Roo.bootstrap.NavHeaderbar
3195  * @extends Roo.bootstrap.NavSimplebar
3196  * Bootstrap Sidebar class
3197  *
3198  * @cfg {String} brand what is brand
3199  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3200  * @cfg {String} brand_href href of the brand
3201  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3202  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3203  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3204  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3205  * 
3206  * @constructor
3207  * Create a new Sidebar
3208  * @param {Object} config The config object
3209  */
3210
3211
3212 Roo.bootstrap.NavHeaderbar = function(config){
3213     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3214       
3215 };
3216
3217 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3218     
3219     position: '',
3220     brand: '',
3221     brand_href: false,
3222     srButton : true,
3223     autohide : false,
3224     desktopCenter : false,
3225    
3226     
3227     getAutoCreate : function(){
3228         
3229         var   cfg = {
3230             tag: this.nav || 'nav',
3231             cls: 'navbar',
3232             role: 'navigation',
3233             cn: []
3234         };
3235         
3236         var cn = cfg.cn;
3237         if (this.desktopCenter) {
3238             cn.push({cls : 'container', cn : []});
3239             cn = cn[0].cn;
3240         }
3241         
3242         if(this.srButton){
3243             cn.push({
3244                 tag: 'div',
3245                 cls: 'navbar-header',
3246                 cn: [
3247                     {
3248                         tag: 'button',
3249                         type: 'button',
3250                         cls: 'navbar-toggle',
3251                         'data-toggle': 'collapse',
3252                         cn: [
3253                             {
3254                                 tag: 'span',
3255                                 cls: 'sr-only',
3256                                 html: 'Toggle navigation'
3257                             },
3258                             {
3259                                 tag: 'span',
3260                                 cls: 'icon-bar'
3261                             },
3262                             {
3263                                 tag: 'span',
3264                                 cls: 'icon-bar'
3265                             },
3266                             {
3267                                 tag: 'span',
3268                                 cls: 'icon-bar'
3269                             }
3270                         ]
3271                     }
3272                 ]
3273             });
3274         }
3275         
3276         cn.push({
3277             tag: 'div',
3278             cls: 'collapse navbar-collapse',
3279             cn : []
3280         });
3281         
3282         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3283         
3284         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3285             cfg.cls += ' navbar-' + this.position;
3286             
3287             // tag can override this..
3288             
3289             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3290         }
3291         
3292         if (this.brand !== '') {
3293             cn[0].cn.push({
3294                 tag: 'a',
3295                 href: this.brand_href ? this.brand_href : '#',
3296                 cls: 'navbar-brand',
3297                 cn: [
3298                 this.brand
3299                 ]
3300             });
3301         }
3302         
3303         if(this.main){
3304             cfg.cls += ' main-nav';
3305         }
3306         
3307         
3308         return cfg;
3309
3310         
3311     },
3312     getHeaderChildContainer : function()
3313     {
3314         if (this.el.select('.navbar-header').getCount()) {
3315             return this.el.select('.navbar-header',true).first();
3316         }
3317         
3318         return this.getChildContainer();
3319     },
3320     
3321     
3322     initEvents : function()
3323     {
3324         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3325         
3326         if (this.autohide) {
3327             
3328             var prevScroll = 0;
3329             var ft = this.el;
3330             
3331             Roo.get(document).on('scroll',function(e) {
3332                 var ns = Roo.get(document).getScroll().top;
3333                 var os = prevScroll;
3334                 prevScroll = ns;
3335                 
3336                 if(ns > os){
3337                     ft.removeClass('slideDown');
3338                     ft.addClass('slideUp');
3339                     return;
3340                 }
3341                 ft.removeClass('slideUp');
3342                 ft.addClass('slideDown');
3343                  
3344               
3345           },this);
3346         }
3347     }    
3348           
3349       
3350     
3351     
3352 });
3353
3354
3355
3356  
3357
3358  /*
3359  * - LGPL
3360  *
3361  * navbar
3362  * 
3363  */
3364
3365 /**
3366  * @class Roo.bootstrap.NavSidebar
3367  * @extends Roo.bootstrap.Navbar
3368  * Bootstrap Sidebar class
3369  * 
3370  * @constructor
3371  * Create a new Sidebar
3372  * @param {Object} config The config object
3373  */
3374
3375
3376 Roo.bootstrap.NavSidebar = function(config){
3377     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3378 };
3379
3380 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3381     
3382     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3383     
3384     getAutoCreate : function(){
3385         
3386         
3387         return  {
3388             tag: 'div',
3389             cls: 'sidebar sidebar-nav'
3390         };
3391     
3392         
3393     }
3394     
3395     
3396     
3397 });
3398
3399
3400
3401  
3402
3403  /*
3404  * - LGPL
3405  *
3406  * nav group
3407  * 
3408  */
3409
3410 /**
3411  * @class Roo.bootstrap.NavGroup
3412  * @extends Roo.bootstrap.Component
3413  * Bootstrap NavGroup class
3414  * @cfg {String} align left | right
3415  * @cfg {Boolean} inverse false | true
3416  * @cfg {String} type (nav|pills|tab) default nav
3417  * @cfg {String} navId - reference Id for navbar.
3418
3419  * 
3420  * @constructor
3421  * Create a new nav group
3422  * @param {Object} config The config object
3423  */
3424
3425 Roo.bootstrap.NavGroup = function(config){
3426     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3427     this.navItems = [];
3428    
3429     Roo.bootstrap.NavGroup.register(this);
3430      this.addEvents({
3431         /**
3432              * @event changed
3433              * Fires when the active item changes
3434              * @param {Roo.bootstrap.NavGroup} this
3435              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3436              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3437          */
3438         'changed': true
3439      });
3440     
3441 };
3442
3443 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3444     
3445     align: '',
3446     inverse: false,
3447     form: false,
3448     type: 'nav',
3449     navId : '',
3450     // private
3451     
3452     navItems : false, 
3453     
3454     getAutoCreate : function()
3455     {
3456         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3457         
3458         cfg = {
3459             tag : 'ul',
3460             cls: 'nav' 
3461         }
3462         
3463         if (['tabs','pills'].indexOf(this.type)!==-1) {
3464             cfg.cls += ' nav-' + this.type
3465         } else {
3466             if (this.type!=='nav') {
3467                 Roo.log('nav type must be nav/tabs/pills')
3468             }
3469             cfg.cls += ' navbar-nav'
3470         }
3471         
3472         if (this.parent().sidebar) {
3473             cfg = {
3474                 tag: 'ul',
3475                 cls: 'dashboard-menu sidebar-menu'
3476             }
3477             
3478             return cfg;
3479         }
3480         
3481         if (this.form === true) {
3482             cfg = {
3483                 tag: 'form',
3484                 cls: 'navbar-form'
3485             }
3486             
3487             if (this.align === 'right') {
3488                 cfg.cls += ' navbar-right';
3489             } else {
3490                 cfg.cls += ' navbar-left';
3491             }
3492         }
3493         
3494         if (this.align === 'right') {
3495             cfg.cls += ' navbar-right';
3496         }
3497         
3498         if (this.inverse) {
3499             cfg.cls += ' navbar-inverse';
3500             
3501         }
3502         
3503         
3504         return cfg;
3505     },
3506     /**
3507     * sets the active Navigation item
3508     * @param {Roo.bootstrap.NavItem} the new current navitem
3509     */
3510     setActiveItem : function(item)
3511     {
3512         var prev = false;
3513         Roo.each(this.navItems, function(v){
3514             if (v == item) {
3515                 return ;
3516             }
3517             if (v.isActive()) {
3518                 v.setActive(false, true);
3519                 prev = v;
3520                 
3521             }
3522             
3523         });
3524
3525         item.setActive(true, true);
3526         this.fireEvent('changed', this, item, prev);
3527         
3528         
3529     },
3530     /**
3531     * gets the active Navigation item
3532     * @return {Roo.bootstrap.NavItem} the current navitem
3533     */
3534     getActive : function()
3535     {
3536         
3537         var prev = false;
3538         Roo.each(this.navItems, function(v){
3539             
3540             if (v.isActive()) {
3541                 prev = v;
3542                 
3543             }
3544             
3545         });
3546         return prev;
3547     },
3548     
3549     indexOfNav : function()
3550     {
3551         
3552         var prev = false;
3553         Roo.each(this.navItems, function(v,i){
3554             
3555             if (v.isActive()) {
3556                 prev = i;
3557                 
3558             }
3559             
3560         });
3561         return prev;
3562     },
3563     /**
3564     * adds a Navigation item
3565     * @param {Roo.bootstrap.NavItem} the navitem to add
3566     */
3567     addItem : function(cfg)
3568     {
3569         var cn = new Roo.bootstrap.NavItem(cfg);
3570         this.register(cn);
3571         cn.parentId = this.id;
3572         cn.onRender(this.el, null);
3573         return cn;
3574     },
3575     /**
3576     * register a Navigation item
3577     * @param {Roo.bootstrap.NavItem} the navitem to add
3578     */
3579     register : function(item)
3580     {
3581         this.navItems.push( item);
3582         item.navId = this.navId;
3583     
3584     },
3585     
3586     /**
3587     * clear all the Navigation item
3588     */
3589    
3590     clearAll : function()
3591     {
3592         this.navItems = [];
3593         this.el.dom.innerHTML = '';
3594     },
3595     
3596     getNavItem: function(tabId)
3597     {
3598         var ret = false;
3599         Roo.each(this.navItems, function(e) {
3600             if (e.tabId == tabId) {
3601                ret =  e;
3602                return false;
3603             }
3604             return true;
3605             
3606         });
3607         return ret;
3608     },
3609     
3610     setActiveNext : function()
3611     {
3612         var i = this.indexOfNav(this.getActive());
3613         if (i > this.navItems.length) {
3614             return;
3615         }
3616         this.setActiveItem(this.navItems[i+1]);
3617     },
3618     setActivePrev : function()
3619     {
3620         var i = this.indexOfNav(this.getActive());
3621         if (i  < 1) {
3622             return;
3623         }
3624         this.setActiveItem(this.navItems[i-1]);
3625     },
3626     clearWasActive : function(except) {
3627         Roo.each(this.navItems, function(e) {
3628             if (e.tabId != except.tabId && e.was_active) {
3629                e.was_active = false;
3630                return false;
3631             }
3632             return true;
3633             
3634         });
3635     },
3636     getWasActive : function ()
3637     {
3638         var r = false;
3639         Roo.each(this.navItems, function(e) {
3640             if (e.was_active) {
3641                r = e;
3642                return false;
3643             }
3644             return true;
3645             
3646         });
3647         return r;
3648     }
3649     
3650     
3651 });
3652
3653  
3654 Roo.apply(Roo.bootstrap.NavGroup, {
3655     
3656     groups: {},
3657      /**
3658     * register a Navigation Group
3659     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3660     */
3661     register : function(navgrp)
3662     {
3663         this.groups[navgrp.navId] = navgrp;
3664         
3665     },
3666     /**
3667     * fetch a Navigation Group based on the navigation ID
3668     * @param {string} the navgroup to add
3669     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3670     */
3671     get: function(navId) {
3672         if (typeof(this.groups[navId]) == 'undefined') {
3673             return false;
3674             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3675         }
3676         return this.groups[navId] ;
3677     }
3678     
3679     
3680     
3681 });
3682
3683  /*
3684  * - LGPL
3685  *
3686  * row
3687  * 
3688  */
3689
3690 /**
3691  * @class Roo.bootstrap.NavItem
3692  * @extends Roo.bootstrap.Component
3693  * Bootstrap Navbar.NavItem class
3694  * @cfg {String} href  link to
3695  * @cfg {String} html content of button
3696  * @cfg {String} badge text inside badge
3697  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3698  * @cfg {String} glyphicon name of glyphicon
3699  * @cfg {String} icon name of font awesome icon
3700  * @cfg {Boolean} active Is item active
3701  * @cfg {Boolean} disabled Is item disabled
3702  
3703  * @cfg {Boolean} preventDefault (true | false) default false
3704  * @cfg {String} tabId the tab that this item activates.
3705  * @cfg {String} tagtype (a|span) render as a href or span?
3706   
3707  * @constructor
3708  * Create a new Navbar Item
3709  * @param {Object} config The config object
3710  */
3711 Roo.bootstrap.NavItem = function(config){
3712     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3713     this.addEvents({
3714         // raw events
3715         /**
3716          * @event click
3717          * The raw click event for the entire grid.
3718          * @param {Roo.EventObject} e
3719          */
3720         "click" : true,
3721          /**
3722             * @event changed
3723             * Fires when the active item active state changes
3724             * @param {Roo.bootstrap.NavItem} this
3725             * @param {boolean} state the new state
3726              
3727          */
3728         'changed': true
3729     });
3730    
3731 };
3732
3733 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3734     
3735     href: false,
3736     html: '',
3737     badge: '',
3738     icon: false,
3739     glyphicon: false,
3740     active: false,
3741     preventDefault : false,
3742     tabId : false,
3743     tagtype : 'a',
3744     disabled : false,
3745     
3746     was_active : false,
3747     
3748     getAutoCreate : function(){
3749          
3750         var cfg = {
3751             tag: 'li',
3752             cls: 'nav-item'
3753             
3754         }
3755         if (this.active) {
3756             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3757         }
3758         if (this.disabled) {
3759             cfg.cls += ' disabled';
3760         }
3761         
3762         if (this.href || this.html || this.glyphicon || this.icon) {
3763             cfg.cn = [
3764                 {
3765                     tag: this.tagtype,
3766                     href : this.href || "#",
3767                     html: this.html || ''
3768                 }
3769             ];
3770             
3771             if (this.icon) {
3772                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3773             }
3774
3775             if(this.glyphicon) {
3776                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3777             }
3778             
3779             if (this.menu) {
3780                 
3781                 cfg.cn[0].html += " <span class='caret'></span>";
3782              
3783             }
3784             
3785             if (this.badge !== '') {
3786                  
3787                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3788             }
3789         }
3790         
3791         
3792         
3793         return cfg;
3794     },
3795     initEvents: function() 
3796     {
3797         if (typeof (this.menu) != 'undefined') {
3798             this.menu.parentType = this.xtype;
3799             this.menu.triggerEl = this.el;
3800             this.menu = this.addxtype(Roo.apply({}, this.menu));
3801         }
3802         
3803         this.el.select('a',true).on('click', this.onClick, this);
3804         
3805         if(this.tagtype == 'span'){
3806             this.el.select('span',true).on('click', this.onClick, this);
3807         }
3808        
3809         // at this point parent should be available..
3810         this.parent().register(this);
3811     },
3812     
3813     onClick : function(e)
3814     {
3815         if(this.preventDefault || this.href == '#'){
3816             e.preventDefault();
3817         }
3818         
3819         if (this.disabled) {
3820             return;
3821         }
3822         
3823         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3824         if (tg && tg.transition) {
3825             Roo.log("waiting for the transitionend");
3826             return;
3827         }
3828         
3829         Roo.log("fire event clicked");
3830         if(this.fireEvent('click', this, e) === false){
3831             return;
3832         };
3833         
3834         if(this.tagtype == 'span'){
3835             return;
3836         }
3837         
3838         var p = this.parent();
3839         if (['tabs','pills'].indexOf(p.type)!==-1) {
3840             if (typeof(p.setActiveItem) !== 'undefined') {
3841                 p.setActiveItem(this);
3842             }
3843         }
3844         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3845         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3846             // remove the collapsed menu expand...
3847             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3848         }
3849         
3850     },
3851     
3852     isActive: function () {
3853         return this.active
3854     },
3855     setActive : function(state, fire, is_was_active)
3856     {
3857         if (this.active && !state & this.navId) {
3858             this.was_active = true;
3859             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3860             if (nv) {
3861                 nv.clearWasActive(this);
3862             }
3863             
3864         }
3865         this.active = state;
3866         
3867         if (!state ) {
3868             this.el.removeClass('active');
3869         } else if (!this.el.hasClass('active')) {
3870             this.el.addClass('active');
3871         }
3872         if (fire) {
3873             this.fireEvent('changed', this, state);
3874         }
3875         
3876         // show a panel if it's registered and related..
3877         
3878         if (!this.navId || !this.tabId || !state || is_was_active) {
3879             return;
3880         }
3881         
3882         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3883         if (!tg) {
3884             return;
3885         }
3886         var pan = tg.getPanelByName(this.tabId);
3887         if (!pan) {
3888             return;
3889         }
3890         // if we can not flip to new panel - go back to old nav highlight..
3891         if (false == tg.showPanel(pan)) {
3892             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3893             if (nv) {
3894                 var onav = nv.getWasActive();
3895                 if (onav) {
3896                     onav.setActive(true, false, true);
3897                 }
3898             }
3899             
3900         }
3901         
3902         
3903         
3904     },
3905      // this should not be here...
3906     setDisabled : function(state)
3907     {
3908         this.disabled = state;
3909         if (!state ) {
3910             this.el.removeClass('disabled');
3911         } else if (!this.el.hasClass('disabled')) {
3912             this.el.addClass('disabled');
3913         }
3914         
3915     },
3916     
3917     /**
3918      * Fetch the element to display the tooltip on.
3919      * @return {Roo.Element} defaults to this.el
3920      */
3921     tooltipEl : function()
3922     {
3923         return this.el.select('' + this.tagtype + '', true).first();
3924     }
3925 });
3926  
3927
3928  /*
3929  * - LGPL
3930  *
3931  * sidebar item
3932  *
3933  *  li
3934  *    <span> icon </span>
3935  *    <span> text </span>
3936  *    <span>badge </span>
3937  */
3938
3939 /**
3940  * @class Roo.bootstrap.NavSidebarItem
3941  * @extends Roo.bootstrap.NavItem
3942  * Bootstrap Navbar.NavSidebarItem class
3943  * @constructor
3944  * Create a new Navbar Button
3945  * @param {Object} config The config object
3946  */
3947 Roo.bootstrap.NavSidebarItem = function(config){
3948     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3949     this.addEvents({
3950         // raw events
3951         /**
3952          * @event click
3953          * The raw click event for the entire grid.
3954          * @param {Roo.EventObject} e
3955          */
3956         "click" : true,
3957          /**
3958             * @event changed
3959             * Fires when the active item active state changes
3960             * @param {Roo.bootstrap.NavSidebarItem} this
3961             * @param {boolean} state the new state
3962              
3963          */
3964         'changed': true
3965     });
3966    
3967 };
3968
3969 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
3970     
3971     
3972     getAutoCreate : function(){
3973         
3974         
3975         var a = {
3976                 tag: 'a',
3977                 href : this.href || '#',
3978                 cls: '',
3979                 html : '',
3980                 cn : []
3981         };
3982         var cfg = {
3983             tag: 'li',
3984             cls: '',
3985             cn: [ a ]
3986         }
3987         var span = {
3988             tag: 'span',
3989             html : this.html || ''
3990         }
3991         
3992         
3993         if (this.active) {
3994             cfg.cls += ' active';
3995         }
3996         
3997         // left icon..
3998         if (this.glyphicon || this.icon) {
3999             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4000             a.cn.push({ tag : 'i', cls : c }) ;
4001         }
4002         // html..
4003         a.cn.push(span);
4004         // then badge..
4005         if (this.badge !== '') {
4006             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4007         }
4008         // fi
4009         if (this.menu) {
4010             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4011             a.cls += 'dropdown-toggle treeview' ;
4012             
4013         }
4014         
4015         
4016         
4017         return cfg;
4018          
4019            
4020     }
4021    
4022      
4023  
4024 });
4025  
4026
4027  /*
4028  * - LGPL
4029  *
4030  * row
4031  * 
4032  */
4033
4034 /**
4035  * @class Roo.bootstrap.Row
4036  * @extends Roo.bootstrap.Component
4037  * Bootstrap Row class (contains columns...)
4038  * 
4039  * @constructor
4040  * Create a new Row
4041  * @param {Object} config The config object
4042  */
4043
4044 Roo.bootstrap.Row = function(config){
4045     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4046 };
4047
4048 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4049     
4050     getAutoCreate : function(){
4051        return {
4052             cls: 'row clearfix'
4053        };
4054     }
4055     
4056     
4057 });
4058
4059  
4060
4061  /*
4062  * - LGPL
4063  *
4064  * element
4065  * 
4066  */
4067
4068 /**
4069  * @class Roo.bootstrap.Element
4070  * @extends Roo.bootstrap.Component
4071  * Bootstrap Element class
4072  * @cfg {String} html contents of the element
4073  * @cfg {String} tag tag of the element
4074  * @cfg {String} cls class of the element
4075  * 
4076  * @constructor
4077  * Create a new Element
4078  * @param {Object} config The config object
4079  */
4080
4081 Roo.bootstrap.Element = function(config){
4082     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4083 };
4084
4085 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4086     
4087     tag: 'div',
4088     cls: '',
4089     html: '',
4090      
4091     
4092     getAutoCreate : function(){
4093         
4094         var cfg = {
4095             tag: this.tag,
4096             cls: this.cls,
4097             html: this.html
4098         }
4099         
4100         
4101         
4102         return cfg;
4103     }
4104    
4105 });
4106
4107  
4108
4109  /*
4110  * - LGPL
4111  *
4112  * pagination
4113  * 
4114  */
4115
4116 /**
4117  * @class Roo.bootstrap.Pagination
4118  * @extends Roo.bootstrap.Component
4119  * Bootstrap Pagination class
4120  * @cfg {String} size xs | sm | md | lg
4121  * @cfg {Boolean} inverse false | true
4122  * 
4123  * @constructor
4124  * Create a new Pagination
4125  * @param {Object} config The config object
4126  */
4127
4128 Roo.bootstrap.Pagination = function(config){
4129     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4130 };
4131
4132 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4133     
4134     cls: false,
4135     size: false,
4136     inverse: false,
4137     
4138     getAutoCreate : function(){
4139         var cfg = {
4140             tag: 'ul',
4141                 cls: 'pagination'
4142         };
4143         if (this.inverse) {
4144             cfg.cls += ' inverse';
4145         }
4146         if (this.html) {
4147             cfg.html=this.html;
4148         }
4149         if (this.cls) {
4150             cfg.cls += " " + this.cls;
4151         }
4152         return cfg;
4153     }
4154    
4155 });
4156
4157  
4158
4159  /*
4160  * - LGPL
4161  *
4162  * Pagination item
4163  * 
4164  */
4165
4166
4167 /**
4168  * @class Roo.bootstrap.PaginationItem
4169  * @extends Roo.bootstrap.Component
4170  * Bootstrap PaginationItem class
4171  * @cfg {String} html text
4172  * @cfg {String} href the link
4173  * @cfg {Boolean} preventDefault (true | false) default true
4174  * @cfg {Boolean} active (true | false) default false
4175  * @cfg {Boolean} disabled default false
4176  * 
4177  * 
4178  * @constructor
4179  * Create a new PaginationItem
4180  * @param {Object} config The config object
4181  */
4182
4183
4184 Roo.bootstrap.PaginationItem = function(config){
4185     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4186     this.addEvents({
4187         // raw events
4188         /**
4189          * @event click
4190          * The raw click event for the entire grid.
4191          * @param {Roo.EventObject} e
4192          */
4193         "click" : true
4194     });
4195 };
4196
4197 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4198     
4199     href : false,
4200     html : false,
4201     preventDefault: true,
4202     active : false,
4203     cls : false,
4204     disabled: false,
4205     
4206     getAutoCreate : function(){
4207         var cfg= {
4208             tag: 'li',
4209             cn: [
4210                 {
4211                     tag : 'a',
4212                     href : this.href ? this.href : '#',
4213                     html : this.html ? this.html : ''
4214                 }
4215             ]
4216         };
4217         
4218         if(this.cls){
4219             cfg.cls = this.cls;
4220         }
4221         
4222         if(this.disabled){
4223             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4224         }
4225         
4226         if(this.active){
4227             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4228         }
4229         
4230         return cfg;
4231     },
4232     
4233     initEvents: function() {
4234         
4235         this.el.on('click', this.onClick, this);
4236         
4237     },
4238     onClick : function(e)
4239     {
4240         Roo.log('PaginationItem on click ');
4241         if(this.preventDefault){
4242             e.preventDefault();
4243         }
4244         
4245         if(this.disabled){
4246             return;
4247         }
4248         
4249         this.fireEvent('click', this, e);
4250     }
4251    
4252 });
4253
4254  
4255
4256  /*
4257  * - LGPL
4258  *
4259  * slider
4260  * 
4261  */
4262
4263
4264 /**
4265  * @class Roo.bootstrap.Slider
4266  * @extends Roo.bootstrap.Component
4267  * Bootstrap Slider class
4268  *    
4269  * @constructor
4270  * Create a new Slider
4271  * @param {Object} config The config object
4272  */
4273
4274 Roo.bootstrap.Slider = function(config){
4275     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4276 };
4277
4278 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4279     
4280     getAutoCreate : function(){
4281         
4282         var cfg = {
4283             tag: 'div',
4284             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4285             cn: [
4286                 {
4287                     tag: 'a',
4288                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4289                 }
4290             ]
4291         }
4292         
4293         return cfg;
4294     }
4295    
4296 });
4297
4298  /*
4299  * Based on:
4300  * Ext JS Library 1.1.1
4301  * Copyright(c) 2006-2007, Ext JS, LLC.
4302  *
4303  * Originally Released Under LGPL - original licence link has changed is not relivant.
4304  *
4305  * Fork - LGPL
4306  * <script type="text/javascript">
4307  */
4308  
4309
4310 /**
4311  * @class Roo.grid.ColumnModel
4312  * @extends Roo.util.Observable
4313  * This is the default implementation of a ColumnModel used by the Grid. It defines
4314  * the columns in the grid.
4315  * <br>Usage:<br>
4316  <pre><code>
4317  var colModel = new Roo.grid.ColumnModel([
4318         {header: "Ticker", width: 60, sortable: true, locked: true},
4319         {header: "Company Name", width: 150, sortable: true},
4320         {header: "Market Cap.", width: 100, sortable: true},
4321         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4322         {header: "Employees", width: 100, sortable: true, resizable: false}
4323  ]);
4324  </code></pre>
4325  * <p>
4326  
4327  * The config options listed for this class are options which may appear in each
4328  * individual column definition.
4329  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4330  * @constructor
4331  * @param {Object} config An Array of column config objects. See this class's
4332  * config objects for details.
4333 */
4334 Roo.grid.ColumnModel = function(config){
4335         /**
4336      * The config passed into the constructor
4337      */
4338     this.config = config;
4339     this.lookup = {};
4340
4341     // if no id, create one
4342     // if the column does not have a dataIndex mapping,
4343     // map it to the order it is in the config
4344     for(var i = 0, len = config.length; i < len; i++){
4345         var c = config[i];
4346         if(typeof c.dataIndex == "undefined"){
4347             c.dataIndex = i;
4348         }
4349         if(typeof c.renderer == "string"){
4350             c.renderer = Roo.util.Format[c.renderer];
4351         }
4352         if(typeof c.id == "undefined"){
4353             c.id = Roo.id();
4354         }
4355         if(c.editor && c.editor.xtype){
4356             c.editor  = Roo.factory(c.editor, Roo.grid);
4357         }
4358         if(c.editor && c.editor.isFormField){
4359             c.editor = new Roo.grid.GridEditor(c.editor);
4360         }
4361         this.lookup[c.id] = c;
4362     }
4363
4364     /**
4365      * The width of columns which have no width specified (defaults to 100)
4366      * @type Number
4367      */
4368     this.defaultWidth = 100;
4369
4370     /**
4371      * Default sortable of columns which have no sortable specified (defaults to false)
4372      * @type Boolean
4373      */
4374     this.defaultSortable = false;
4375
4376     this.addEvents({
4377         /**
4378              * @event widthchange
4379              * Fires when the width of a column changes.
4380              * @param {ColumnModel} this
4381              * @param {Number} columnIndex The column index
4382              * @param {Number} newWidth The new width
4383              */
4384             "widthchange": true,
4385         /**
4386              * @event headerchange
4387              * Fires when the text of a header changes.
4388              * @param {ColumnModel} this
4389              * @param {Number} columnIndex The column index
4390              * @param {Number} newText The new header text
4391              */
4392             "headerchange": true,
4393         /**
4394              * @event hiddenchange
4395              * Fires when a column is hidden or "unhidden".
4396              * @param {ColumnModel} this
4397              * @param {Number} columnIndex The column index
4398              * @param {Boolean} hidden true if hidden, false otherwise
4399              */
4400             "hiddenchange": true,
4401             /**
4402          * @event columnmoved
4403          * Fires when a column is moved.
4404          * @param {ColumnModel} this
4405          * @param {Number} oldIndex
4406          * @param {Number} newIndex
4407          */
4408         "columnmoved" : true,
4409         /**
4410          * @event columlockchange
4411          * Fires when a column's locked state is changed
4412          * @param {ColumnModel} this
4413          * @param {Number} colIndex
4414          * @param {Boolean} locked true if locked
4415          */
4416         "columnlockchange" : true
4417     });
4418     Roo.grid.ColumnModel.superclass.constructor.call(this);
4419 };
4420 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4421     /**
4422      * @cfg {String} header The header text to display in the Grid view.
4423      */
4424     /**
4425      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4426      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4427      * specified, the column's index is used as an index into the Record's data Array.
4428      */
4429     /**
4430      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4431      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4432      */
4433     /**
4434      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4435      * Defaults to the value of the {@link #defaultSortable} property.
4436      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4437      */
4438     /**
4439      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4440      */
4441     /**
4442      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4443      */
4444     /**
4445      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4446      */
4447     /**
4448      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4449      */
4450     /**
4451      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4452      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4453      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4454      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4455      */
4456        /**
4457      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4458      */
4459     /**
4460      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4461      */
4462     /**
4463      * @cfg {String} cursor (Optional)
4464      */
4465     /**
4466      * @cfg {String} tooltip (Optional)
4467      */
4468     /**
4469      * Returns the id of the column at the specified index.
4470      * @param {Number} index The column index
4471      * @return {String} the id
4472      */
4473     getColumnId : function(index){
4474         return this.config[index].id;
4475     },
4476
4477     /**
4478      * Returns the column for a specified id.
4479      * @param {String} id The column id
4480      * @return {Object} the column
4481      */
4482     getColumnById : function(id){
4483         return this.lookup[id];
4484     },
4485
4486     
4487     /**
4488      * Returns the column for a specified dataIndex.
4489      * @param {String} dataIndex The column dataIndex
4490      * @return {Object|Boolean} the column or false if not found
4491      */
4492     getColumnByDataIndex: function(dataIndex){
4493         var index = this.findColumnIndex(dataIndex);
4494         return index > -1 ? this.config[index] : false;
4495     },
4496     
4497     /**
4498      * Returns the index for a specified column id.
4499      * @param {String} id The column id
4500      * @return {Number} the index, or -1 if not found
4501      */
4502     getIndexById : function(id){
4503         for(var i = 0, len = this.config.length; i < len; i++){
4504             if(this.config[i].id == id){
4505                 return i;
4506             }
4507         }
4508         return -1;
4509     },
4510     
4511     /**
4512      * Returns the index for a specified column dataIndex.
4513      * @param {String} dataIndex The column dataIndex
4514      * @return {Number} the index, or -1 if not found
4515      */
4516     
4517     findColumnIndex : function(dataIndex){
4518         for(var i = 0, len = this.config.length; i < len; i++){
4519             if(this.config[i].dataIndex == dataIndex){
4520                 return i;
4521             }
4522         }
4523         return -1;
4524     },
4525     
4526     
4527     moveColumn : function(oldIndex, newIndex){
4528         var c = this.config[oldIndex];
4529         this.config.splice(oldIndex, 1);
4530         this.config.splice(newIndex, 0, c);
4531         this.dataMap = null;
4532         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4533     },
4534
4535     isLocked : function(colIndex){
4536         return this.config[colIndex].locked === true;
4537     },
4538
4539     setLocked : function(colIndex, value, suppressEvent){
4540         if(this.isLocked(colIndex) == value){
4541             return;
4542         }
4543         this.config[colIndex].locked = value;
4544         if(!suppressEvent){
4545             this.fireEvent("columnlockchange", this, colIndex, value);
4546         }
4547     },
4548
4549     getTotalLockedWidth : function(){
4550         var totalWidth = 0;
4551         for(var i = 0; i < this.config.length; i++){
4552             if(this.isLocked(i) && !this.isHidden(i)){
4553                 this.totalWidth += this.getColumnWidth(i);
4554             }
4555         }
4556         return totalWidth;
4557     },
4558
4559     getLockedCount : function(){
4560         for(var i = 0, len = this.config.length; i < len; i++){
4561             if(!this.isLocked(i)){
4562                 return i;
4563             }
4564         }
4565     },
4566
4567     /**
4568      * Returns the number of columns.
4569      * @return {Number}
4570      */
4571     getColumnCount : function(visibleOnly){
4572         if(visibleOnly === true){
4573             var c = 0;
4574             for(var i = 0, len = this.config.length; i < len; i++){
4575                 if(!this.isHidden(i)){
4576                     c++;
4577                 }
4578             }
4579             return c;
4580         }
4581         return this.config.length;
4582     },
4583
4584     /**
4585      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4586      * @param {Function} fn
4587      * @param {Object} scope (optional)
4588      * @return {Array} result
4589      */
4590     getColumnsBy : function(fn, scope){
4591         var r = [];
4592         for(var i = 0, len = this.config.length; i < len; i++){
4593             var c = this.config[i];
4594             if(fn.call(scope||this, c, i) === true){
4595                 r[r.length] = c;
4596             }
4597         }
4598         return r;
4599     },
4600
4601     /**
4602      * Returns true if the specified column is sortable.
4603      * @param {Number} col The column index
4604      * @return {Boolean}
4605      */
4606     isSortable : function(col){
4607         if(typeof this.config[col].sortable == "undefined"){
4608             return this.defaultSortable;
4609         }
4610         return this.config[col].sortable;
4611     },
4612
4613     /**
4614      * Returns the rendering (formatting) function defined for the column.
4615      * @param {Number} col The column index.
4616      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4617      */
4618     getRenderer : function(col){
4619         if(!this.config[col].renderer){
4620             return Roo.grid.ColumnModel.defaultRenderer;
4621         }
4622         return this.config[col].renderer;
4623     },
4624
4625     /**
4626      * Sets the rendering (formatting) function for a column.
4627      * @param {Number} col The column index
4628      * @param {Function} fn The function to use to process the cell's raw data
4629      * to return HTML markup for the grid view. The render function is called with
4630      * the following parameters:<ul>
4631      * <li>Data value.</li>
4632      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4633      * <li>css A CSS style string to apply to the table cell.</li>
4634      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4635      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4636      * <li>Row index</li>
4637      * <li>Column index</li>
4638      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4639      */
4640     setRenderer : function(col, fn){
4641         this.config[col].renderer = fn;
4642     },
4643
4644     /**
4645      * Returns the width for the specified column.
4646      * @param {Number} col The column index
4647      * @return {Number}
4648      */
4649     getColumnWidth : function(col){
4650         return this.config[col].width * 1 || this.defaultWidth;
4651     },
4652
4653     /**
4654      * Sets the width for a column.
4655      * @param {Number} col The column index
4656      * @param {Number} width The new width
4657      */
4658     setColumnWidth : function(col, width, suppressEvent){
4659         this.config[col].width = width;
4660         this.totalWidth = null;
4661         if(!suppressEvent){
4662              this.fireEvent("widthchange", this, col, width);
4663         }
4664     },
4665
4666     /**
4667      * Returns the total width of all columns.
4668      * @param {Boolean} includeHidden True to include hidden column widths
4669      * @return {Number}
4670      */
4671     getTotalWidth : function(includeHidden){
4672         if(!this.totalWidth){
4673             this.totalWidth = 0;
4674             for(var i = 0, len = this.config.length; i < len; i++){
4675                 if(includeHidden || !this.isHidden(i)){
4676                     this.totalWidth += this.getColumnWidth(i);
4677                 }
4678             }
4679         }
4680         return this.totalWidth;
4681     },
4682
4683     /**
4684      * Returns the header for the specified column.
4685      * @param {Number} col The column index
4686      * @return {String}
4687      */
4688     getColumnHeader : function(col){
4689         return this.config[col].header;
4690     },
4691
4692     /**
4693      * Sets the header for a column.
4694      * @param {Number} col The column index
4695      * @param {String} header The new header
4696      */
4697     setColumnHeader : function(col, header){
4698         this.config[col].header = header;
4699         this.fireEvent("headerchange", this, col, header);
4700     },
4701
4702     /**
4703      * Returns the tooltip for the specified column.
4704      * @param {Number} col The column index
4705      * @return {String}
4706      */
4707     getColumnTooltip : function(col){
4708             return this.config[col].tooltip;
4709     },
4710     /**
4711      * Sets the tooltip for a column.
4712      * @param {Number} col The column index
4713      * @param {String} tooltip The new tooltip
4714      */
4715     setColumnTooltip : function(col, tooltip){
4716             this.config[col].tooltip = tooltip;
4717     },
4718
4719     /**
4720      * Returns the dataIndex for the specified column.
4721      * @param {Number} col The column index
4722      * @return {Number}
4723      */
4724     getDataIndex : function(col){
4725         return this.config[col].dataIndex;
4726     },
4727
4728     /**
4729      * Sets the dataIndex for a column.
4730      * @param {Number} col The column index
4731      * @param {Number} dataIndex The new dataIndex
4732      */
4733     setDataIndex : function(col, dataIndex){
4734         this.config[col].dataIndex = dataIndex;
4735     },
4736
4737     
4738     
4739     /**
4740      * Returns true if the cell is editable.
4741      * @param {Number} colIndex The column index
4742      * @param {Number} rowIndex The row index
4743      * @return {Boolean}
4744      */
4745     isCellEditable : function(colIndex, rowIndex){
4746         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4747     },
4748
4749     /**
4750      * Returns the editor defined for the cell/column.
4751      * return false or null to disable editing.
4752      * @param {Number} colIndex The column index
4753      * @param {Number} rowIndex The row index
4754      * @return {Object}
4755      */
4756     getCellEditor : function(colIndex, rowIndex){
4757         return this.config[colIndex].editor;
4758     },
4759
4760     /**
4761      * Sets if a column is editable.
4762      * @param {Number} col The column index
4763      * @param {Boolean} editable True if the column is editable
4764      */
4765     setEditable : function(col, editable){
4766         this.config[col].editable = editable;
4767     },
4768
4769
4770     /**
4771      * Returns true if the column is hidden.
4772      * @param {Number} colIndex The column index
4773      * @return {Boolean}
4774      */
4775     isHidden : function(colIndex){
4776         return this.config[colIndex].hidden;
4777     },
4778
4779
4780     /**
4781      * Returns true if the column width cannot be changed
4782      */
4783     isFixed : function(colIndex){
4784         return this.config[colIndex].fixed;
4785     },
4786
4787     /**
4788      * Returns true if the column can be resized
4789      * @return {Boolean}
4790      */
4791     isResizable : function(colIndex){
4792         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4793     },
4794     /**
4795      * Sets if a column is hidden.
4796      * @param {Number} colIndex The column index
4797      * @param {Boolean} hidden True if the column is hidden
4798      */
4799     setHidden : function(colIndex, hidden){
4800         this.config[colIndex].hidden = hidden;
4801         this.totalWidth = null;
4802         this.fireEvent("hiddenchange", this, colIndex, hidden);
4803     },
4804
4805     /**
4806      * Sets the editor for a column.
4807      * @param {Number} col The column index
4808      * @param {Object} editor The editor object
4809      */
4810     setEditor : function(col, editor){
4811         this.config[col].editor = editor;
4812     }
4813 });
4814
4815 Roo.grid.ColumnModel.defaultRenderer = function(value){
4816         if(typeof value == "string" && value.length < 1){
4817             return "&#160;";
4818         }
4819         return value;
4820 };
4821
4822 // Alias for backwards compatibility
4823 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4824 /*
4825  * Based on:
4826  * Ext JS Library 1.1.1
4827  * Copyright(c) 2006-2007, Ext JS, LLC.
4828  *
4829  * Originally Released Under LGPL - original licence link has changed is not relivant.
4830  *
4831  * Fork - LGPL
4832  * <script type="text/javascript">
4833  */
4834  
4835 /**
4836  * @class Roo.LoadMask
4837  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4838  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4839  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4840  * element's UpdateManager load indicator and will be destroyed after the initial load.
4841  * @constructor
4842  * Create a new LoadMask
4843  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4844  * @param {Object} config The config object
4845  */
4846 Roo.LoadMask = function(el, config){
4847     this.el = Roo.get(el);
4848     Roo.apply(this, config);
4849     if(this.store){
4850         this.store.on('beforeload', this.onBeforeLoad, this);
4851         this.store.on('load', this.onLoad, this);
4852         this.store.on('loadexception', this.onLoadException, this);
4853         this.removeMask = false;
4854     }else{
4855         var um = this.el.getUpdateManager();
4856         um.showLoadIndicator = false; // disable the default indicator
4857         um.on('beforeupdate', this.onBeforeLoad, this);
4858         um.on('update', this.onLoad, this);
4859         um.on('failure', this.onLoad, this);
4860         this.removeMask = true;
4861     }
4862 };
4863
4864 Roo.LoadMask.prototype = {
4865     /**
4866      * @cfg {Boolean} removeMask
4867      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4868      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4869      */
4870     /**
4871      * @cfg {String} msg
4872      * The text to display in a centered loading message box (defaults to 'Loading...')
4873      */
4874     msg : 'Loading...',
4875     /**
4876      * @cfg {String} msgCls
4877      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4878      */
4879     msgCls : 'x-mask-loading',
4880
4881     /**
4882      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4883      * @type Boolean
4884      */
4885     disabled: false,
4886
4887     /**
4888      * Disables the mask to prevent it from being displayed
4889      */
4890     disable : function(){
4891        this.disabled = true;
4892     },
4893
4894     /**
4895      * Enables the mask so that it can be displayed
4896      */
4897     enable : function(){
4898         this.disabled = false;
4899     },
4900     
4901     onLoadException : function()
4902     {
4903         Roo.log(arguments);
4904         
4905         if (typeof(arguments[3]) != 'undefined') {
4906             Roo.MessageBox.alert("Error loading",arguments[3]);
4907         } 
4908         /*
4909         try {
4910             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4911                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4912             }   
4913         } catch(e) {
4914             
4915         }
4916         */
4917     
4918         
4919         
4920         this.el.unmask(this.removeMask);
4921     },
4922     // private
4923     onLoad : function()
4924     {
4925         this.el.unmask(this.removeMask);
4926     },
4927
4928     // private
4929     onBeforeLoad : function(){
4930         if(!this.disabled){
4931             this.el.mask(this.msg, this.msgCls);
4932         }
4933     },
4934
4935     // private
4936     destroy : function(){
4937         if(this.store){
4938             this.store.un('beforeload', this.onBeforeLoad, this);
4939             this.store.un('load', this.onLoad, this);
4940             this.store.un('loadexception', this.onLoadException, this);
4941         }else{
4942             var um = this.el.getUpdateManager();
4943             um.un('beforeupdate', this.onBeforeLoad, this);
4944             um.un('update', this.onLoad, this);
4945             um.un('failure', this.onLoad, this);
4946         }
4947     }
4948 };/*
4949  * - LGPL
4950  *
4951  * table
4952  * 
4953  */
4954
4955 /**
4956  * @class Roo.bootstrap.Table
4957  * @extends Roo.bootstrap.Component
4958  * Bootstrap Table class
4959  * @cfg {String} cls table class
4960  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4961  * @cfg {String} bgcolor Specifies the background color for a table
4962  * @cfg {Number} border Specifies whether the table cells should have borders or not
4963  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4964  * @cfg {Number} cellspacing Specifies the space between cells
4965  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4966  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4967  * @cfg {String} sortable Specifies that the table should be sortable
4968  * @cfg {String} summary Specifies a summary of the content of a table
4969  * @cfg {Number} width Specifies the width of a table
4970  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4971  * 
4972  * @cfg {boolean} striped Should the rows be alternative striped
4973  * @cfg {boolean} bordered Add borders to the table
4974  * @cfg {boolean} hover Add hover highlighting
4975  * @cfg {boolean} condensed Format condensed
4976  * @cfg {boolean} responsive Format condensed
4977  * @cfg {Boolean} loadMask (true|false) default false
4978  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4979  * @cfg {Boolean} thead (true|false) generate thead, default true
4980  * @cfg {Boolean} RowSelection (true|false) default false
4981  * @cfg {Boolean} CellSelection (true|false) default false
4982  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
4983  
4984  * 
4985  * @constructor
4986  * Create a new Table
4987  * @param {Object} config The config object
4988  */
4989
4990 Roo.bootstrap.Table = function(config){
4991     Roo.bootstrap.Table.superclass.constructor.call(this, config);
4992     
4993     if (this.sm) {
4994         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4995         this.sm = this.selModel;
4996         this.sm.xmodule = this.xmodule || false;
4997     }
4998     if (this.cm && typeof(this.cm.config) == 'undefined') {
4999         this.colModel = new Roo.grid.ColumnModel(this.cm);
5000         this.cm = this.colModel;
5001         this.cm.xmodule = this.xmodule || false;
5002     }
5003     if (this.store) {
5004         this.store= Roo.factory(this.store, Roo.data);
5005         this.ds = this.store;
5006         this.ds.xmodule = this.xmodule || false;
5007          
5008     }
5009     if (this.footer && this.store) {
5010         this.footer.dataSource = this.ds;
5011         this.footer = Roo.factory(this.footer);
5012     }
5013     
5014     /** @private */
5015     this.addEvents({
5016         /**
5017          * @event cellclick
5018          * Fires when a cell is clicked
5019          * @param {Roo.bootstrap.Table} this
5020          * @param {Roo.Element} el
5021          * @param {Number} rowIndex
5022          * @param {Number} columnIndex
5023          * @param {Roo.EventObject} e
5024          */
5025         "cellclick" : true,
5026         /**
5027          * @event celldblclick
5028          * Fires when a cell is double clicked
5029          * @param {Roo.bootstrap.Table} this
5030          * @param {Roo.Element} el
5031          * @param {Number} rowIndex
5032          * @param {Number} columnIndex
5033          * @param {Roo.EventObject} e
5034          */
5035         "celldblclick" : true,
5036         /**
5037          * @event rowclick
5038          * Fires when a row is clicked
5039          * @param {Roo.bootstrap.Table} this
5040          * @param {Roo.Element} el
5041          * @param {Number} rowIndex
5042          * @param {Roo.EventObject} e
5043          */
5044         "rowclick" : true,
5045         /**
5046          * @event rowdblclick
5047          * Fires when a row is double clicked
5048          * @param {Roo.bootstrap.Table} this
5049          * @param {Roo.Element} el
5050          * @param {Number} rowIndex
5051          * @param {Roo.EventObject} e
5052          */
5053         "rowdblclick" : true,
5054         /**
5055          * @event mouseover
5056          * Fires when a mouseover occur
5057          * @param {Roo.bootstrap.Table} this
5058          * @param {Roo.Element} el
5059          * @param {Number} rowIndex
5060          * @param {Number} columnIndex
5061          * @param {Roo.EventObject} e
5062          */
5063         "mouseover" : true,
5064         /**
5065          * @event mouseout
5066          * Fires when a mouseout occur
5067          * @param {Roo.bootstrap.Table} this
5068          * @param {Roo.Element} el
5069          * @param {Number} rowIndex
5070          * @param {Number} columnIndex
5071          * @param {Roo.EventObject} e
5072          */
5073         "mouseout" : true,
5074         /**
5075          * @event rowclass
5076          * Fires when a row is rendered, so you can change add a style to it.
5077          * @param {Roo.bootstrap.Table} this
5078          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5079          */
5080         'rowclass' : true,
5081           /**
5082          * @event rowsrendered
5083          * Fires when all the  rows have been rendered
5084          * @param {Roo.bootstrap.Table} this
5085          */
5086         'rowsrendered' : true
5087         
5088     });
5089 };
5090
5091 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5092     
5093     cls: false,
5094     align: false,
5095     bgcolor: false,
5096     border: false,
5097     cellpadding: false,
5098     cellspacing: false,
5099     frame: false,
5100     rules: false,
5101     sortable: false,
5102     summary: false,
5103     width: false,
5104     striped : false,
5105     bordered: false,
5106     hover:  false,
5107     condensed : false,
5108     responsive : false,
5109     sm : false,
5110     cm : false,
5111     store : false,
5112     loadMask : false,
5113     tfoot : true,
5114     thead : true,
5115     RowSelection : false,
5116     CellSelection : false,
5117     layout : false,
5118     
5119     // Roo.Element - the tbody
5120     mainBody: false, 
5121     
5122     getAutoCreate : function(){
5123         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5124         
5125         cfg = {
5126             tag: 'table',
5127             cls : 'table',
5128             cn : []
5129         }
5130             
5131         if (this.striped) {
5132             cfg.cls += ' table-striped';
5133         }
5134         
5135         if (this.hover) {
5136             cfg.cls += ' table-hover';
5137         }
5138         if (this.bordered) {
5139             cfg.cls += ' table-bordered';
5140         }
5141         if (this.condensed) {
5142             cfg.cls += ' table-condensed';
5143         }
5144         if (this.responsive) {
5145             cfg.cls += ' table-responsive';
5146         }
5147         
5148         if (this.cls) {
5149             cfg.cls+=  ' ' +this.cls;
5150         }
5151         
5152         // this lot should be simplifed...
5153         
5154         if (this.align) {
5155             cfg.align=this.align;
5156         }
5157         if (this.bgcolor) {
5158             cfg.bgcolor=this.bgcolor;
5159         }
5160         if (this.border) {
5161             cfg.border=this.border;
5162         }
5163         if (this.cellpadding) {
5164             cfg.cellpadding=this.cellpadding;
5165         }
5166         if (this.cellspacing) {
5167             cfg.cellspacing=this.cellspacing;
5168         }
5169         if (this.frame) {
5170             cfg.frame=this.frame;
5171         }
5172         if (this.rules) {
5173             cfg.rules=this.rules;
5174         }
5175         if (this.sortable) {
5176             cfg.sortable=this.sortable;
5177         }
5178         if (this.summary) {
5179             cfg.summary=this.summary;
5180         }
5181         if (this.width) {
5182             cfg.width=this.width;
5183         }
5184         if (this.layout) {
5185             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5186         }
5187         
5188         if(this.store || this.cm){
5189             if(this.thead){
5190                 cfg.cn.push(this.renderHeader());
5191             }
5192             
5193             cfg.cn.push(this.renderBody());
5194             
5195             if(this.tfoot){
5196                 cfg.cn.push(this.renderFooter());
5197             }
5198             
5199             cfg.cls+=  ' TableGrid';
5200         }
5201         
5202         return { cn : [ cfg ] };
5203     },
5204     
5205     initEvents : function()
5206     {   
5207         if(!this.store || !this.cm){
5208             return;
5209         }
5210         
5211         //Roo.log('initEvents with ds!!!!');
5212         
5213         this.mainBody = this.el.select('tbody', true).first();
5214         
5215         
5216         var _this = this;
5217         
5218         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5219             e.on('click', _this.sort, _this);
5220         });
5221         
5222         this.el.on("click", this.onClick, this);
5223         this.el.on("dblclick", this.onDblClick, this);
5224         
5225         // why is this done????? = it breaks dialogs??
5226         //this.parent().el.setStyle('position', 'relative');
5227         
5228         
5229         if (this.footer) {
5230             this.footer.parentId = this.id;
5231             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5232         }
5233         
5234         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5235         
5236         this.store.on('load', this.onLoad, this);
5237         this.store.on('beforeload', this.onBeforeLoad, this);
5238         this.store.on('update', this.onUpdate, this);
5239         this.store.on('add', this.onAdd, this);
5240         
5241     },
5242     
5243     onMouseover : function(e, el)
5244     {
5245         var cell = Roo.get(el);
5246         
5247         if(!cell){
5248             return;
5249         }
5250         
5251         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5252             cell = cell.findParent('td', false, true);
5253         }
5254         
5255         var row = cell.findParent('tr', false, true);
5256         var cellIndex = cell.dom.cellIndex;
5257         var rowIndex = row.dom.rowIndex - 1; // start from 0
5258         
5259         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5260         
5261     },
5262     
5263     onMouseout : function(e, el)
5264     {
5265         var cell = Roo.get(el);
5266         
5267         if(!cell){
5268             return;
5269         }
5270         
5271         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5272             cell = cell.findParent('td', false, true);
5273         }
5274         
5275         var row = cell.findParent('tr', false, true);
5276         var cellIndex = cell.dom.cellIndex;
5277         var rowIndex = row.dom.rowIndex - 1; // start from 0
5278         
5279         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5280         
5281     },
5282     
5283     onClick : function(e, el)
5284     {
5285         var cell = Roo.get(el);
5286         
5287         if(!cell || (!this.CellSelection && !this.RowSelection)){
5288             return;
5289         }
5290         
5291         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5292             cell = cell.findParent('td', false, true);
5293         }
5294         
5295         if(!cell || typeof(cell) == 'undefined'){
5296             return;
5297         }
5298         
5299         var row = cell.findParent('tr', false, true);
5300         
5301         if(!row || typeof(row) == 'undefined'){
5302             return;
5303         }
5304         
5305         var cellIndex = cell.dom.cellIndex;
5306         var rowIndex = this.getRowIndex(row);
5307         
5308         if(this.CellSelection){
5309             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5310         }
5311         
5312         if(this.RowSelection){
5313             this.fireEvent('rowclick', this, row, rowIndex, e);
5314         }
5315         
5316         
5317     },
5318     
5319     onDblClick : function(e,el)
5320     {
5321         var cell = Roo.get(el);
5322         
5323         if(!cell || (!this.CellSelection && !this.RowSelection)){
5324             return;
5325         }
5326         
5327         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5328             cell = cell.findParent('td', false, true);
5329         }
5330         
5331         if(!cell || typeof(cell) == 'undefined'){
5332             return;
5333         }
5334         
5335         var row = cell.findParent('tr', false, true);
5336         
5337         if(!row || typeof(row) == 'undefined'){
5338             return;
5339         }
5340         
5341         var cellIndex = cell.dom.cellIndex;
5342         var rowIndex = this.getRowIndex(row);
5343         
5344         if(this.CellSelection){
5345             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5346         }
5347         
5348         if(this.RowSelection){
5349             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5350         }
5351     },
5352     
5353     sort : function(e,el)
5354     {
5355         var col = Roo.get(el);
5356         
5357         if(!col.hasClass('sortable')){
5358             return;
5359         }
5360         
5361         var sort = col.attr('sort');
5362         var dir = 'ASC';
5363         
5364         if(col.hasClass('glyphicon-arrow-up')){
5365             dir = 'DESC';
5366         }
5367         
5368         this.store.sortInfo = {field : sort, direction : dir};
5369         
5370         if (this.footer) {
5371             Roo.log("calling footer first");
5372             this.footer.onClick('first');
5373         } else {
5374         
5375             this.store.load({ params : { start : 0 } });
5376         }
5377     },
5378     
5379     renderHeader : function()
5380     {
5381         var header = {
5382             tag: 'thead',
5383             cn : []
5384         };
5385         
5386         var cm = this.cm;
5387         
5388         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5389             
5390             var config = cm.config[i];
5391                     
5392             var c = {
5393                 tag: 'th',
5394                 style : '',
5395                 html: cm.getColumnHeader(i)
5396             };
5397             
5398             if(typeof(config.tooltip) != 'undefined'){
5399                 c.tooltip = config.tooltip;
5400             }
5401             
5402             if(typeof(config.hidden) != 'undefined' && config.hidden){
5403                 c.style += ' display:none;';
5404             }
5405             
5406             if(typeof(config.dataIndex) != 'undefined'){
5407                 c.sort = config.dataIndex;
5408             }
5409             
5410             if(typeof(config.sortable) != 'undefined' && config.sortable){
5411                 c.cls = 'sortable';
5412             }
5413             
5414             if(typeof(config.align) != 'undefined' && config.align.length){
5415                 c.style += ' text-align:' + config.align + ';';
5416             }
5417             
5418             if(typeof(config.width) != 'undefined'){
5419                 c.style += ' width:' + config.width + 'px;';
5420             }
5421             
5422             header.cn.push(c)
5423         }
5424         
5425         return header;
5426     },
5427     
5428     renderBody : function()
5429     {
5430         var body = {
5431             tag: 'tbody',
5432             cn : [
5433                 {
5434                     tag: 'tr',
5435                     cn : [
5436                         {
5437                             tag : 'td',
5438                             colspan :  this.cm.getColumnCount()
5439                         }
5440                     ]
5441                 }
5442             ]
5443         };
5444         
5445         return body;
5446     },
5447     
5448     renderFooter : function()
5449     {
5450         var footer = {
5451             tag: 'tfoot',
5452             cn : [
5453                 {
5454                     tag: 'tr',
5455                     cn : [
5456                         {
5457                             tag : 'td',
5458                             colspan :  this.cm.getColumnCount()
5459                         }
5460                     ]
5461                 }
5462             ]
5463         };
5464         
5465         return footer;
5466     },
5467     
5468     
5469     
5470     onLoad : function()
5471     {
5472         Roo.log('ds onload');
5473         this.clear();
5474         
5475         var _this = this;
5476         var cm = this.cm;
5477         var ds = this.store;
5478         
5479         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5480             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5481             
5482             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5483                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5484             }
5485             
5486             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5487                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5488             }
5489         });
5490         
5491         var tbody =  this.mainBody;
5492               
5493         if(ds.getCount() > 0){
5494             ds.data.each(function(d,rowIndex){
5495                 var row =  this.renderRow(cm, ds, rowIndex);
5496                 
5497                 tbody.createChild(row);
5498                 
5499                 var _this = this;
5500                 
5501                 if(row.cellObjects.length){
5502                     Roo.each(row.cellObjects, function(r){
5503                         _this.renderCellObject(r);
5504                     })
5505                 }
5506                 
5507             }, this);
5508         }
5509         
5510         Roo.each(this.el.select('tbody td', true).elements, function(e){
5511             e.on('mouseover', _this.onMouseover, _this);
5512         });
5513         
5514         Roo.each(this.el.select('tbody td', true).elements, function(e){
5515             e.on('mouseout', _this.onMouseout, _this);
5516         });
5517         this.fireEvent('rowsrendered', this);
5518         //if(this.loadMask){
5519         //    this.maskEl.hide();
5520         //}
5521     },
5522     
5523     
5524     onUpdate : function(ds,record)
5525     {
5526         this.refreshRow(record);
5527     },
5528     
5529     onRemove : function(ds, record, index, isUpdate){
5530         if(isUpdate !== true){
5531             this.fireEvent("beforerowremoved", this, index, record);
5532         }
5533         var bt = this.mainBody.dom;
5534         
5535         var rows = this.el.select('tbody > tr', true).elements;
5536         
5537         if(typeof(rows[index]) != 'undefined'){
5538             bt.removeChild(rows[index].dom);
5539         }
5540         
5541 //        if(bt.rows[index]){
5542 //            bt.removeChild(bt.rows[index]);
5543 //        }
5544         
5545         if(isUpdate !== true){
5546             //this.stripeRows(index);
5547             //this.syncRowHeights(index, index);
5548             //this.layout();
5549             this.fireEvent("rowremoved", this, index, record);
5550         }
5551     },
5552     
5553     onAdd : function(ds, records, rowIndex)
5554     {
5555         //Roo.log('on Add called');
5556         // - note this does not handle multiple adding very well..
5557         var bt = this.mainBody.dom;
5558         for (var i =0 ; i < records.length;i++) {
5559             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5560             //Roo.log(records[i]);
5561             //Roo.log(this.store.getAt(rowIndex+i));
5562             this.insertRow(this.store, rowIndex + i, false);
5563             return;
5564         }
5565         
5566     },
5567     
5568     
5569     refreshRow : function(record){
5570         var ds = this.store, index;
5571         if(typeof record == 'number'){
5572             index = record;
5573             record = ds.getAt(index);
5574         }else{
5575             index = ds.indexOf(record);
5576         }
5577         this.insertRow(ds, index, true);
5578         this.onRemove(ds, record, index+1, true);
5579         //this.syncRowHeights(index, index);
5580         //this.layout();
5581         this.fireEvent("rowupdated", this, index, record);
5582     },
5583     
5584     insertRow : function(dm, rowIndex, isUpdate){
5585         
5586         if(!isUpdate){
5587             this.fireEvent("beforerowsinserted", this, rowIndex);
5588         }
5589             //var s = this.getScrollState();
5590         var row = this.renderRow(this.cm, this.store, rowIndex);
5591         // insert before rowIndex..
5592         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5593         
5594         var _this = this;
5595                 
5596         if(row.cellObjects.length){
5597             Roo.each(row.cellObjects, function(r){
5598                 _this.renderCellObject(r);
5599             })
5600         }
5601             
5602         if(!isUpdate){
5603             this.fireEvent("rowsinserted", this, rowIndex);
5604             //this.syncRowHeights(firstRow, lastRow);
5605             //this.stripeRows(firstRow);
5606             //this.layout();
5607         }
5608         
5609     },
5610     
5611     
5612     getRowDom : function(rowIndex)
5613     {
5614         var rows = this.el.select('tbody > tr', true).elements;
5615         
5616         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5617         
5618     },
5619     // returns the object tree for a tr..
5620   
5621     
5622     renderRow : function(cm, ds, rowIndex) 
5623     {
5624         
5625         var d = ds.getAt(rowIndex);
5626         
5627         var row = {
5628             tag : 'tr',
5629             cn : []
5630         };
5631             
5632         var cellObjects = [];
5633         
5634         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5635             var config = cm.config[i];
5636             
5637             var renderer = cm.getRenderer(i);
5638             var value = '';
5639             var id = false;
5640             
5641             if(typeof(renderer) !== 'undefined'){
5642                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5643             }
5644             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5645             // and are rendered into the cells after the row is rendered - using the id for the element.
5646             
5647             if(typeof(value) === 'object'){
5648                 id = Roo.id();
5649                 cellObjects.push({
5650                     container : id,
5651                     cfg : value 
5652                 })
5653             }
5654             
5655             var rowcfg = {
5656                 record: d,
5657                 rowIndex : rowIndex,
5658                 colIndex : i,
5659                 rowClass : ''
5660             }
5661
5662             this.fireEvent('rowclass', this, rowcfg);
5663             
5664             var td = {
5665                 tag: 'td',
5666                 cls : rowcfg.rowClass,
5667                 style: '',
5668                 html: (typeof(value) === 'object') ? '' : value
5669             };
5670             
5671             if (id) {
5672                 td.id = id;
5673             }
5674             
5675             if(typeof(config.hidden) != 'undefined' && config.hidden){
5676                 td.style += ' display:none;';
5677             }
5678             
5679             if(typeof(config.align) != 'undefined' && config.align.length){
5680                 td.style += ' text-align:' + config.align + ';';
5681             }
5682             
5683             if(typeof(config.width) != 'undefined'){
5684                 td.style += ' width:' +  config.width + 'px;';
5685             }
5686             
5687             if(typeof(config.cursor) != 'undefined'){
5688                 td.style += ' cursor:' +  config.cursor + ';';
5689             }
5690              
5691             row.cn.push(td);
5692            
5693         }
5694         
5695         row.cellObjects = cellObjects;
5696         
5697         return row;
5698           
5699     },
5700     
5701     
5702     
5703     onBeforeLoad : function()
5704     {
5705         //Roo.log('ds onBeforeLoad');
5706         
5707         //this.clear();
5708         
5709         //if(this.loadMask){
5710         //    this.maskEl.show();
5711         //}
5712     },
5713      /**
5714      * Remove all rows
5715      */
5716     clear : function()
5717     {
5718         this.el.select('tbody', true).first().dom.innerHTML = '';
5719     },
5720     /**
5721      * Show or hide a row.
5722      * @param {Number} rowIndex to show or hide
5723      * @param {Boolean} state hide
5724      */
5725     setRowVisibility : function(rowIndex, state)
5726     {
5727         var bt = this.mainBody.dom;
5728         
5729         var rows = this.el.select('tbody > tr', true).elements;
5730         
5731         if(typeof(rows[rowIndex]) == 'undefined'){
5732             return;
5733         }
5734         rows[rowIndex].dom.style.display = state ? '' : 'none';
5735     },
5736     
5737     
5738     getSelectionModel : function(){
5739         if(!this.selModel){
5740             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5741         }
5742         return this.selModel;
5743     },
5744     /*
5745      * Render the Roo.bootstrap object from renderder
5746      */
5747     renderCellObject : function(r)
5748     {
5749         var _this = this;
5750         
5751         var t = r.cfg.render(r.container);
5752         
5753         if(r.cfg.cn){
5754             Roo.each(r.cfg.cn, function(c){
5755                 var child = {
5756                     container: t.getChildContainer(),
5757                     cfg: c
5758                 }
5759                 _this.renderCellObject(child);
5760             })
5761         }
5762     },
5763     
5764     getRowIndex : function(row)
5765     {
5766         var rowIndex = -1;
5767         
5768         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5769             if(el != row){
5770                 return;
5771             }
5772             
5773             rowIndex = index;
5774         });
5775         
5776         return rowIndex;
5777     }
5778    
5779 });
5780
5781  
5782
5783  /*
5784  * - LGPL
5785  *
5786  * table cell
5787  * 
5788  */
5789
5790 /**
5791  * @class Roo.bootstrap.TableCell
5792  * @extends Roo.bootstrap.Component
5793  * Bootstrap TableCell class
5794  * @cfg {String} html cell contain text
5795  * @cfg {String} cls cell class
5796  * @cfg {String} tag cell tag (td|th) default td
5797  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5798  * @cfg {String} align Aligns the content in a cell
5799  * @cfg {String} axis Categorizes cells
5800  * @cfg {String} bgcolor Specifies the background color of a cell
5801  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5802  * @cfg {Number} colspan Specifies the number of columns a cell should span
5803  * @cfg {String} headers Specifies one or more header cells a cell is related to
5804  * @cfg {Number} height Sets the height of a cell
5805  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5806  * @cfg {Number} rowspan Sets the number of rows a cell should span
5807  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5808  * @cfg {String} valign Vertical aligns the content in a cell
5809  * @cfg {Number} width Specifies the width of a cell
5810  * 
5811  * @constructor
5812  * Create a new TableCell
5813  * @param {Object} config The config object
5814  */
5815
5816 Roo.bootstrap.TableCell = function(config){
5817     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5818 };
5819
5820 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5821     
5822     html: false,
5823     cls: false,
5824     tag: false,
5825     abbr: false,
5826     align: false,
5827     axis: false,
5828     bgcolor: false,
5829     charoff: false,
5830     colspan: false,
5831     headers: false,
5832     height: false,
5833     nowrap: false,
5834     rowspan: false,
5835     scope: false,
5836     valign: false,
5837     width: false,
5838     
5839     
5840     getAutoCreate : function(){
5841         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5842         
5843         cfg = {
5844             tag: 'td'
5845         }
5846         
5847         if(this.tag){
5848             cfg.tag = this.tag;
5849         }
5850         
5851         if (this.html) {
5852             cfg.html=this.html
5853         }
5854         if (this.cls) {
5855             cfg.cls=this.cls
5856         }
5857         if (this.abbr) {
5858             cfg.abbr=this.abbr
5859         }
5860         if (this.align) {
5861             cfg.align=this.align
5862         }
5863         if (this.axis) {
5864             cfg.axis=this.axis
5865         }
5866         if (this.bgcolor) {
5867             cfg.bgcolor=this.bgcolor
5868         }
5869         if (this.charoff) {
5870             cfg.charoff=this.charoff
5871         }
5872         if (this.colspan) {
5873             cfg.colspan=this.colspan
5874         }
5875         if (this.headers) {
5876             cfg.headers=this.headers
5877         }
5878         if (this.height) {
5879             cfg.height=this.height
5880         }
5881         if (this.nowrap) {
5882             cfg.nowrap=this.nowrap
5883         }
5884         if (this.rowspan) {
5885             cfg.rowspan=this.rowspan
5886         }
5887         if (this.scope) {
5888             cfg.scope=this.scope
5889         }
5890         if (this.valign) {
5891             cfg.valign=this.valign
5892         }
5893         if (this.width) {
5894             cfg.width=this.width
5895         }
5896         
5897         
5898         return cfg;
5899     }
5900    
5901 });
5902
5903  
5904
5905  /*
5906  * - LGPL
5907  *
5908  * table row
5909  * 
5910  */
5911
5912 /**
5913  * @class Roo.bootstrap.TableRow
5914  * @extends Roo.bootstrap.Component
5915  * Bootstrap TableRow class
5916  * @cfg {String} cls row class
5917  * @cfg {String} align Aligns the content in a table row
5918  * @cfg {String} bgcolor Specifies a background color for a table row
5919  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5920  * @cfg {String} valign Vertical aligns the content in a table row
5921  * 
5922  * @constructor
5923  * Create a new TableRow
5924  * @param {Object} config The config object
5925  */
5926
5927 Roo.bootstrap.TableRow = function(config){
5928     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5929 };
5930
5931 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5932     
5933     cls: false,
5934     align: false,
5935     bgcolor: false,
5936     charoff: false,
5937     valign: false,
5938     
5939     getAutoCreate : function(){
5940         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5941         
5942         cfg = {
5943             tag: 'tr'
5944         }
5945             
5946         if(this.cls){
5947             cfg.cls = this.cls;
5948         }
5949         if(this.align){
5950             cfg.align = this.align;
5951         }
5952         if(this.bgcolor){
5953             cfg.bgcolor = this.bgcolor;
5954         }
5955         if(this.charoff){
5956             cfg.charoff = this.charoff;
5957         }
5958         if(this.valign){
5959             cfg.valign = this.valign;
5960         }
5961         
5962         return cfg;
5963     }
5964    
5965 });
5966
5967  
5968
5969  /*
5970  * - LGPL
5971  *
5972  * table body
5973  * 
5974  */
5975
5976 /**
5977  * @class Roo.bootstrap.TableBody
5978  * @extends Roo.bootstrap.Component
5979  * Bootstrap TableBody class
5980  * @cfg {String} cls element class
5981  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5982  * @cfg {String} align Aligns the content inside the element
5983  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5984  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5985  * 
5986  * @constructor
5987  * Create a new TableBody
5988  * @param {Object} config The config object
5989  */
5990
5991 Roo.bootstrap.TableBody = function(config){
5992     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5993 };
5994
5995 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
5996     
5997     cls: false,
5998     tag: false,
5999     align: false,
6000     charoff: false,
6001     valign: false,
6002     
6003     getAutoCreate : function(){
6004         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6005         
6006         cfg = {
6007             tag: 'tbody'
6008         }
6009             
6010         if (this.cls) {
6011             cfg.cls=this.cls
6012         }
6013         if(this.tag){
6014             cfg.tag = this.tag;
6015         }
6016         
6017         if(this.align){
6018             cfg.align = this.align;
6019         }
6020         if(this.charoff){
6021             cfg.charoff = this.charoff;
6022         }
6023         if(this.valign){
6024             cfg.valign = this.valign;
6025         }
6026         
6027         return cfg;
6028     }
6029     
6030     
6031 //    initEvents : function()
6032 //    {
6033 //        
6034 //        if(!this.store){
6035 //            return;
6036 //        }
6037 //        
6038 //        this.store = Roo.factory(this.store, Roo.data);
6039 //        this.store.on('load', this.onLoad, this);
6040 //        
6041 //        this.store.load();
6042 //        
6043 //    },
6044 //    
6045 //    onLoad: function () 
6046 //    {   
6047 //        this.fireEvent('load', this);
6048 //    }
6049 //    
6050 //   
6051 });
6052
6053  
6054
6055  /*
6056  * Based on:
6057  * Ext JS Library 1.1.1
6058  * Copyright(c) 2006-2007, Ext JS, LLC.
6059  *
6060  * Originally Released Under LGPL - original licence link has changed is not relivant.
6061  *
6062  * Fork - LGPL
6063  * <script type="text/javascript">
6064  */
6065
6066 // as we use this in bootstrap.
6067 Roo.namespace('Roo.form');
6068  /**
6069  * @class Roo.form.Action
6070  * Internal Class used to handle form actions
6071  * @constructor
6072  * @param {Roo.form.BasicForm} el The form element or its id
6073  * @param {Object} config Configuration options
6074  */
6075
6076  
6077  
6078 // define the action interface
6079 Roo.form.Action = function(form, options){
6080     this.form = form;
6081     this.options = options || {};
6082 };
6083 /**
6084  * Client Validation Failed
6085  * @const 
6086  */
6087 Roo.form.Action.CLIENT_INVALID = 'client';
6088 /**
6089  * Server Validation Failed
6090  * @const 
6091  */
6092 Roo.form.Action.SERVER_INVALID = 'server';
6093  /**
6094  * Connect to Server Failed
6095  * @const 
6096  */
6097 Roo.form.Action.CONNECT_FAILURE = 'connect';
6098 /**
6099  * Reading Data from Server Failed
6100  * @const 
6101  */
6102 Roo.form.Action.LOAD_FAILURE = 'load';
6103
6104 Roo.form.Action.prototype = {
6105     type : 'default',
6106     failureType : undefined,
6107     response : undefined,
6108     result : undefined,
6109
6110     // interface method
6111     run : function(options){
6112
6113     },
6114
6115     // interface method
6116     success : function(response){
6117
6118     },
6119
6120     // interface method
6121     handleResponse : function(response){
6122
6123     },
6124
6125     // default connection failure
6126     failure : function(response){
6127         
6128         this.response = response;
6129         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6130         this.form.afterAction(this, false);
6131     },
6132
6133     processResponse : function(response){
6134         this.response = response;
6135         if(!response.responseText){
6136             return true;
6137         }
6138         this.result = this.handleResponse(response);
6139         return this.result;
6140     },
6141
6142     // utility functions used internally
6143     getUrl : function(appendParams){
6144         var url = this.options.url || this.form.url || this.form.el.dom.action;
6145         if(appendParams){
6146             var p = this.getParams();
6147             if(p){
6148                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6149             }
6150         }
6151         return url;
6152     },
6153
6154     getMethod : function(){
6155         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6156     },
6157
6158     getParams : function(){
6159         var bp = this.form.baseParams;
6160         var p = this.options.params;
6161         if(p){
6162             if(typeof p == "object"){
6163                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6164             }else if(typeof p == 'string' && bp){
6165                 p += '&' + Roo.urlEncode(bp);
6166             }
6167         }else if(bp){
6168             p = Roo.urlEncode(bp);
6169         }
6170         return p;
6171     },
6172
6173     createCallback : function(){
6174         return {
6175             success: this.success,
6176             failure: this.failure,
6177             scope: this,
6178             timeout: (this.form.timeout*1000),
6179             upload: this.form.fileUpload ? this.success : undefined
6180         };
6181     }
6182 };
6183
6184 Roo.form.Action.Submit = function(form, options){
6185     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6186 };
6187
6188 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6189     type : 'submit',
6190
6191     haveProgress : false,
6192     uploadComplete : false,
6193     
6194     // uploadProgress indicator.
6195     uploadProgress : function()
6196     {
6197         if (!this.form.progressUrl) {
6198             return;
6199         }
6200         
6201         if (!this.haveProgress) {
6202             Roo.MessageBox.progress("Uploading", "Uploading");
6203         }
6204         if (this.uploadComplete) {
6205            Roo.MessageBox.hide();
6206            return;
6207         }
6208         
6209         this.haveProgress = true;
6210    
6211         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6212         
6213         var c = new Roo.data.Connection();
6214         c.request({
6215             url : this.form.progressUrl,
6216             params: {
6217                 id : uid
6218             },
6219             method: 'GET',
6220             success : function(req){
6221                //console.log(data);
6222                 var rdata = false;
6223                 var edata;
6224                 try  {
6225                    rdata = Roo.decode(req.responseText)
6226                 } catch (e) {
6227                     Roo.log("Invalid data from server..");
6228                     Roo.log(edata);
6229                     return;
6230                 }
6231                 if (!rdata || !rdata.success) {
6232                     Roo.log(rdata);
6233                     Roo.MessageBox.alert(Roo.encode(rdata));
6234                     return;
6235                 }
6236                 var data = rdata.data;
6237                 
6238                 if (this.uploadComplete) {
6239                    Roo.MessageBox.hide();
6240                    return;
6241                 }
6242                    
6243                 if (data){
6244                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6245                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6246                     );
6247                 }
6248                 this.uploadProgress.defer(2000,this);
6249             },
6250        
6251             failure: function(data) {
6252                 Roo.log('progress url failed ');
6253                 Roo.log(data);
6254             },
6255             scope : this
6256         });
6257            
6258     },
6259     
6260     
6261     run : function()
6262     {
6263         // run get Values on the form, so it syncs any secondary forms.
6264         this.form.getValues();
6265         
6266         var o = this.options;
6267         var method = this.getMethod();
6268         var isPost = method == 'POST';
6269         if(o.clientValidation === false || this.form.isValid()){
6270             
6271             if (this.form.progressUrl) {
6272                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6273                     (new Date() * 1) + '' + Math.random());
6274                     
6275             } 
6276             
6277             
6278             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6279                 form:this.form.el.dom,
6280                 url:this.getUrl(!isPost),
6281                 method: method,
6282                 params:isPost ? this.getParams() : null,
6283                 isUpload: this.form.fileUpload
6284             }));
6285             
6286             this.uploadProgress();
6287
6288         }else if (o.clientValidation !== false){ // client validation failed
6289             this.failureType = Roo.form.Action.CLIENT_INVALID;
6290             this.form.afterAction(this, false);
6291         }
6292     },
6293
6294     success : function(response)
6295     {
6296         this.uploadComplete= true;
6297         if (this.haveProgress) {
6298             Roo.MessageBox.hide();
6299         }
6300         
6301         
6302         var result = this.processResponse(response);
6303         if(result === true || result.success){
6304             this.form.afterAction(this, true);
6305             return;
6306         }
6307         if(result.errors){
6308             this.form.markInvalid(result.errors);
6309             this.failureType = Roo.form.Action.SERVER_INVALID;
6310         }
6311         this.form.afterAction(this, false);
6312     },
6313     failure : function(response)
6314     {
6315         this.uploadComplete= true;
6316         if (this.haveProgress) {
6317             Roo.MessageBox.hide();
6318         }
6319         
6320         this.response = response;
6321         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6322         this.form.afterAction(this, false);
6323     },
6324     
6325     handleResponse : function(response){
6326         if(this.form.errorReader){
6327             var rs = this.form.errorReader.read(response);
6328             var errors = [];
6329             if(rs.records){
6330                 for(var i = 0, len = rs.records.length; i < len; i++) {
6331                     var r = rs.records[i];
6332                     errors[i] = r.data;
6333                 }
6334             }
6335             if(errors.length < 1){
6336                 errors = null;
6337             }
6338             return {
6339                 success : rs.success,
6340                 errors : errors
6341             };
6342         }
6343         var ret = false;
6344         try {
6345             ret = Roo.decode(response.responseText);
6346         } catch (e) {
6347             ret = {
6348                 success: false,
6349                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6350                 errors : []
6351             };
6352         }
6353         return ret;
6354         
6355     }
6356 });
6357
6358
6359 Roo.form.Action.Load = function(form, options){
6360     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6361     this.reader = this.form.reader;
6362 };
6363
6364 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6365     type : 'load',
6366
6367     run : function(){
6368         
6369         Roo.Ajax.request(Roo.apply(
6370                 this.createCallback(), {
6371                     method:this.getMethod(),
6372                     url:this.getUrl(false),
6373                     params:this.getParams()
6374         }));
6375     },
6376
6377     success : function(response){
6378         
6379         var result = this.processResponse(response);
6380         if(result === true || !result.success || !result.data){
6381             this.failureType = Roo.form.Action.LOAD_FAILURE;
6382             this.form.afterAction(this, false);
6383             return;
6384         }
6385         this.form.clearInvalid();
6386         this.form.setValues(result.data);
6387         this.form.afterAction(this, true);
6388     },
6389
6390     handleResponse : function(response){
6391         if(this.form.reader){
6392             var rs = this.form.reader.read(response);
6393             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6394             return {
6395                 success : rs.success,
6396                 data : data
6397             };
6398         }
6399         return Roo.decode(response.responseText);
6400     }
6401 });
6402
6403 Roo.form.Action.ACTION_TYPES = {
6404     'load' : Roo.form.Action.Load,
6405     'submit' : Roo.form.Action.Submit
6406 };/*
6407  * - LGPL
6408  *
6409  * form
6410  * 
6411  */
6412
6413 /**
6414  * @class Roo.bootstrap.Form
6415  * @extends Roo.bootstrap.Component
6416  * Bootstrap Form class
6417  * @cfg {String} method  GET | POST (default POST)
6418  * @cfg {String} labelAlign top | left (default top)
6419  * @cfg {String} align left  | right - for navbars
6420  * @cfg {Boolean} loadMask load mask when submit (default true)
6421
6422  * 
6423  * @constructor
6424  * Create a new Form
6425  * @param {Object} config The config object
6426  */
6427
6428
6429 Roo.bootstrap.Form = function(config){
6430     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6431     this.addEvents({
6432         /**
6433          * @event clientvalidation
6434          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6435          * @param {Form} this
6436          * @param {Boolean} valid true if the form has passed client-side validation
6437          */
6438         clientvalidation: true,
6439         /**
6440          * @event beforeaction
6441          * Fires before any action is performed. Return false to cancel the action.
6442          * @param {Form} this
6443          * @param {Action} action The action to be performed
6444          */
6445         beforeaction: true,
6446         /**
6447          * @event actionfailed
6448          * Fires when an action fails.
6449          * @param {Form} this
6450          * @param {Action} action The action that failed
6451          */
6452         actionfailed : true,
6453         /**
6454          * @event actioncomplete
6455          * Fires when an action is completed.
6456          * @param {Form} this
6457          * @param {Action} action The action that completed
6458          */
6459         actioncomplete : true
6460     });
6461     
6462 };
6463
6464 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6465       
6466      /**
6467      * @cfg {String} method
6468      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6469      */
6470     method : 'POST',
6471     /**
6472      * @cfg {String} url
6473      * The URL to use for form actions if one isn't supplied in the action options.
6474      */
6475     /**
6476      * @cfg {Boolean} fileUpload
6477      * Set to true if this form is a file upload.
6478      */
6479      
6480     /**
6481      * @cfg {Object} baseParams
6482      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6483      */
6484       
6485     /**
6486      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6487      */
6488     timeout: 30,
6489     /**
6490      * @cfg {Sting} align (left|right) for navbar forms
6491      */
6492     align : 'left',
6493
6494     // private
6495     activeAction : null,
6496  
6497     /**
6498      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6499      * element by passing it or its id or mask the form itself by passing in true.
6500      * @type Mixed
6501      */
6502     waitMsgTarget : false,
6503     
6504     loadMask : true,
6505     
6506     getAutoCreate : function(){
6507         
6508         var cfg = {
6509             tag: 'form',
6510             method : this.method || 'POST',
6511             id : this.id || Roo.id(),
6512             cls : ''
6513         }
6514         if (this.parent().xtype.match(/^Nav/)) {
6515             cfg.cls = 'navbar-form navbar-' + this.align;
6516             
6517         }
6518         
6519         if (this.labelAlign == 'left' ) {
6520             cfg.cls += ' form-horizontal';
6521         }
6522         
6523         
6524         return cfg;
6525     },
6526     initEvents : function()
6527     {
6528         this.el.on('submit', this.onSubmit, this);
6529         // this was added as random key presses on the form where triggering form submit.
6530         this.el.on('keypress', function(e) {
6531             if (e.getCharCode() != 13) {
6532                 return true;
6533             }
6534             // we might need to allow it for textareas.. and some other items.
6535             // check e.getTarget().
6536             
6537             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6538                 return true;
6539             }
6540         
6541             Roo.log("keypress blocked");
6542             
6543             e.preventDefault();
6544             return false;
6545         });
6546         
6547     },
6548     // private
6549     onSubmit : function(e){
6550         e.stopEvent();
6551     },
6552     
6553      /**
6554      * Returns true if client-side validation on the form is successful.
6555      * @return Boolean
6556      */
6557     isValid : function(){
6558         var items = this.getItems();
6559         var valid = true;
6560         items.each(function(f){
6561            if(!f.validate()){
6562                valid = false;
6563                
6564            }
6565         });
6566         return valid;
6567     },
6568     /**
6569      * Returns true if any fields in this form have changed since their original load.
6570      * @return Boolean
6571      */
6572     isDirty : function(){
6573         var dirty = false;
6574         var items = this.getItems();
6575         items.each(function(f){
6576            if(f.isDirty()){
6577                dirty = true;
6578                return false;
6579            }
6580            return true;
6581         });
6582         return dirty;
6583     },
6584      /**
6585      * Performs a predefined action (submit or load) or custom actions you define on this form.
6586      * @param {String} actionName The name of the action type
6587      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6588      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6589      * accept other config options):
6590      * <pre>
6591 Property          Type             Description
6592 ----------------  ---------------  ----------------------------------------------------------------------------------
6593 url               String           The url for the action (defaults to the form's url)
6594 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6595 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6596 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6597                                    validate the form on the client (defaults to false)
6598      * </pre>
6599      * @return {BasicForm} this
6600      */
6601     doAction : function(action, options){
6602         if(typeof action == 'string'){
6603             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6604         }
6605         if(this.fireEvent('beforeaction', this, action) !== false){
6606             this.beforeAction(action);
6607             action.run.defer(100, action);
6608         }
6609         return this;
6610     },
6611     
6612     // private
6613     beforeAction : function(action){
6614         var o = action.options;
6615         
6616         if(this.loadMask){
6617             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6618         }
6619         // not really supported yet.. ??
6620         
6621         //if(this.waitMsgTarget === true){
6622         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6623         //}else if(this.waitMsgTarget){
6624         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6625         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6626         //}else {
6627         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6628        // }
6629          
6630     },
6631
6632     // private
6633     afterAction : function(action, success){
6634         this.activeAction = null;
6635         var o = action.options;
6636         
6637         //if(this.waitMsgTarget === true){
6638             this.el.unmask();
6639         //}else if(this.waitMsgTarget){
6640         //    this.waitMsgTarget.unmask();
6641         //}else{
6642         //    Roo.MessageBox.updateProgress(1);
6643         //    Roo.MessageBox.hide();
6644        // }
6645         // 
6646         if(success){
6647             if(o.reset){
6648                 this.reset();
6649             }
6650             Roo.callback(o.success, o.scope, [this, action]);
6651             this.fireEvent('actioncomplete', this, action);
6652             
6653         }else{
6654             
6655             // failure condition..
6656             // we have a scenario where updates need confirming.
6657             // eg. if a locking scenario exists..
6658             // we look for { errors : { needs_confirm : true }} in the response.
6659             if (
6660                 (typeof(action.result) != 'undefined')  &&
6661                 (typeof(action.result.errors) != 'undefined')  &&
6662                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6663            ){
6664                 var _t = this;
6665                 Roo.log("not supported yet");
6666                  /*
6667                 
6668                 Roo.MessageBox.confirm(
6669                     "Change requires confirmation",
6670                     action.result.errorMsg,
6671                     function(r) {
6672                         if (r != 'yes') {
6673                             return;
6674                         }
6675                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6676                     }
6677                     
6678                 );
6679                 */
6680                 
6681                 
6682                 return;
6683             }
6684             
6685             Roo.callback(o.failure, o.scope, [this, action]);
6686             // show an error message if no failed handler is set..
6687             if (!this.hasListener('actionfailed')) {
6688                 Roo.log("need to add dialog support");
6689                 /*
6690                 Roo.MessageBox.alert("Error",
6691                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6692                         action.result.errorMsg :
6693                         "Saving Failed, please check your entries or try again"
6694                 );
6695                 */
6696             }
6697             
6698             this.fireEvent('actionfailed', this, action);
6699         }
6700         
6701     },
6702     /**
6703      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6704      * @param {String} id The value to search for
6705      * @return Field
6706      */
6707     findField : function(id){
6708         var items = this.getItems();
6709         var field = items.get(id);
6710         if(!field){
6711              items.each(function(f){
6712                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6713                     field = f;
6714                     return false;
6715                 }
6716                 return true;
6717             });
6718         }
6719         return field || null;
6720     },
6721      /**
6722      * Mark fields in this form invalid in bulk.
6723      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6724      * @return {BasicForm} this
6725      */
6726     markInvalid : function(errors){
6727         if(errors instanceof Array){
6728             for(var i = 0, len = errors.length; i < len; i++){
6729                 var fieldError = errors[i];
6730                 var f = this.findField(fieldError.id);
6731                 if(f){
6732                     f.markInvalid(fieldError.msg);
6733                 }
6734             }
6735         }else{
6736             var field, id;
6737             for(id in errors){
6738                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6739                     field.markInvalid(errors[id]);
6740                 }
6741             }
6742         }
6743         //Roo.each(this.childForms || [], function (f) {
6744         //    f.markInvalid(errors);
6745         //});
6746         
6747         return this;
6748     },
6749
6750     /**
6751      * Set values for fields in this form in bulk.
6752      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6753      * @return {BasicForm} this
6754      */
6755     setValues : function(values){
6756         if(values instanceof Array){ // array of objects
6757             for(var i = 0, len = values.length; i < len; i++){
6758                 var v = values[i];
6759                 var f = this.findField(v.id);
6760                 if(f){
6761                     f.setValue(v.value);
6762                     if(this.trackResetOnLoad){
6763                         f.originalValue = f.getValue();
6764                     }
6765                 }
6766             }
6767         }else{ // object hash
6768             var field, id;
6769             for(id in values){
6770                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6771                     
6772                     if (field.setFromData && 
6773                         field.valueField && 
6774                         field.displayField &&
6775                         // combos' with local stores can 
6776                         // be queried via setValue()
6777                         // to set their value..
6778                         (field.store && !field.store.isLocal)
6779                         ) {
6780                         // it's a combo
6781                         var sd = { };
6782                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6783                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6784                         field.setFromData(sd);
6785                         
6786                     } else {
6787                         field.setValue(values[id]);
6788                     }
6789                     
6790                     
6791                     if(this.trackResetOnLoad){
6792                         field.originalValue = field.getValue();
6793                     }
6794                 }
6795             }
6796         }
6797          
6798         //Roo.each(this.childForms || [], function (f) {
6799         //    f.setValues(values);
6800         //});
6801                 
6802         return this;
6803     },
6804
6805     /**
6806      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6807      * they are returned as an array.
6808      * @param {Boolean} asString
6809      * @return {Object}
6810      */
6811     getValues : function(asString){
6812         //if (this.childForms) {
6813             // copy values from the child forms
6814         //    Roo.each(this.childForms, function (f) {
6815         //        this.setValues(f.getValues());
6816         //    }, this);
6817         //}
6818         
6819         
6820         
6821         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6822         if(asString === true){
6823             return fs;
6824         }
6825         return Roo.urlDecode(fs);
6826     },
6827     
6828     /**
6829      * Returns the fields in this form as an object with key/value pairs. 
6830      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6831      * @return {Object}
6832      */
6833     getFieldValues : function(with_hidden)
6834     {
6835         var items = this.getItems();
6836         var ret = {};
6837         items.each(function(f){
6838             if (!f.getName()) {
6839                 return;
6840             }
6841             var v = f.getValue();
6842             if (f.inputType =='radio') {
6843                 if (typeof(ret[f.getName()]) == 'undefined') {
6844                     ret[f.getName()] = ''; // empty..
6845                 }
6846                 
6847                 if (!f.el.dom.checked) {
6848                     return;
6849                     
6850                 }
6851                 v = f.el.dom.value;
6852                 
6853             }
6854             
6855             // not sure if this supported any more..
6856             if ((typeof(v) == 'object') && f.getRawValue) {
6857                 v = f.getRawValue() ; // dates..
6858             }
6859             // combo boxes where name != hiddenName...
6860             if (f.name != f.getName()) {
6861                 ret[f.name] = f.getRawValue();
6862             }
6863             ret[f.getName()] = v;
6864         });
6865         
6866         return ret;
6867     },
6868
6869     /**
6870      * Clears all invalid messages in this form.
6871      * @return {BasicForm} this
6872      */
6873     clearInvalid : function(){
6874         var items = this.getItems();
6875         
6876         items.each(function(f){
6877            f.clearInvalid();
6878         });
6879         
6880         
6881         
6882         return this;
6883     },
6884
6885     /**
6886      * Resets this form.
6887      * @return {BasicForm} this
6888      */
6889     reset : function(){
6890         var items = this.getItems();
6891         items.each(function(f){
6892             f.reset();
6893         });
6894         
6895         Roo.each(this.childForms || [], function (f) {
6896             f.reset();
6897         });
6898        
6899         
6900         return this;
6901     },
6902     getItems : function()
6903     {
6904         var r=new Roo.util.MixedCollection(false, function(o){
6905             return o.id || (o.id = Roo.id());
6906         });
6907         var iter = function(el) {
6908             if (el.inputEl) {
6909                 r.add(el);
6910             }
6911             if (!el.items) {
6912                 return;
6913             }
6914             Roo.each(el.items,function(e) {
6915                 iter(e);
6916             });
6917             
6918             
6919         };
6920         
6921         iter(this);
6922         return r;
6923         
6924         
6925         
6926         
6927     }
6928     
6929 });
6930
6931  
6932 /*
6933  * Based on:
6934  * Ext JS Library 1.1.1
6935  * Copyright(c) 2006-2007, Ext JS, LLC.
6936  *
6937  * Originally Released Under LGPL - original licence link has changed is not relivant.
6938  *
6939  * Fork - LGPL
6940  * <script type="text/javascript">
6941  */
6942 /**
6943  * @class Roo.form.VTypes
6944  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6945  * @singleton
6946  */
6947 Roo.form.VTypes = function(){
6948     // closure these in so they are only created once.
6949     var alpha = /^[a-zA-Z_]+$/;
6950     var alphanum = /^[a-zA-Z0-9_]+$/;
6951     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6952     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6953
6954     // All these messages and functions are configurable
6955     return {
6956         /**
6957          * The function used to validate email addresses
6958          * @param {String} value The email address
6959          */
6960         'email' : function(v){
6961             return email.test(v);
6962         },
6963         /**
6964          * The error text to display when the email validation function returns false
6965          * @type String
6966          */
6967         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6968         /**
6969          * The keystroke filter mask to be applied on email input
6970          * @type RegExp
6971          */
6972         'emailMask' : /[a-z0-9_\.\-@]/i,
6973
6974         /**
6975          * The function used to validate URLs
6976          * @param {String} value The URL
6977          */
6978         'url' : function(v){
6979             return url.test(v);
6980         },
6981         /**
6982          * The error text to display when the url validation function returns false
6983          * @type String
6984          */
6985         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6986         
6987         /**
6988          * The function used to validate alpha values
6989          * @param {String} value The value
6990          */
6991         'alpha' : function(v){
6992             return alpha.test(v);
6993         },
6994         /**
6995          * The error text to display when the alpha validation function returns false
6996          * @type String
6997          */
6998         'alphaText' : 'This field should only contain letters and _',
6999         /**
7000          * The keystroke filter mask to be applied on alpha input
7001          * @type RegExp
7002          */
7003         'alphaMask' : /[a-z_]/i,
7004
7005         /**
7006          * The function used to validate alphanumeric values
7007          * @param {String} value The value
7008          */
7009         'alphanum' : function(v){
7010             return alphanum.test(v);
7011         },
7012         /**
7013          * The error text to display when the alphanumeric validation function returns false
7014          * @type String
7015          */
7016         'alphanumText' : 'This field should only contain letters, numbers and _',
7017         /**
7018          * The keystroke filter mask to be applied on alphanumeric input
7019          * @type RegExp
7020          */
7021         'alphanumMask' : /[a-z0-9_]/i
7022     };
7023 }();/*
7024  * - LGPL
7025  *
7026  * Input
7027  * 
7028  */
7029
7030 /**
7031  * @class Roo.bootstrap.Input
7032  * @extends Roo.bootstrap.Component
7033  * Bootstrap Input class
7034  * @cfg {Boolean} disabled is it disabled
7035  * @cfg {String} fieldLabel - the label associated
7036  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7037  * @cfg {String} name name of the input
7038  * @cfg {string} fieldLabel - the label associated
7039  * @cfg {string}  inputType - input / file submit ...
7040  * @cfg {string} placeholder - placeholder to put in text.
7041  * @cfg {string}  before - input group add on before
7042  * @cfg {string} after - input group add on after
7043  * @cfg {string} size - (lg|sm) or leave empty..
7044  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7045  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7046  * @cfg {Number} md colspan out of 12 for computer-sized screens
7047  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7048  * @cfg {string} value default value of the input
7049  * @cfg {Number} labelWidth set the width of label (0-12)
7050  * @cfg {String} labelAlign (top|left)
7051  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7052  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7053
7054  * @cfg {String} align (left|center|right) Default left
7055  * 
7056  * 
7057  * 
7058  * @constructor
7059  * Create a new Input
7060  * @param {Object} config The config object
7061  */
7062
7063 Roo.bootstrap.Input = function(config){
7064     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7065    
7066         this.addEvents({
7067             /**
7068              * @event focus
7069              * Fires when this field receives input focus.
7070              * @param {Roo.form.Field} this
7071              */
7072             focus : true,
7073             /**
7074              * @event blur
7075              * Fires when this field loses input focus.
7076              * @param {Roo.form.Field} this
7077              */
7078             blur : true,
7079             /**
7080              * @event specialkey
7081              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7082              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7083              * @param {Roo.form.Field} this
7084              * @param {Roo.EventObject} e The event object
7085              */
7086             specialkey : true,
7087             /**
7088              * @event change
7089              * Fires just before the field blurs if the field value has changed.
7090              * @param {Roo.form.Field} this
7091              * @param {Mixed} newValue The new value
7092              * @param {Mixed} oldValue The original value
7093              */
7094             change : true,
7095             /**
7096              * @event invalid
7097              * Fires after the field has been marked as invalid.
7098              * @param {Roo.form.Field} this
7099              * @param {String} msg The validation message
7100              */
7101             invalid : true,
7102             /**
7103              * @event valid
7104              * Fires after the field has been validated with no errors.
7105              * @param {Roo.form.Field} this
7106              */
7107             valid : true,
7108              /**
7109              * @event keyup
7110              * Fires after the key up
7111              * @param {Roo.form.Field} this
7112              * @param {Roo.EventObject}  e The event Object
7113              */
7114             keyup : true
7115         });
7116 };
7117
7118 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7119      /**
7120      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7121       automatic validation (defaults to "keyup").
7122      */
7123     validationEvent : "keyup",
7124      /**
7125      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7126      */
7127     validateOnBlur : true,
7128     /**
7129      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7130      */
7131     validationDelay : 250,
7132      /**
7133      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7134      */
7135     focusClass : "x-form-focus",  // not needed???
7136     
7137        
7138     /**
7139      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7140      */
7141     invalidClass : "has-warning",
7142     
7143     /**
7144      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7145      */
7146     validClass : "has-success",
7147     
7148     /**
7149      * @cfg {Boolean} hasFeedback (true|false) default true
7150      */
7151     hasFeedback : true,
7152     
7153     /**
7154      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7155      */
7156     invalidFeedbackClass : "glyphicon-warning-sign",
7157     
7158     /**
7159      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7160      */
7161     validFeedbackClass : "glyphicon-ok",
7162     
7163     /**
7164      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7165      */
7166     selectOnFocus : false,
7167     
7168      /**
7169      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7170      */
7171     maskRe : null,
7172        /**
7173      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7174      */
7175     vtype : null,
7176     
7177       /**
7178      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7179      */
7180     disableKeyFilter : false,
7181     
7182        /**
7183      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7184      */
7185     disabled : false,
7186      /**
7187      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7188      */
7189     allowBlank : true,
7190     /**
7191      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7192      */
7193     blankText : "This field is required",
7194     
7195      /**
7196      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7197      */
7198     minLength : 0,
7199     /**
7200      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7201      */
7202     maxLength : Number.MAX_VALUE,
7203     /**
7204      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7205      */
7206     minLengthText : "The minimum length for this field is {0}",
7207     /**
7208      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7209      */
7210     maxLengthText : "The maximum length for this field is {0}",
7211   
7212     
7213     /**
7214      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7215      * If available, this function will be called only after the basic validators all return true, and will be passed the
7216      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7217      */
7218     validator : null,
7219     /**
7220      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7221      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7222      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7223      */
7224     regex : null,
7225     /**
7226      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7227      */
7228     regexText : "",
7229     
7230     autocomplete: false,
7231     
7232     
7233     fieldLabel : '',
7234     inputType : 'text',
7235     
7236     name : false,
7237     placeholder: false,
7238     before : false,
7239     after : false,
7240     size : false,
7241     hasFocus : false,
7242     preventMark: false,
7243     isFormField : true,
7244     value : '',
7245     labelWidth : 2,
7246     labelAlign : false,
7247     readOnly : false,
7248     align : false,
7249     formatedValue : false,
7250     
7251     parentLabelAlign : function()
7252     {
7253         var parent = this;
7254         while (parent.parent()) {
7255             parent = parent.parent();
7256             if (typeof(parent.labelAlign) !='undefined') {
7257                 return parent.labelAlign;
7258             }
7259         }
7260         return 'left';
7261         
7262     },
7263     
7264     getAutoCreate : function(){
7265         
7266         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7267         
7268         var id = Roo.id();
7269         
7270         var cfg = {};
7271         
7272         if(this.inputType != 'hidden'){
7273             cfg.cls = 'form-group' //input-group
7274         }
7275         
7276         var input =  {
7277             tag: 'input',
7278             id : id,
7279             type : this.inputType,
7280             value : this.value,
7281             cls : 'form-control',
7282             placeholder : this.placeholder || '',
7283             autocomplete : this.autocomplete || 'new-password'
7284         };
7285         
7286         
7287         if(this.align){
7288             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7289         }
7290         
7291         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7292             input.maxLength = this.maxLength;
7293         }
7294         
7295         if (this.disabled) {
7296             input.disabled=true;
7297         }
7298         
7299         if (this.readOnly) {
7300             input.readonly=true;
7301         }
7302         
7303         if (this.name) {
7304             input.name = this.name;
7305         }
7306         if (this.size) {
7307             input.cls += ' input-' + this.size;
7308         }
7309         var settings=this;
7310         ['xs','sm','md','lg'].map(function(size){
7311             if (settings[size]) {
7312                 cfg.cls += ' col-' + size + '-' + settings[size];
7313             }
7314         });
7315         
7316         var inputblock = input;
7317         
7318         if(this.hasFeedback && this.inputType != 'hidden'){
7319             
7320             var feedback = {
7321                 tag: 'span',
7322                 cls: 'glyphicon form-control-feedback'
7323             };
7324
7325             inputblock = {
7326                 cls : 'has-feedback',
7327                 cn :  [
7328                     input,
7329                     feedback
7330                 ] 
7331             };  
7332         }
7333          
7334 //        var inputblock = input;
7335         
7336         if (this.before || this.after) {
7337             
7338             inputblock = {
7339                 cls : 'input-group',
7340                 cn :  [] 
7341             };
7342             
7343             if (this.before && typeof(this.before) == 'string') {
7344                 
7345                 inputblock.cn.push({
7346                     tag :'span',
7347                     cls : 'roo-input-before input-group-addon',
7348                     html : this.before
7349                 });
7350             }
7351             if (this.before && typeof(this.before) == 'object') {
7352                 this.before = Roo.factory(this.before);
7353                 Roo.log(this.before);
7354                 inputblock.cn.push({
7355                     tag :'span',
7356                     cls : 'roo-input-before input-group-' +
7357                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7358                 });
7359             }
7360             
7361             inputblock.cn.push(input);
7362             
7363             if(this.hasFeedback && this.inputType != 'hidden'){
7364                 inputblock.cls += ' has-feedback';
7365                 inputblock.cn.push(feedback);
7366             }
7367             
7368             if (this.after && typeof(this.after) == 'string') {
7369                 inputblock.cn.push({
7370                     tag :'span',
7371                     cls : 'roo-input-after input-group-addon',
7372                     html : this.after
7373                 });
7374             }
7375             if (this.after && typeof(this.after) == 'object') {
7376                 this.after = Roo.factory(this.after);
7377                 Roo.log(this.after);
7378                 inputblock.cn.push({
7379                     tag :'span',
7380                     cls : 'roo-input-after input-group-' +
7381                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7382                 });
7383             }
7384         };
7385         
7386         if (align ==='left' && this.fieldLabel.length) {
7387                 Roo.log("left and has label");
7388                 cfg.cn = [
7389                     
7390                     {
7391                         tag: 'label',
7392                         'for' :  id,
7393                         cls : 'control-label col-sm-' + this.labelWidth,
7394                         html : this.fieldLabel
7395                         
7396                     },
7397                     {
7398                         cls : "col-sm-" + (12 - this.labelWidth), 
7399                         cn: [
7400                             inputblock
7401                         ]
7402                     }
7403                     
7404                 ];
7405         } else if ( this.fieldLabel.length) {
7406                 Roo.log(" label");
7407                  cfg.cn = [
7408                    
7409                     {
7410                         tag: 'label',
7411                         //cls : 'input-group-addon',
7412                         html : this.fieldLabel
7413                         
7414                     },
7415                     
7416                     inputblock
7417                     
7418                 ];
7419
7420         } else {
7421             
7422                 Roo.log(" no label && no align");
7423                 cfg.cn = [
7424                     
7425                         inputblock
7426                     
7427                 ];
7428                 
7429                 
7430         };
7431         Roo.log('input-parentType: ' + this.parentType);
7432         
7433         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7434            cfg.cls += ' navbar-form';
7435            Roo.log(cfg);
7436         }
7437         
7438         return cfg;
7439         
7440     },
7441     /**
7442      * return the real input element.
7443      */
7444     inputEl: function ()
7445     {
7446         return this.el.select('input.form-control',true).first();
7447     },
7448     
7449     tooltipEl : function()
7450     {
7451         return this.inputEl();
7452     },
7453     
7454     setDisabled : function(v)
7455     {
7456         var i  = this.inputEl().dom;
7457         if (!v) {
7458             i.removeAttribute('disabled');
7459             return;
7460             
7461         }
7462         i.setAttribute('disabled','true');
7463     },
7464     initEvents : function()
7465     {
7466           
7467         this.inputEl().on("keydown" , this.fireKey,  this);
7468         this.inputEl().on("focus", this.onFocus,  this);
7469         this.inputEl().on("blur", this.onBlur,  this);
7470         
7471         this.inputEl().relayEvent('keyup', this);
7472
7473         // reference to original value for reset
7474         this.originalValue = this.getValue();
7475         //Roo.form.TextField.superclass.initEvents.call(this);
7476         if(this.validationEvent == 'keyup'){
7477             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7478             this.inputEl().on('keyup', this.filterValidation, this);
7479         }
7480         else if(this.validationEvent !== false){
7481             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7482         }
7483         
7484         if(this.selectOnFocus){
7485             this.on("focus", this.preFocus, this);
7486             
7487         }
7488         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7489             this.inputEl().on("keypress", this.filterKeys, this);
7490         }
7491        /* if(this.grow){
7492             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7493             this.el.on("click", this.autoSize,  this);
7494         }
7495         */
7496         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7497             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7498         }
7499         
7500         if (typeof(this.before) == 'object') {
7501             this.before.render(this.el.select('.roo-input-before',true).first());
7502         }
7503         if (typeof(this.after) == 'object') {
7504             this.after.render(this.el.select('.roo-input-after',true).first());
7505         }
7506         
7507         
7508     },
7509     filterValidation : function(e){
7510         if(!e.isNavKeyPress()){
7511             this.validationTask.delay(this.validationDelay);
7512         }
7513     },
7514      /**
7515      * Validates the field value
7516      * @return {Boolean} True if the value is valid, else false
7517      */
7518     validate : function(){
7519         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7520         if(this.disabled || this.validateValue(this.getRawValue())){
7521             this.markValid();
7522             return true;
7523         }
7524         
7525         this.markInvalid();
7526         return false;
7527     },
7528     
7529     
7530     /**
7531      * Validates a value according to the field's validation rules and marks the field as invalid
7532      * if the validation fails
7533      * @param {Mixed} value The value to validate
7534      * @return {Boolean} True if the value is valid, else false
7535      */
7536     validateValue : function(value){
7537         if(value.length < 1)  { // if it's blank
7538             if(this.allowBlank){
7539                 return true;
7540             }
7541             return false;
7542         }
7543         
7544         if(value.length < this.minLength){
7545             return false;
7546         }
7547         if(value.length > this.maxLength){
7548             return false;
7549         }
7550         if(this.vtype){
7551             var vt = Roo.form.VTypes;
7552             if(!vt[this.vtype](value, this)){
7553                 return false;
7554             }
7555         }
7556         if(typeof this.validator == "function"){
7557             var msg = this.validator(value);
7558             if(msg !== true){
7559                 return false;
7560             }
7561         }
7562         
7563         if(this.regex && !this.regex.test(value)){
7564             return false;
7565         }
7566         
7567         return true;
7568     },
7569
7570     
7571     
7572      // private
7573     fireKey : function(e){
7574         //Roo.log('field ' + e.getKey());
7575         if(e.isNavKeyPress()){
7576             this.fireEvent("specialkey", this, e);
7577         }
7578     },
7579     focus : function (selectText){
7580         if(this.rendered){
7581             this.inputEl().focus();
7582             if(selectText === true){
7583                 this.inputEl().dom.select();
7584             }
7585         }
7586         return this;
7587     } ,
7588     
7589     onFocus : function(){
7590         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7591            // this.el.addClass(this.focusClass);
7592         }
7593         if(!this.hasFocus){
7594             this.hasFocus = true;
7595             this.startValue = this.getValue();
7596             this.fireEvent("focus", this);
7597         }
7598     },
7599     
7600     beforeBlur : Roo.emptyFn,
7601
7602     
7603     // private
7604     onBlur : function(){
7605         this.beforeBlur();
7606         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7607             //this.el.removeClass(this.focusClass);
7608         }
7609         this.hasFocus = false;
7610         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7611             this.validate();
7612         }
7613         var v = this.getValue();
7614         if(String(v) !== String(this.startValue)){
7615             this.fireEvent('change', this, v, this.startValue);
7616         }
7617         this.fireEvent("blur", this);
7618     },
7619     
7620     /**
7621      * Resets the current field value to the originally loaded value and clears any validation messages
7622      */
7623     reset : function(){
7624         this.setValue(this.originalValue);
7625         this.validate();
7626     },
7627      /**
7628      * Returns the name of the field
7629      * @return {Mixed} name The name field
7630      */
7631     getName: function(){
7632         return this.name;
7633     },
7634      /**
7635      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7636      * @return {Mixed} value The field value
7637      */
7638     getValue : function(){
7639         
7640         var v = this.inputEl().getValue();
7641         
7642         return v;
7643     },
7644     /**
7645      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7646      * @return {Mixed} value The field value
7647      */
7648     getRawValue : function(){
7649         var v = this.inputEl().getValue();
7650         
7651         return v;
7652     },
7653     
7654     /**
7655      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7656      * @param {Mixed} value The value to set
7657      */
7658     setRawValue : function(v){
7659         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7660     },
7661     
7662     selectText : function(start, end){
7663         var v = this.getRawValue();
7664         if(v.length > 0){
7665             start = start === undefined ? 0 : start;
7666             end = end === undefined ? v.length : end;
7667             var d = this.inputEl().dom;
7668             if(d.setSelectionRange){
7669                 d.setSelectionRange(start, end);
7670             }else if(d.createTextRange){
7671                 var range = d.createTextRange();
7672                 range.moveStart("character", start);
7673                 range.moveEnd("character", v.length-end);
7674                 range.select();
7675             }
7676         }
7677     },
7678     
7679     /**
7680      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7681      * @param {Mixed} value The value to set
7682      */
7683     setValue : function(v){
7684         this.value = v;
7685         if(this.rendered){
7686             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7687             this.validate();
7688         }
7689     },
7690     
7691     /*
7692     processValue : function(value){
7693         if(this.stripCharsRe){
7694             var newValue = value.replace(this.stripCharsRe, '');
7695             if(newValue !== value){
7696                 this.setRawValue(newValue);
7697                 return newValue;
7698             }
7699         }
7700         return value;
7701     },
7702   */
7703     preFocus : function(){
7704         
7705         if(this.selectOnFocus){
7706             this.inputEl().dom.select();
7707         }
7708     },
7709     filterKeys : function(e){
7710         var k = e.getKey();
7711         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7712             return;
7713         }
7714         var c = e.getCharCode(), cc = String.fromCharCode(c);
7715         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7716             return;
7717         }
7718         if(!this.maskRe.test(cc)){
7719             e.stopEvent();
7720         }
7721     },
7722      /**
7723      * Clear any invalid styles/messages for this field
7724      */
7725     clearInvalid : function(){
7726         
7727         if(!this.el || this.preventMark){ // not rendered
7728             return;
7729         }
7730         this.el.removeClass(this.invalidClass);
7731         
7732         this.fireEvent('valid', this);
7733     },
7734     
7735      /**
7736      * Mark this field as valid
7737      */
7738     markValid : function(){
7739         if(!this.el  || this.preventMark){ // not rendered
7740             return;
7741         }
7742         
7743         this.el.removeClass([this.invalidClass, this.validClass]);
7744         
7745         this.el.addClass(this.validClass);
7746         
7747         if(this.hasFeedback && this.inputType != 'hidden'){
7748             var feedback = this.el.select('.form-control-feedback', true).first();
7749             
7750             if(feedback){
7751                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7752                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7753             }
7754             
7755         }
7756         
7757         this.fireEvent('valid', this);
7758     },
7759     
7760      /**
7761      * Mark this field as invalid
7762      * @param {String} msg The validation message
7763      */
7764     markInvalid : function(msg){
7765         if(!this.el  || this.preventMark){ // not rendered
7766             return;
7767         }
7768         
7769         this.el.removeClass([this.invalidClass, this.validClass]);
7770         
7771         this.el.addClass(this.invalidClass);
7772         
7773         if(this.hasFeedback && this.inputType != 'hidden'){
7774             
7775             var feedback = this.el.select('.form-control-feedback', true).first();
7776             
7777             if(feedback){
7778                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7779                 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7780             }
7781             
7782         }
7783         
7784         this.fireEvent('invalid', this, msg);
7785     },
7786     // private
7787     SafariOnKeyDown : function(event)
7788     {
7789         // this is a workaround for a password hang bug on chrome/ webkit.
7790         
7791         var isSelectAll = false;
7792         
7793         if(this.inputEl().dom.selectionEnd > 0){
7794             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7795         }
7796         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7797             event.preventDefault();
7798             this.setValue('');
7799             return;
7800         }
7801         
7802         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7803             
7804             event.preventDefault();
7805             // this is very hacky as keydown always get's upper case.
7806             //
7807             var cc = String.fromCharCode(event.getCharCode());
7808             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7809             
7810         }
7811     },
7812     adjustWidth : function(tag, w){
7813         tag = tag.toLowerCase();
7814         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7815             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7816                 if(tag == 'input'){
7817                     return w + 2;
7818                 }
7819                 if(tag == 'textarea'){
7820                     return w-2;
7821                 }
7822             }else if(Roo.isOpera){
7823                 if(tag == 'input'){
7824                     return w + 2;
7825                 }
7826                 if(tag == 'textarea'){
7827                     return w-2;
7828                 }
7829             }
7830         }
7831         return w;
7832     }
7833     
7834 });
7835
7836  
7837 /*
7838  * - LGPL
7839  *
7840  * Input
7841  * 
7842  */
7843
7844 /**
7845  * @class Roo.bootstrap.TextArea
7846  * @extends Roo.bootstrap.Input
7847  * Bootstrap TextArea class
7848  * @cfg {Number} cols Specifies the visible width of a text area
7849  * @cfg {Number} rows Specifies the visible number of lines in a text area
7850  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7851  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7852  * @cfg {string} html text
7853  * 
7854  * @constructor
7855  * Create a new TextArea
7856  * @param {Object} config The config object
7857  */
7858
7859 Roo.bootstrap.TextArea = function(config){
7860     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7861    
7862 };
7863
7864 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7865      
7866     cols : false,
7867     rows : 5,
7868     readOnly : false,
7869     warp : 'soft',
7870     resize : false,
7871     value: false,
7872     html: false,
7873     
7874     getAutoCreate : function(){
7875         
7876         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7877         
7878         var id = Roo.id();
7879         
7880         var cfg = {};
7881         
7882         var input =  {
7883             tag: 'textarea',
7884             id : id,
7885             warp : this.warp,
7886             rows : this.rows,
7887             value : this.value || '',
7888             html: this.html || '',
7889             cls : 'form-control',
7890             placeholder : this.placeholder || '' 
7891             
7892         };
7893         
7894         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7895             input.maxLength = this.maxLength;
7896         }
7897         
7898         if(this.resize){
7899             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7900         }
7901         
7902         if(this.cols){
7903             input.cols = this.cols;
7904         }
7905         
7906         if (this.readOnly) {
7907             input.readonly = true;
7908         }
7909         
7910         if (this.name) {
7911             input.name = this.name;
7912         }
7913         
7914         if (this.size) {
7915             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7916         }
7917         
7918         var settings=this;
7919         ['xs','sm','md','lg'].map(function(size){
7920             if (settings[size]) {
7921                 cfg.cls += ' col-' + size + '-' + settings[size];
7922             }
7923         });
7924         
7925         var inputblock = input;
7926         
7927         if(this.hasFeedback){
7928             
7929             var feedback = {
7930                 tag: 'span',
7931                 cls: 'glyphicon form-control-feedback'
7932             };
7933
7934             inputblock = {
7935                 cls : 'has-feedback',
7936                 cn :  [
7937                     input,
7938                     feedback
7939                 ] 
7940             };  
7941         }
7942         
7943         
7944         if (this.before || this.after) {
7945             
7946             inputblock = {
7947                 cls : 'input-group',
7948                 cn :  [] 
7949             };
7950             if (this.before) {
7951                 inputblock.cn.push({
7952                     tag :'span',
7953                     cls : 'input-group-addon',
7954                     html : this.before
7955                 });
7956             }
7957             
7958             inputblock.cn.push(input);
7959             
7960             if(this.hasFeedback){
7961                 inputblock.cls += ' has-feedback';
7962                 inputblock.cn.push(feedback);
7963             }
7964             
7965             if (this.after) {
7966                 inputblock.cn.push({
7967                     tag :'span',
7968                     cls : 'input-group-addon',
7969                     html : this.after
7970                 });
7971             }
7972             
7973         }
7974         
7975         if (align ==='left' && this.fieldLabel.length) {
7976                 Roo.log("left and has label");
7977                 cfg.cn = [
7978                     
7979                     {
7980                         tag: 'label',
7981                         'for' :  id,
7982                         cls : 'control-label col-sm-' + this.labelWidth,
7983                         html : this.fieldLabel
7984                         
7985                     },
7986                     {
7987                         cls : "col-sm-" + (12 - this.labelWidth), 
7988                         cn: [
7989                             inputblock
7990                         ]
7991                     }
7992                     
7993                 ];
7994         } else if ( this.fieldLabel.length) {
7995                 Roo.log(" label");
7996                  cfg.cn = [
7997                    
7998                     {
7999                         tag: 'label',
8000                         //cls : 'input-group-addon',
8001                         html : this.fieldLabel
8002                         
8003                     },
8004                     
8005                     inputblock
8006                     
8007                 ];
8008
8009         } else {
8010             
8011                    Roo.log(" no label && no align");
8012                 cfg.cn = [
8013                     
8014                         inputblock
8015                     
8016                 ];
8017                 
8018                 
8019         }
8020         
8021         if (this.disabled) {
8022             input.disabled=true;
8023         }
8024         
8025         return cfg;
8026         
8027     },
8028     /**
8029      * return the real textarea element.
8030      */
8031     inputEl: function ()
8032     {
8033         return this.el.select('textarea.form-control',true).first();
8034     }
8035 });
8036
8037  
8038 /*
8039  * - LGPL
8040  *
8041  * trigger field - base class for combo..
8042  * 
8043  */
8044  
8045 /**
8046  * @class Roo.bootstrap.TriggerField
8047  * @extends Roo.bootstrap.Input
8048  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8049  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8050  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8051  * for which you can provide a custom implementation.  For example:
8052  * <pre><code>
8053 var trigger = new Roo.bootstrap.TriggerField();
8054 trigger.onTriggerClick = myTriggerFn;
8055 trigger.applyTo('my-field');
8056 </code></pre>
8057  *
8058  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8059  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8060  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8061  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8062  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8063
8064  * @constructor
8065  * Create a new TriggerField.
8066  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8067  * to the base TextField)
8068  */
8069 Roo.bootstrap.TriggerField = function(config){
8070     this.mimicing = false;
8071     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8072 };
8073
8074 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8075     /**
8076      * @cfg {String} triggerClass A CSS class to apply to the trigger
8077      */
8078      /**
8079      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8080      */
8081     hideTrigger:false,
8082
8083     /** @cfg {Boolean} grow @hide */
8084     /** @cfg {Number} growMin @hide */
8085     /** @cfg {Number} growMax @hide */
8086
8087     /**
8088      * @hide 
8089      * @method
8090      */
8091     autoSize: Roo.emptyFn,
8092     // private
8093     monitorTab : true,
8094     // private
8095     deferHeight : true,
8096
8097     
8098     actionMode : 'wrap',
8099     
8100     caret : false,
8101     
8102     
8103     getAutoCreate : function(){
8104        
8105         var align = this.labelAlign || this.parentLabelAlign();
8106         
8107         var id = Roo.id();
8108         
8109         var cfg = {
8110             cls: 'form-group' //input-group
8111         };
8112         
8113         
8114         var input =  {
8115             tag: 'input',
8116             id : id,
8117             type : this.inputType,
8118             cls : 'form-control',
8119             autocomplete: 'new-password',
8120             placeholder : this.placeholder || '' 
8121             
8122         };
8123         if (this.name) {
8124             input.name = this.name;
8125         }
8126         if (this.size) {
8127             input.cls += ' input-' + this.size;
8128         }
8129         
8130         if (this.disabled) {
8131             input.disabled=true;
8132         }
8133         
8134         var inputblock = input;
8135         
8136         if(this.hasFeedback){
8137             
8138             var feedback = {
8139                 tag: 'span',
8140                 cls: 'glyphicon form-control-feedback'
8141             };
8142
8143             inputblock = {
8144                 cls : 'has-feedback',
8145                 cn :  [
8146                     input,
8147                     feedback
8148                 ] 
8149             };  
8150         }
8151         
8152         if (this.before || this.after) {
8153             
8154             inputblock = {
8155                 cls : 'input-group',
8156                 cn :  [] 
8157             };
8158             if (this.before) {
8159                 inputblock.cn.push({
8160                     tag :'span',
8161                     cls : 'input-group-addon',
8162                     html : this.before
8163                 });
8164             }
8165             
8166             inputblock.cn.push(input);
8167             
8168             if(this.hasFeedback){
8169                 inputblock.cls += ' has-feedback';
8170                 inputblock.cn.push(feedback);
8171             }
8172             
8173             if (this.after) {
8174                 inputblock.cn.push({
8175                     tag :'span',
8176                     cls : 'input-group-addon',
8177                     html : this.after
8178                 });
8179             }
8180             
8181         };
8182         
8183         var box = {
8184             tag: 'div',
8185             cn: [
8186                 {
8187                     tag: 'input',
8188                     type : 'hidden',
8189                     cls: 'form-hidden-field'
8190                 },
8191                 inputblock
8192             ]
8193             
8194         };
8195         
8196         if(this.multiple){
8197             Roo.log('multiple');
8198             
8199             box = {
8200                 tag: 'div',
8201                 cn: [
8202                     {
8203                         tag: 'input',
8204                         type : 'hidden',
8205                         cls: 'form-hidden-field'
8206                     },
8207                     {
8208                         tag: 'ul',
8209                         cls: 'select2-choices',
8210                         cn:[
8211                             {
8212                                 tag: 'li',
8213                                 cls: 'select2-search-field',
8214                                 cn: [
8215
8216                                     inputblock
8217                                 ]
8218                             }
8219                         ]
8220                     }
8221                 ]
8222             }
8223         };
8224         
8225         var combobox = {
8226             cls: 'select2-container input-group',
8227             cn: [
8228                 box
8229 //                {
8230 //                    tag: 'ul',
8231 //                    cls: 'typeahead typeahead-long dropdown-menu',
8232 //                    style: 'display:none'
8233 //                }
8234             ]
8235         };
8236         
8237         if(!this.multiple && this.showToggleBtn){
8238             
8239             var caret = {
8240                         tag: 'span',
8241                         cls: 'caret'
8242              };
8243             if (this.caret != false) {
8244                 caret = {
8245                      tag: 'i',
8246                      cls: 'fa fa-' + this.caret
8247                 };
8248                 
8249             }
8250             
8251             combobox.cn.push({
8252                 tag :'span',
8253                 cls : 'input-group-addon btn dropdown-toggle',
8254                 cn : [
8255                     caret,
8256                     {
8257                         tag: 'span',
8258                         cls: 'combobox-clear',
8259                         cn  : [
8260                             {
8261                                 tag : 'i',
8262                                 cls: 'icon-remove'
8263                             }
8264                         ]
8265                     }
8266                 ]
8267
8268             })
8269         }
8270         
8271         if(this.multiple){
8272             combobox.cls += ' select2-container-multi';
8273         }
8274         
8275         if (align ==='left' && this.fieldLabel.length) {
8276             
8277                 Roo.log("left and has label");
8278                 cfg.cn = [
8279                     
8280                     {
8281                         tag: 'label',
8282                         'for' :  id,
8283                         cls : 'control-label col-sm-' + this.labelWidth,
8284                         html : this.fieldLabel
8285                         
8286                     },
8287                     {
8288                         cls : "col-sm-" + (12 - this.labelWidth), 
8289                         cn: [
8290                             combobox
8291                         ]
8292                     }
8293                     
8294                 ];
8295         } else if ( this.fieldLabel.length) {
8296                 Roo.log(" label");
8297                  cfg.cn = [
8298                    
8299                     {
8300                         tag: 'label',
8301                         //cls : 'input-group-addon',
8302                         html : this.fieldLabel
8303                         
8304                     },
8305                     
8306                     combobox
8307                     
8308                 ];
8309
8310         } else {
8311             
8312                 Roo.log(" no label && no align");
8313                 cfg = combobox
8314                      
8315                 
8316         }
8317          
8318         var settings=this;
8319         ['xs','sm','md','lg'].map(function(size){
8320             if (settings[size]) {
8321                 cfg.cls += ' col-' + size + '-' + settings[size];
8322             }
8323         });
8324         
8325         return cfg;
8326         
8327     },
8328     
8329     
8330     
8331     // private
8332     onResize : function(w, h){
8333 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8334 //        if(typeof w == 'number'){
8335 //            var x = w - this.trigger.getWidth();
8336 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8337 //            this.trigger.setStyle('left', x+'px');
8338 //        }
8339     },
8340
8341     // private
8342     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8343
8344     // private
8345     getResizeEl : function(){
8346         return this.inputEl();
8347     },
8348
8349     // private
8350     getPositionEl : function(){
8351         return this.inputEl();
8352     },
8353
8354     // private
8355     alignErrorIcon : function(){
8356         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8357     },
8358
8359     // private
8360     initEvents : function(){
8361         
8362         this.createList();
8363         
8364         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8365         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8366         if(!this.multiple && this.showToggleBtn){
8367             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8368             if(this.hideTrigger){
8369                 this.trigger.setDisplayed(false);
8370             }
8371             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8372         }
8373         
8374         if(this.multiple){
8375             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8376         }
8377         
8378         //this.trigger.addClassOnOver('x-form-trigger-over');
8379         //this.trigger.addClassOnClick('x-form-trigger-click');
8380         
8381         //if(!this.width){
8382         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8383         //}
8384     },
8385     
8386     createList : function()
8387     {
8388         this.list = Roo.get(document.body).createChild({
8389             tag: 'ul',
8390             cls: 'typeahead typeahead-long dropdown-menu',
8391             style: 'display:none'
8392         });
8393         
8394         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8395         
8396     },
8397
8398     // private
8399     initTrigger : function(){
8400        
8401     },
8402
8403     // private
8404     onDestroy : function(){
8405         if(this.trigger){
8406             this.trigger.removeAllListeners();
8407           //  this.trigger.remove();
8408         }
8409         //if(this.wrap){
8410         //    this.wrap.remove();
8411         //}
8412         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8413     },
8414
8415     // private
8416     onFocus : function(){
8417         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8418         /*
8419         if(!this.mimicing){
8420             this.wrap.addClass('x-trigger-wrap-focus');
8421             this.mimicing = true;
8422             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8423             if(this.monitorTab){
8424                 this.el.on("keydown", this.checkTab, this);
8425             }
8426         }
8427         */
8428     },
8429
8430     // private
8431     checkTab : function(e){
8432         if(e.getKey() == e.TAB){
8433             this.triggerBlur();
8434         }
8435     },
8436
8437     // private
8438     onBlur : function(){
8439         // do nothing
8440     },
8441
8442     // private
8443     mimicBlur : function(e, t){
8444         /*
8445         if(!this.wrap.contains(t) && this.validateBlur()){
8446             this.triggerBlur();
8447         }
8448         */
8449     },
8450
8451     // private
8452     triggerBlur : function(){
8453         this.mimicing = false;
8454         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8455         if(this.monitorTab){
8456             this.el.un("keydown", this.checkTab, this);
8457         }
8458         //this.wrap.removeClass('x-trigger-wrap-focus');
8459         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8460     },
8461
8462     // private
8463     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8464     validateBlur : function(e, t){
8465         return true;
8466     },
8467
8468     // private
8469     onDisable : function(){
8470         this.inputEl().dom.disabled = true;
8471         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8472         //if(this.wrap){
8473         //    this.wrap.addClass('x-item-disabled');
8474         //}
8475     },
8476
8477     // private
8478     onEnable : function(){
8479         this.inputEl().dom.disabled = false;
8480         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8481         //if(this.wrap){
8482         //    this.el.removeClass('x-item-disabled');
8483         //}
8484     },
8485
8486     // private
8487     onShow : function(){
8488         var ae = this.getActionEl();
8489         
8490         if(ae){
8491             ae.dom.style.display = '';
8492             ae.dom.style.visibility = 'visible';
8493         }
8494     },
8495
8496     // private
8497     
8498     onHide : function(){
8499         var ae = this.getActionEl();
8500         ae.dom.style.display = 'none';
8501     },
8502
8503     /**
8504      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8505      * by an implementing function.
8506      * @method
8507      * @param {EventObject} e
8508      */
8509     onTriggerClick : Roo.emptyFn
8510 });
8511  /*
8512  * Based on:
8513  * Ext JS Library 1.1.1
8514  * Copyright(c) 2006-2007, Ext JS, LLC.
8515  *
8516  * Originally Released Under LGPL - original licence link has changed is not relivant.
8517  *
8518  * Fork - LGPL
8519  * <script type="text/javascript">
8520  */
8521
8522
8523 /**
8524  * @class Roo.data.SortTypes
8525  * @singleton
8526  * Defines the default sorting (casting?) comparison functions used when sorting data.
8527  */
8528 Roo.data.SortTypes = {
8529     /**
8530      * Default sort that does nothing
8531      * @param {Mixed} s The value being converted
8532      * @return {Mixed} The comparison value
8533      */
8534     none : function(s){
8535         return s;
8536     },
8537     
8538     /**
8539      * The regular expression used to strip tags
8540      * @type {RegExp}
8541      * @property
8542      */
8543     stripTagsRE : /<\/?[^>]+>/gi,
8544     
8545     /**
8546      * Strips all HTML tags to sort on text only
8547      * @param {Mixed} s The value being converted
8548      * @return {String} The comparison value
8549      */
8550     asText : function(s){
8551         return String(s).replace(this.stripTagsRE, "");
8552     },
8553     
8554     /**
8555      * Strips all HTML tags to sort on text only - Case insensitive
8556      * @param {Mixed} s The value being converted
8557      * @return {String} The comparison value
8558      */
8559     asUCText : function(s){
8560         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8561     },
8562     
8563     /**
8564      * Case insensitive string
8565      * @param {Mixed} s The value being converted
8566      * @return {String} The comparison value
8567      */
8568     asUCString : function(s) {
8569         return String(s).toUpperCase();
8570     },
8571     
8572     /**
8573      * Date sorting
8574      * @param {Mixed} s The value being converted
8575      * @return {Number} The comparison value
8576      */
8577     asDate : function(s) {
8578         if(!s){
8579             return 0;
8580         }
8581         if(s instanceof Date){
8582             return s.getTime();
8583         }
8584         return Date.parse(String(s));
8585     },
8586     
8587     /**
8588      * Float sorting
8589      * @param {Mixed} s The value being converted
8590      * @return {Float} The comparison value
8591      */
8592     asFloat : function(s) {
8593         var val = parseFloat(String(s).replace(/,/g, ""));
8594         if(isNaN(val)) val = 0;
8595         return val;
8596     },
8597     
8598     /**
8599      * Integer sorting
8600      * @param {Mixed} s The value being converted
8601      * @return {Number} The comparison value
8602      */
8603     asInt : function(s) {
8604         var val = parseInt(String(s).replace(/,/g, ""));
8605         if(isNaN(val)) val = 0;
8606         return val;
8607     }
8608 };/*
8609  * Based on:
8610  * Ext JS Library 1.1.1
8611  * Copyright(c) 2006-2007, Ext JS, LLC.
8612  *
8613  * Originally Released Under LGPL - original licence link has changed is not relivant.
8614  *
8615  * Fork - LGPL
8616  * <script type="text/javascript">
8617  */
8618
8619 /**
8620 * @class Roo.data.Record
8621  * Instances of this class encapsulate both record <em>definition</em> information, and record
8622  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8623  * to access Records cached in an {@link Roo.data.Store} object.<br>
8624  * <p>
8625  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8626  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8627  * objects.<br>
8628  * <p>
8629  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8630  * @constructor
8631  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8632  * {@link #create}. The parameters are the same.
8633  * @param {Array} data An associative Array of data values keyed by the field name.
8634  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8635  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8636  * not specified an integer id is generated.
8637  */
8638 Roo.data.Record = function(data, id){
8639     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8640     this.data = data;
8641 };
8642
8643 /**
8644  * Generate a constructor for a specific record layout.
8645  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8646  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8647  * Each field definition object may contain the following properties: <ul>
8648  * <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,
8649  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8650  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8651  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8652  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8653  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8654  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8655  * this may be omitted.</p></li>
8656  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8657  * <ul><li>auto (Default, implies no conversion)</li>
8658  * <li>string</li>
8659  * <li>int</li>
8660  * <li>float</li>
8661  * <li>boolean</li>
8662  * <li>date</li></ul></p></li>
8663  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8664  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8665  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8666  * by the Reader into an object that will be stored in the Record. It is passed the
8667  * following parameters:<ul>
8668  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8669  * </ul></p></li>
8670  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8671  * </ul>
8672  * <br>usage:<br><pre><code>
8673 var TopicRecord = Roo.data.Record.create(
8674     {name: 'title', mapping: 'topic_title'},
8675     {name: 'author', mapping: 'username'},
8676     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8677     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8678     {name: 'lastPoster', mapping: 'user2'},
8679     {name: 'excerpt', mapping: 'post_text'}
8680 );
8681
8682 var myNewRecord = new TopicRecord({
8683     title: 'Do my job please',
8684     author: 'noobie',
8685     totalPosts: 1,
8686     lastPost: new Date(),
8687     lastPoster: 'Animal',
8688     excerpt: 'No way dude!'
8689 });
8690 myStore.add(myNewRecord);
8691 </code></pre>
8692  * @method create
8693  * @static
8694  */
8695 Roo.data.Record.create = function(o){
8696     var f = function(){
8697         f.superclass.constructor.apply(this, arguments);
8698     };
8699     Roo.extend(f, Roo.data.Record);
8700     var p = f.prototype;
8701     p.fields = new Roo.util.MixedCollection(false, function(field){
8702         return field.name;
8703     });
8704     for(var i = 0, len = o.length; i < len; i++){
8705         p.fields.add(new Roo.data.Field(o[i]));
8706     }
8707     f.getField = function(name){
8708         return p.fields.get(name);  
8709     };
8710     return f;
8711 };
8712
8713 Roo.data.Record.AUTO_ID = 1000;
8714 Roo.data.Record.EDIT = 'edit';
8715 Roo.data.Record.REJECT = 'reject';
8716 Roo.data.Record.COMMIT = 'commit';
8717
8718 Roo.data.Record.prototype = {
8719     /**
8720      * Readonly flag - true if this record has been modified.
8721      * @type Boolean
8722      */
8723     dirty : false,
8724     editing : false,
8725     error: null,
8726     modified: null,
8727
8728     // private
8729     join : function(store){
8730         this.store = store;
8731     },
8732
8733     /**
8734      * Set the named field to the specified value.
8735      * @param {String} name The name of the field to set.
8736      * @param {Object} value The value to set the field to.
8737      */
8738     set : function(name, value){
8739         if(this.data[name] == value){
8740             return;
8741         }
8742         this.dirty = true;
8743         if(!this.modified){
8744             this.modified = {};
8745         }
8746         if(typeof this.modified[name] == 'undefined'){
8747             this.modified[name] = this.data[name];
8748         }
8749         this.data[name] = value;
8750         if(!this.editing && this.store){
8751             this.store.afterEdit(this);
8752         }       
8753     },
8754
8755     /**
8756      * Get the value of the named field.
8757      * @param {String} name The name of the field to get the value of.
8758      * @return {Object} The value of the field.
8759      */
8760     get : function(name){
8761         return this.data[name]; 
8762     },
8763
8764     // private
8765     beginEdit : function(){
8766         this.editing = true;
8767         this.modified = {}; 
8768     },
8769
8770     // private
8771     cancelEdit : function(){
8772         this.editing = false;
8773         delete this.modified;
8774     },
8775
8776     // private
8777     endEdit : function(){
8778         this.editing = false;
8779         if(this.dirty && this.store){
8780             this.store.afterEdit(this);
8781         }
8782     },
8783
8784     /**
8785      * Usually called by the {@link Roo.data.Store} which owns the Record.
8786      * Rejects all changes made to the Record since either creation, or the last commit operation.
8787      * Modified fields are reverted to their original values.
8788      * <p>
8789      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8790      * of reject operations.
8791      */
8792     reject : function(){
8793         var m = this.modified;
8794         for(var n in m){
8795             if(typeof m[n] != "function"){
8796                 this.data[n] = m[n];
8797             }
8798         }
8799         this.dirty = false;
8800         delete this.modified;
8801         this.editing = false;
8802         if(this.store){
8803             this.store.afterReject(this);
8804         }
8805     },
8806
8807     /**
8808      * Usually called by the {@link Roo.data.Store} which owns the Record.
8809      * Commits all changes made to the Record since either creation, or the last commit operation.
8810      * <p>
8811      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8812      * of commit operations.
8813      */
8814     commit : function(){
8815         this.dirty = false;
8816         delete this.modified;
8817         this.editing = false;
8818         if(this.store){
8819             this.store.afterCommit(this);
8820         }
8821     },
8822
8823     // private
8824     hasError : function(){
8825         return this.error != null;
8826     },
8827
8828     // private
8829     clearError : function(){
8830         this.error = null;
8831     },
8832
8833     /**
8834      * Creates a copy of this record.
8835      * @param {String} id (optional) A new record id if you don't want to use this record's id
8836      * @return {Record}
8837      */
8838     copy : function(newId) {
8839         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8840     }
8841 };/*
8842  * Based on:
8843  * Ext JS Library 1.1.1
8844  * Copyright(c) 2006-2007, Ext JS, LLC.
8845  *
8846  * Originally Released Under LGPL - original licence link has changed is not relivant.
8847  *
8848  * Fork - LGPL
8849  * <script type="text/javascript">
8850  */
8851
8852
8853
8854 /**
8855  * @class Roo.data.Store
8856  * @extends Roo.util.Observable
8857  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8858  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8859  * <p>
8860  * 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
8861  * has no knowledge of the format of the data returned by the Proxy.<br>
8862  * <p>
8863  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8864  * instances from the data object. These records are cached and made available through accessor functions.
8865  * @constructor
8866  * Creates a new Store.
8867  * @param {Object} config A config object containing the objects needed for the Store to access data,
8868  * and read the data into Records.
8869  */
8870 Roo.data.Store = function(config){
8871     this.data = new Roo.util.MixedCollection(false);
8872     this.data.getKey = function(o){
8873         return o.id;
8874     };
8875     this.baseParams = {};
8876     // private
8877     this.paramNames = {
8878         "start" : "start",
8879         "limit" : "limit",
8880         "sort" : "sort",
8881         "dir" : "dir",
8882         "multisort" : "_multisort"
8883     };
8884
8885     if(config && config.data){
8886         this.inlineData = config.data;
8887         delete config.data;
8888     }
8889
8890     Roo.apply(this, config);
8891     
8892     if(this.reader){ // reader passed
8893         this.reader = Roo.factory(this.reader, Roo.data);
8894         this.reader.xmodule = this.xmodule || false;
8895         if(!this.recordType){
8896             this.recordType = this.reader.recordType;
8897         }
8898         if(this.reader.onMetaChange){
8899             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8900         }
8901     }
8902
8903     if(this.recordType){
8904         this.fields = this.recordType.prototype.fields;
8905     }
8906     this.modified = [];
8907
8908     this.addEvents({
8909         /**
8910          * @event datachanged
8911          * Fires when the data cache has changed, and a widget which is using this Store
8912          * as a Record cache should refresh its view.
8913          * @param {Store} this
8914          */
8915         datachanged : true,
8916         /**
8917          * @event metachange
8918          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8919          * @param {Store} this
8920          * @param {Object} meta The JSON metadata
8921          */
8922         metachange : true,
8923         /**
8924          * @event add
8925          * Fires when Records have been added to the Store
8926          * @param {Store} this
8927          * @param {Roo.data.Record[]} records The array of Records added
8928          * @param {Number} index The index at which the record(s) were added
8929          */
8930         add : true,
8931         /**
8932          * @event remove
8933          * Fires when a Record has been removed from the Store
8934          * @param {Store} this
8935          * @param {Roo.data.Record} record The Record that was removed
8936          * @param {Number} index The index at which the record was removed
8937          */
8938         remove : true,
8939         /**
8940          * @event update
8941          * Fires when a Record has been updated
8942          * @param {Store} this
8943          * @param {Roo.data.Record} record The Record that was updated
8944          * @param {String} operation The update operation being performed.  Value may be one of:
8945          * <pre><code>
8946  Roo.data.Record.EDIT
8947  Roo.data.Record.REJECT
8948  Roo.data.Record.COMMIT
8949          * </code></pre>
8950          */
8951         update : true,
8952         /**
8953          * @event clear
8954          * Fires when the data cache has been cleared.
8955          * @param {Store} this
8956          */
8957         clear : true,
8958         /**
8959          * @event beforeload
8960          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8961          * the load action will be canceled.
8962          * @param {Store} this
8963          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8964          */
8965         beforeload : true,
8966         /**
8967          * @event beforeloadadd
8968          * Fires after a new set of Records has been loaded.
8969          * @param {Store} this
8970          * @param {Roo.data.Record[]} records The Records that were loaded
8971          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8972          */
8973         beforeloadadd : true,
8974         /**
8975          * @event load
8976          * Fires after a new set of Records has been loaded, before they are added to the store.
8977          * @param {Store} this
8978          * @param {Roo.data.Record[]} records The Records that were loaded
8979          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8980          * @params {Object} return from reader
8981          */
8982         load : true,
8983         /**
8984          * @event loadexception
8985          * Fires if an exception occurs in the Proxy during loading.
8986          * Called with the signature of the Proxy's "loadexception" event.
8987          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8988          * 
8989          * @param {Proxy} 
8990          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8991          * @param {Object} load options 
8992          * @param {Object} jsonData from your request (normally this contains the Exception)
8993          */
8994         loadexception : true
8995     });
8996     
8997     if(this.proxy){
8998         this.proxy = Roo.factory(this.proxy, Roo.data);
8999         this.proxy.xmodule = this.xmodule || false;
9000         this.relayEvents(this.proxy,  ["loadexception"]);
9001     }
9002     this.sortToggle = {};
9003     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9004
9005     Roo.data.Store.superclass.constructor.call(this);
9006
9007     if(this.inlineData){
9008         this.loadData(this.inlineData);
9009         delete this.inlineData;
9010     }
9011 };
9012
9013 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9014      /**
9015     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9016     * without a remote query - used by combo/forms at present.
9017     */
9018     
9019     /**
9020     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9021     */
9022     /**
9023     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9024     */
9025     /**
9026     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9027     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9028     */
9029     /**
9030     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9031     * on any HTTP request
9032     */
9033     /**
9034     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9035     */
9036     /**
9037     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9038     */
9039     multiSort: false,
9040     /**
9041     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9042     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9043     */
9044     remoteSort : false,
9045
9046     /**
9047     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9048      * loaded or when a record is removed. (defaults to false).
9049     */
9050     pruneModifiedRecords : false,
9051
9052     // private
9053     lastOptions : null,
9054
9055     /**
9056      * Add Records to the Store and fires the add event.
9057      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9058      */
9059     add : function(records){
9060         records = [].concat(records);
9061         for(var i = 0, len = records.length; i < len; i++){
9062             records[i].join(this);
9063         }
9064         var index = this.data.length;
9065         this.data.addAll(records);
9066         this.fireEvent("add", this, records, index);
9067     },
9068
9069     /**
9070      * Remove a Record from the Store and fires the remove event.
9071      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9072      */
9073     remove : function(record){
9074         var index = this.data.indexOf(record);
9075         this.data.removeAt(index);
9076         if(this.pruneModifiedRecords){
9077             this.modified.remove(record);
9078         }
9079         this.fireEvent("remove", this, record, index);
9080     },
9081
9082     /**
9083      * Remove all Records from the Store and fires the clear event.
9084      */
9085     removeAll : function(){
9086         this.data.clear();
9087         if(this.pruneModifiedRecords){
9088             this.modified = [];
9089         }
9090         this.fireEvent("clear", this);
9091     },
9092
9093     /**
9094      * Inserts Records to the Store at the given index and fires the add event.
9095      * @param {Number} index The start index at which to insert the passed Records.
9096      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9097      */
9098     insert : function(index, records){
9099         records = [].concat(records);
9100         for(var i = 0, len = records.length; i < len; i++){
9101             this.data.insert(index, records[i]);
9102             records[i].join(this);
9103         }
9104         this.fireEvent("add", this, records, index);
9105     },
9106
9107     /**
9108      * Get the index within the cache of the passed Record.
9109      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9110      * @return {Number} The index of the passed Record. Returns -1 if not found.
9111      */
9112     indexOf : function(record){
9113         return this.data.indexOf(record);
9114     },
9115
9116     /**
9117      * Get the index within the cache of the Record with the passed id.
9118      * @param {String} id The id of the Record to find.
9119      * @return {Number} The index of the Record. Returns -1 if not found.
9120      */
9121     indexOfId : function(id){
9122         return this.data.indexOfKey(id);
9123     },
9124
9125     /**
9126      * Get the Record with the specified id.
9127      * @param {String} id The id of the Record to find.
9128      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9129      */
9130     getById : function(id){
9131         return this.data.key(id);
9132     },
9133
9134     /**
9135      * Get the Record at the specified index.
9136      * @param {Number} index The index of the Record to find.
9137      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9138      */
9139     getAt : function(index){
9140         return this.data.itemAt(index);
9141     },
9142
9143     /**
9144      * Returns a range of Records between specified indices.
9145      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9146      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9147      * @return {Roo.data.Record[]} An array of Records
9148      */
9149     getRange : function(start, end){
9150         return this.data.getRange(start, end);
9151     },
9152
9153     // private
9154     storeOptions : function(o){
9155         o = Roo.apply({}, o);
9156         delete o.callback;
9157         delete o.scope;
9158         this.lastOptions = o;
9159     },
9160
9161     /**
9162      * Loads the Record cache from the configured Proxy using the configured Reader.
9163      * <p>
9164      * If using remote paging, then the first load call must specify the <em>start</em>
9165      * and <em>limit</em> properties in the options.params property to establish the initial
9166      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9167      * <p>
9168      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9169      * and this call will return before the new data has been loaded. Perform any post-processing
9170      * in a callback function, or in a "load" event handler.</strong>
9171      * <p>
9172      * @param {Object} options An object containing properties which control loading options:<ul>
9173      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9174      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9175      * passed the following arguments:<ul>
9176      * <li>r : Roo.data.Record[]</li>
9177      * <li>options: Options object from the load call</li>
9178      * <li>success: Boolean success indicator</li></ul></li>
9179      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9180      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9181      * </ul>
9182      */
9183     load : function(options){
9184         options = options || {};
9185         if(this.fireEvent("beforeload", this, options) !== false){
9186             this.storeOptions(options);
9187             var p = Roo.apply(options.params || {}, this.baseParams);
9188             // if meta was not loaded from remote source.. try requesting it.
9189             if (!this.reader.metaFromRemote) {
9190                 p._requestMeta = 1;
9191             }
9192             if(this.sortInfo && this.remoteSort){
9193                 var pn = this.paramNames;
9194                 p[pn["sort"]] = this.sortInfo.field;
9195                 p[pn["dir"]] = this.sortInfo.direction;
9196             }
9197             if (this.multiSort) {
9198                 var pn = this.paramNames;
9199                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9200             }
9201             
9202             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9203         }
9204     },
9205
9206     /**
9207      * Reloads the Record cache from the configured Proxy using the configured Reader and
9208      * the options from the last load operation performed.
9209      * @param {Object} options (optional) An object containing properties which may override the options
9210      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9211      * the most recently used options are reused).
9212      */
9213     reload : function(options){
9214         this.load(Roo.applyIf(options||{}, this.lastOptions));
9215     },
9216
9217     // private
9218     // Called as a callback by the Reader during a load operation.
9219     loadRecords : function(o, options, success){
9220         if(!o || success === false){
9221             if(success !== false){
9222                 this.fireEvent("load", this, [], options, o);
9223             }
9224             if(options.callback){
9225                 options.callback.call(options.scope || this, [], options, false);
9226             }
9227             return;
9228         }
9229         // if data returned failure - throw an exception.
9230         if (o.success === false) {
9231             // show a message if no listener is registered.
9232             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9233                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9234             }
9235             // loadmask wil be hooked into this..
9236             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9237             return;
9238         }
9239         var r = o.records, t = o.totalRecords || r.length;
9240         
9241         this.fireEvent("beforeloadadd", this, r, options, o);
9242         
9243         if(!options || options.add !== true){
9244             if(this.pruneModifiedRecords){
9245                 this.modified = [];
9246             }
9247             for(var i = 0, len = r.length; i < len; i++){
9248                 r[i].join(this);
9249             }
9250             if(this.snapshot){
9251                 this.data = this.snapshot;
9252                 delete this.snapshot;
9253             }
9254             this.data.clear();
9255             this.data.addAll(r);
9256             this.totalLength = t;
9257             this.applySort();
9258             this.fireEvent("datachanged", this);
9259         }else{
9260             this.totalLength = Math.max(t, this.data.length+r.length);
9261             this.add(r);
9262         }
9263         this.fireEvent("load", this, r, options, o);
9264         if(options.callback){
9265             options.callback.call(options.scope || this, r, options, true);
9266         }
9267     },
9268
9269
9270     /**
9271      * Loads data from a passed data block. A Reader which understands the format of the data
9272      * must have been configured in the constructor.
9273      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9274      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9275      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9276      */
9277     loadData : function(o, append){
9278         var r = this.reader.readRecords(o);
9279         this.loadRecords(r, {add: append}, true);
9280     },
9281
9282     /**
9283      * Gets the number of cached records.
9284      * <p>
9285      * <em>If using paging, this may not be the total size of the dataset. If the data object
9286      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9287      * the data set size</em>
9288      */
9289     getCount : function(){
9290         return this.data.length || 0;
9291     },
9292
9293     /**
9294      * Gets the total number of records in the dataset as returned by the server.
9295      * <p>
9296      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9297      * the dataset size</em>
9298      */
9299     getTotalCount : function(){
9300         return this.totalLength || 0;
9301     },
9302
9303     /**
9304      * Returns the sort state of the Store as an object with two properties:
9305      * <pre><code>
9306  field {String} The name of the field by which the Records are sorted
9307  direction {String} The sort order, "ASC" or "DESC"
9308      * </code></pre>
9309      */
9310     getSortState : function(){
9311         return this.sortInfo;
9312     },
9313
9314     // private
9315     applySort : function(){
9316         if(this.sortInfo && !this.remoteSort){
9317             var s = this.sortInfo, f = s.field;
9318             var st = this.fields.get(f).sortType;
9319             var fn = function(r1, r2){
9320                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9321                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9322             };
9323             this.data.sort(s.direction, fn);
9324             if(this.snapshot && this.snapshot != this.data){
9325                 this.snapshot.sort(s.direction, fn);
9326             }
9327         }
9328     },
9329
9330     /**
9331      * Sets the default sort column and order to be used by the next load operation.
9332      * @param {String} fieldName The name of the field to sort by.
9333      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9334      */
9335     setDefaultSort : function(field, dir){
9336         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9337     },
9338
9339     /**
9340      * Sort the Records.
9341      * If remote sorting is used, the sort is performed on the server, and the cache is
9342      * reloaded. If local sorting is used, the cache is sorted internally.
9343      * @param {String} fieldName The name of the field to sort by.
9344      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9345      */
9346     sort : function(fieldName, dir){
9347         var f = this.fields.get(fieldName);
9348         if(!dir){
9349             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9350             
9351             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9352                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9353             }else{
9354                 dir = f.sortDir;
9355             }
9356         }
9357         this.sortToggle[f.name] = dir;
9358         this.sortInfo = {field: f.name, direction: dir};
9359         if(!this.remoteSort){
9360             this.applySort();
9361             this.fireEvent("datachanged", this);
9362         }else{
9363             this.load(this.lastOptions);
9364         }
9365     },
9366
9367     /**
9368      * Calls the specified function for each of the Records in the cache.
9369      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9370      * Returning <em>false</em> aborts and exits the iteration.
9371      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9372      */
9373     each : function(fn, scope){
9374         this.data.each(fn, scope);
9375     },
9376
9377     /**
9378      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9379      * (e.g., during paging).
9380      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9381      */
9382     getModifiedRecords : function(){
9383         return this.modified;
9384     },
9385
9386     // private
9387     createFilterFn : function(property, value, anyMatch){
9388         if(!value.exec){ // not a regex
9389             value = String(value);
9390             if(value.length == 0){
9391                 return false;
9392             }
9393             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9394         }
9395         return function(r){
9396             return value.test(r.data[property]);
9397         };
9398     },
9399
9400     /**
9401      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9402      * @param {String} property A field on your records
9403      * @param {Number} start The record index to start at (defaults to 0)
9404      * @param {Number} end The last record index to include (defaults to length - 1)
9405      * @return {Number} The sum
9406      */
9407     sum : function(property, start, end){
9408         var rs = this.data.items, v = 0;
9409         start = start || 0;
9410         end = (end || end === 0) ? end : rs.length-1;
9411
9412         for(var i = start; i <= end; i++){
9413             v += (rs[i].data[property] || 0);
9414         }
9415         return v;
9416     },
9417
9418     /**
9419      * Filter the records by a specified property.
9420      * @param {String} field A field on your records
9421      * @param {String/RegExp} value Either a string that the field
9422      * should start with or a RegExp to test against the field
9423      * @param {Boolean} anyMatch True to match any part not just the beginning
9424      */
9425     filter : function(property, value, anyMatch){
9426         var fn = this.createFilterFn(property, value, anyMatch);
9427         return fn ? this.filterBy(fn) : this.clearFilter();
9428     },
9429
9430     /**
9431      * Filter by a function. The specified function will be called with each
9432      * record in this data source. If the function returns true the record is included,
9433      * otherwise it is filtered.
9434      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9435      * @param {Object} scope (optional) The scope of the function (defaults to this)
9436      */
9437     filterBy : function(fn, scope){
9438         this.snapshot = this.snapshot || this.data;
9439         this.data = this.queryBy(fn, scope||this);
9440         this.fireEvent("datachanged", this);
9441     },
9442
9443     /**
9444      * Query the records by a specified property.
9445      * @param {String} field A field on your records
9446      * @param {String/RegExp} value Either a string that the field
9447      * should start with or a RegExp to test against the field
9448      * @param {Boolean} anyMatch True to match any part not just the beginning
9449      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9450      */
9451     query : function(property, value, anyMatch){
9452         var fn = this.createFilterFn(property, value, anyMatch);
9453         return fn ? this.queryBy(fn) : this.data.clone();
9454     },
9455
9456     /**
9457      * Query by a function. The specified function will be called with each
9458      * record in this data source. If the function returns true the record is included
9459      * in the results.
9460      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9461      * @param {Object} scope (optional) The scope of the function (defaults to this)
9462       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9463      **/
9464     queryBy : function(fn, scope){
9465         var data = this.snapshot || this.data;
9466         return data.filterBy(fn, scope||this);
9467     },
9468
9469     /**
9470      * Collects unique values for a particular dataIndex from this store.
9471      * @param {String} dataIndex The property to collect
9472      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9473      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9474      * @return {Array} An array of the unique values
9475      **/
9476     collect : function(dataIndex, allowNull, bypassFilter){
9477         var d = (bypassFilter === true && this.snapshot) ?
9478                 this.snapshot.items : this.data.items;
9479         var v, sv, r = [], l = {};
9480         for(var i = 0, len = d.length; i < len; i++){
9481             v = d[i].data[dataIndex];
9482             sv = String(v);
9483             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9484                 l[sv] = true;
9485                 r[r.length] = v;
9486             }
9487         }
9488         return r;
9489     },
9490
9491     /**
9492      * Revert to a view of the Record cache with no filtering applied.
9493      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9494      */
9495     clearFilter : function(suppressEvent){
9496         if(this.snapshot && this.snapshot != this.data){
9497             this.data = this.snapshot;
9498             delete this.snapshot;
9499             if(suppressEvent !== true){
9500                 this.fireEvent("datachanged", this);
9501             }
9502         }
9503     },
9504
9505     // private
9506     afterEdit : function(record){
9507         if(this.modified.indexOf(record) == -1){
9508             this.modified.push(record);
9509         }
9510         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9511     },
9512     
9513     // private
9514     afterReject : function(record){
9515         this.modified.remove(record);
9516         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9517     },
9518
9519     // private
9520     afterCommit : function(record){
9521         this.modified.remove(record);
9522         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9523     },
9524
9525     /**
9526      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9527      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9528      */
9529     commitChanges : function(){
9530         var m = this.modified.slice(0);
9531         this.modified = [];
9532         for(var i = 0, len = m.length; i < len; i++){
9533             m[i].commit();
9534         }
9535     },
9536
9537     /**
9538      * Cancel outstanding changes on all changed records.
9539      */
9540     rejectChanges : function(){
9541         var m = this.modified.slice(0);
9542         this.modified = [];
9543         for(var i = 0, len = m.length; i < len; i++){
9544             m[i].reject();
9545         }
9546     },
9547
9548     onMetaChange : function(meta, rtype, o){
9549         this.recordType = rtype;
9550         this.fields = rtype.prototype.fields;
9551         delete this.snapshot;
9552         this.sortInfo = meta.sortInfo || this.sortInfo;
9553         this.modified = [];
9554         this.fireEvent('metachange', this, this.reader.meta);
9555     },
9556     
9557     moveIndex : function(data, type)
9558     {
9559         var index = this.indexOf(data);
9560         
9561         var newIndex = index + type;
9562         
9563         this.remove(data);
9564         
9565         this.insert(newIndex, data);
9566         
9567     }
9568 });/*
9569  * Based on:
9570  * Ext JS Library 1.1.1
9571  * Copyright(c) 2006-2007, Ext JS, LLC.
9572  *
9573  * Originally Released Under LGPL - original licence link has changed is not relivant.
9574  *
9575  * Fork - LGPL
9576  * <script type="text/javascript">
9577  */
9578
9579 /**
9580  * @class Roo.data.SimpleStore
9581  * @extends Roo.data.Store
9582  * Small helper class to make creating Stores from Array data easier.
9583  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9584  * @cfg {Array} fields An array of field definition objects, or field name strings.
9585  * @cfg {Array} data The multi-dimensional array of data
9586  * @constructor
9587  * @param {Object} config
9588  */
9589 Roo.data.SimpleStore = function(config){
9590     Roo.data.SimpleStore.superclass.constructor.call(this, {
9591         isLocal : true,
9592         reader: new Roo.data.ArrayReader({
9593                 id: config.id
9594             },
9595             Roo.data.Record.create(config.fields)
9596         ),
9597         proxy : new Roo.data.MemoryProxy(config.data)
9598     });
9599     this.load();
9600 };
9601 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9602  * Based on:
9603  * Ext JS Library 1.1.1
9604  * Copyright(c) 2006-2007, Ext JS, LLC.
9605  *
9606  * Originally Released Under LGPL - original licence link has changed is not relivant.
9607  *
9608  * Fork - LGPL
9609  * <script type="text/javascript">
9610  */
9611
9612 /**
9613 /**
9614  * @extends Roo.data.Store
9615  * @class Roo.data.JsonStore
9616  * Small helper class to make creating Stores for JSON data easier. <br/>
9617 <pre><code>
9618 var store = new Roo.data.JsonStore({
9619     url: 'get-images.php',
9620     root: 'images',
9621     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9622 });
9623 </code></pre>
9624  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9625  * JsonReader and HttpProxy (unless inline data is provided).</b>
9626  * @cfg {Array} fields An array of field definition objects, or field name strings.
9627  * @constructor
9628  * @param {Object} config
9629  */
9630 Roo.data.JsonStore = function(c){
9631     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9632         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9633         reader: new Roo.data.JsonReader(c, c.fields)
9634     }));
9635 };
9636 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9637  * Based on:
9638  * Ext JS Library 1.1.1
9639  * Copyright(c) 2006-2007, Ext JS, LLC.
9640  *
9641  * Originally Released Under LGPL - original licence link has changed is not relivant.
9642  *
9643  * Fork - LGPL
9644  * <script type="text/javascript">
9645  */
9646
9647  
9648 Roo.data.Field = function(config){
9649     if(typeof config == "string"){
9650         config = {name: config};
9651     }
9652     Roo.apply(this, config);
9653     
9654     if(!this.type){
9655         this.type = "auto";
9656     }
9657     
9658     var st = Roo.data.SortTypes;
9659     // named sortTypes are supported, here we look them up
9660     if(typeof this.sortType == "string"){
9661         this.sortType = st[this.sortType];
9662     }
9663     
9664     // set default sortType for strings and dates
9665     if(!this.sortType){
9666         switch(this.type){
9667             case "string":
9668                 this.sortType = st.asUCString;
9669                 break;
9670             case "date":
9671                 this.sortType = st.asDate;
9672                 break;
9673             default:
9674                 this.sortType = st.none;
9675         }
9676     }
9677
9678     // define once
9679     var stripRe = /[\$,%]/g;
9680
9681     // prebuilt conversion function for this field, instead of
9682     // switching every time we're reading a value
9683     if(!this.convert){
9684         var cv, dateFormat = this.dateFormat;
9685         switch(this.type){
9686             case "":
9687             case "auto":
9688             case undefined:
9689                 cv = function(v){ return v; };
9690                 break;
9691             case "string":
9692                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9693                 break;
9694             case "int":
9695                 cv = function(v){
9696                     return v !== undefined && v !== null && v !== '' ?
9697                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9698                     };
9699                 break;
9700             case "float":
9701                 cv = function(v){
9702                     return v !== undefined && v !== null && v !== '' ?
9703                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9704                     };
9705                 break;
9706             case "bool":
9707             case "boolean":
9708                 cv = function(v){ return v === true || v === "true" || v == 1; };
9709                 break;
9710             case "date":
9711                 cv = function(v){
9712                     if(!v){
9713                         return '';
9714                     }
9715                     if(v instanceof Date){
9716                         return v;
9717                     }
9718                     if(dateFormat){
9719                         if(dateFormat == "timestamp"){
9720                             return new Date(v*1000);
9721                         }
9722                         return Date.parseDate(v, dateFormat);
9723                     }
9724                     var parsed = Date.parse(v);
9725                     return parsed ? new Date(parsed) : null;
9726                 };
9727              break;
9728             
9729         }
9730         this.convert = cv;
9731     }
9732 };
9733
9734 Roo.data.Field.prototype = {
9735     dateFormat: null,
9736     defaultValue: "",
9737     mapping: null,
9738     sortType : null,
9739     sortDir : "ASC"
9740 };/*
9741  * Based on:
9742  * Ext JS Library 1.1.1
9743  * Copyright(c) 2006-2007, Ext JS, LLC.
9744  *
9745  * Originally Released Under LGPL - original licence link has changed is not relivant.
9746  *
9747  * Fork - LGPL
9748  * <script type="text/javascript">
9749  */
9750  
9751 // Base class for reading structured data from a data source.  This class is intended to be
9752 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9753
9754 /**
9755  * @class Roo.data.DataReader
9756  * Base class for reading structured data from a data source.  This class is intended to be
9757  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9758  */
9759
9760 Roo.data.DataReader = function(meta, recordType){
9761     
9762     this.meta = meta;
9763     
9764     this.recordType = recordType instanceof Array ? 
9765         Roo.data.Record.create(recordType) : recordType;
9766 };
9767
9768 Roo.data.DataReader.prototype = {
9769      /**
9770      * Create an empty record
9771      * @param {Object} data (optional) - overlay some values
9772      * @return {Roo.data.Record} record created.
9773      */
9774     newRow :  function(d) {
9775         var da =  {};
9776         this.recordType.prototype.fields.each(function(c) {
9777             switch( c.type) {
9778                 case 'int' : da[c.name] = 0; break;
9779                 case 'date' : da[c.name] = new Date(); break;
9780                 case 'float' : da[c.name] = 0.0; break;
9781                 case 'boolean' : da[c.name] = false; break;
9782                 default : da[c.name] = ""; break;
9783             }
9784             
9785         });
9786         return new this.recordType(Roo.apply(da, d));
9787     }
9788     
9789 };/*
9790  * Based on:
9791  * Ext JS Library 1.1.1
9792  * Copyright(c) 2006-2007, Ext JS, LLC.
9793  *
9794  * Originally Released Under LGPL - original licence link has changed is not relivant.
9795  *
9796  * Fork - LGPL
9797  * <script type="text/javascript">
9798  */
9799
9800 /**
9801  * @class Roo.data.DataProxy
9802  * @extends Roo.data.Observable
9803  * This class is an abstract base class for implementations which provide retrieval of
9804  * unformatted data objects.<br>
9805  * <p>
9806  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9807  * (of the appropriate type which knows how to parse the data object) to provide a block of
9808  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9809  * <p>
9810  * Custom implementations must implement the load method as described in
9811  * {@link Roo.data.HttpProxy#load}.
9812  */
9813 Roo.data.DataProxy = function(){
9814     this.addEvents({
9815         /**
9816          * @event beforeload
9817          * Fires before a network request is made to retrieve a data object.
9818          * @param {Object} This DataProxy object.
9819          * @param {Object} params The params parameter to the load function.
9820          */
9821         beforeload : true,
9822         /**
9823          * @event load
9824          * Fires before the load method's callback is called.
9825          * @param {Object} This DataProxy object.
9826          * @param {Object} o The data object.
9827          * @param {Object} arg The callback argument object passed to the load function.
9828          */
9829         load : true,
9830         /**
9831          * @event loadexception
9832          * Fires if an Exception occurs during data retrieval.
9833          * @param {Object} This DataProxy object.
9834          * @param {Object} o The data object.
9835          * @param {Object} arg The callback argument object passed to the load function.
9836          * @param {Object} e The Exception.
9837          */
9838         loadexception : true
9839     });
9840     Roo.data.DataProxy.superclass.constructor.call(this);
9841 };
9842
9843 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9844
9845     /**
9846      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9847      */
9848 /*
9849  * Based on:
9850  * Ext JS Library 1.1.1
9851  * Copyright(c) 2006-2007, Ext JS, LLC.
9852  *
9853  * Originally Released Under LGPL - original licence link has changed is not relivant.
9854  *
9855  * Fork - LGPL
9856  * <script type="text/javascript">
9857  */
9858 /**
9859  * @class Roo.data.MemoryProxy
9860  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9861  * to the Reader when its load method is called.
9862  * @constructor
9863  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9864  */
9865 Roo.data.MemoryProxy = function(data){
9866     if (data.data) {
9867         data = data.data;
9868     }
9869     Roo.data.MemoryProxy.superclass.constructor.call(this);
9870     this.data = data;
9871 };
9872
9873 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9874     /**
9875      * Load data from the requested source (in this case an in-memory
9876      * data object passed to the constructor), read the data object into
9877      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9878      * process that block using the passed callback.
9879      * @param {Object} params This parameter is not used by the MemoryProxy class.
9880      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9881      * object into a block of Roo.data.Records.
9882      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9883      * The function must be passed <ul>
9884      * <li>The Record block object</li>
9885      * <li>The "arg" argument from the load function</li>
9886      * <li>A boolean success indicator</li>
9887      * </ul>
9888      * @param {Object} scope The scope in which to call the callback
9889      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9890      */
9891     load : function(params, reader, callback, scope, arg){
9892         params = params || {};
9893         var result;
9894         try {
9895             result = reader.readRecords(this.data);
9896         }catch(e){
9897             this.fireEvent("loadexception", this, arg, null, e);
9898             callback.call(scope, null, arg, false);
9899             return;
9900         }
9901         callback.call(scope, result, arg, true);
9902     },
9903     
9904     // private
9905     update : function(params, records){
9906         
9907     }
9908 });/*
9909  * Based on:
9910  * Ext JS Library 1.1.1
9911  * Copyright(c) 2006-2007, Ext JS, LLC.
9912  *
9913  * Originally Released Under LGPL - original licence link has changed is not relivant.
9914  *
9915  * Fork - LGPL
9916  * <script type="text/javascript">
9917  */
9918 /**
9919  * @class Roo.data.HttpProxy
9920  * @extends Roo.data.DataProxy
9921  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9922  * configured to reference a certain URL.<br><br>
9923  * <p>
9924  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9925  * from which the running page was served.<br><br>
9926  * <p>
9927  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9928  * <p>
9929  * Be aware that to enable the browser to parse an XML document, the server must set
9930  * the Content-Type header in the HTTP response to "text/xml".
9931  * @constructor
9932  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9933  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9934  * will be used to make the request.
9935  */
9936 Roo.data.HttpProxy = function(conn){
9937     Roo.data.HttpProxy.superclass.constructor.call(this);
9938     // is conn a conn config or a real conn?
9939     this.conn = conn;
9940     this.useAjax = !conn || !conn.events;
9941   
9942 };
9943
9944 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9945     // thse are take from connection...
9946     
9947     /**
9948      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9949      */
9950     /**
9951      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9952      * extra parameters to each request made by this object. (defaults to undefined)
9953      */
9954     /**
9955      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9956      *  to each request made by this object. (defaults to undefined)
9957      */
9958     /**
9959      * @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)
9960      */
9961     /**
9962      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9963      */
9964      /**
9965      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9966      * @type Boolean
9967      */
9968   
9969
9970     /**
9971      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9972      * @type Boolean
9973      */
9974     /**
9975      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9976      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9977      * a finer-grained basis than the DataProxy events.
9978      */
9979     getConnection : function(){
9980         return this.useAjax ? Roo.Ajax : this.conn;
9981     },
9982
9983     /**
9984      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9985      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9986      * process that block using the passed callback.
9987      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9988      * for the request to the remote server.
9989      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9990      * object into a block of Roo.data.Records.
9991      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9992      * The function must be passed <ul>
9993      * <li>The Record block object</li>
9994      * <li>The "arg" argument from the load function</li>
9995      * <li>A boolean success indicator</li>
9996      * </ul>
9997      * @param {Object} scope The scope in which to call the callback
9998      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9999      */
10000     load : function(params, reader, callback, scope, arg){
10001         if(this.fireEvent("beforeload", this, params) !== false){
10002             var  o = {
10003                 params : params || {},
10004                 request: {
10005                     callback : callback,
10006                     scope : scope,
10007                     arg : arg
10008                 },
10009                 reader: reader,
10010                 callback : this.loadResponse,
10011                 scope: this
10012             };
10013             if(this.useAjax){
10014                 Roo.applyIf(o, this.conn);
10015                 if(this.activeRequest){
10016                     Roo.Ajax.abort(this.activeRequest);
10017                 }
10018                 this.activeRequest = Roo.Ajax.request(o);
10019             }else{
10020                 this.conn.request(o);
10021             }
10022         }else{
10023             callback.call(scope||this, null, arg, false);
10024         }
10025     },
10026
10027     // private
10028     loadResponse : function(o, success, response){
10029         delete this.activeRequest;
10030         if(!success){
10031             this.fireEvent("loadexception", this, o, response);
10032             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10033             return;
10034         }
10035         var result;
10036         try {
10037             result = o.reader.read(response);
10038         }catch(e){
10039             this.fireEvent("loadexception", this, o, response, e);
10040             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10041             return;
10042         }
10043         
10044         this.fireEvent("load", this, o, o.request.arg);
10045         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10046     },
10047
10048     // private
10049     update : function(dataSet){
10050
10051     },
10052
10053     // private
10054     updateResponse : function(dataSet){
10055
10056     }
10057 });/*
10058  * Based on:
10059  * Ext JS Library 1.1.1
10060  * Copyright(c) 2006-2007, Ext JS, LLC.
10061  *
10062  * Originally Released Under LGPL - original licence link has changed is not relivant.
10063  *
10064  * Fork - LGPL
10065  * <script type="text/javascript">
10066  */
10067
10068 /**
10069  * @class Roo.data.ScriptTagProxy
10070  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10071  * other than the originating domain of the running page.<br><br>
10072  * <p>
10073  * <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
10074  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10075  * <p>
10076  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10077  * source code that is used as the source inside a &lt;script> tag.<br><br>
10078  * <p>
10079  * In order for the browser to process the returned data, the server must wrap the data object
10080  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10081  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10082  * depending on whether the callback name was passed:
10083  * <p>
10084  * <pre><code>
10085 boolean scriptTag = false;
10086 String cb = request.getParameter("callback");
10087 if (cb != null) {
10088     scriptTag = true;
10089     response.setContentType("text/javascript");
10090 } else {
10091     response.setContentType("application/x-json");
10092 }
10093 Writer out = response.getWriter();
10094 if (scriptTag) {
10095     out.write(cb + "(");
10096 }
10097 out.print(dataBlock.toJsonString());
10098 if (scriptTag) {
10099     out.write(");");
10100 }
10101 </pre></code>
10102  *
10103  * @constructor
10104  * @param {Object} config A configuration object.
10105  */
10106 Roo.data.ScriptTagProxy = function(config){
10107     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10108     Roo.apply(this, config);
10109     this.head = document.getElementsByTagName("head")[0];
10110 };
10111
10112 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10113
10114 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10115     /**
10116      * @cfg {String} url The URL from which to request the data object.
10117      */
10118     /**
10119      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10120      */
10121     timeout : 30000,
10122     /**
10123      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10124      * the server the name of the callback function set up by the load call to process the returned data object.
10125      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10126      * javascript output which calls this named function passing the data object as its only parameter.
10127      */
10128     callbackParam : "callback",
10129     /**
10130      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10131      * name to the request.
10132      */
10133     nocache : true,
10134
10135     /**
10136      * Load data from the configured URL, read the data object into
10137      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10138      * process that block using the passed callback.
10139      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10140      * for the request to the remote server.
10141      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10142      * object into a block of Roo.data.Records.
10143      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10144      * The function must be passed <ul>
10145      * <li>The Record block object</li>
10146      * <li>The "arg" argument from the load function</li>
10147      * <li>A boolean success indicator</li>
10148      * </ul>
10149      * @param {Object} scope The scope in which to call the callback
10150      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10151      */
10152     load : function(params, reader, callback, scope, arg){
10153         if(this.fireEvent("beforeload", this, params) !== false){
10154
10155             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10156
10157             var url = this.url;
10158             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10159             if(this.nocache){
10160                 url += "&_dc=" + (new Date().getTime());
10161             }
10162             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10163             var trans = {
10164                 id : transId,
10165                 cb : "stcCallback"+transId,
10166                 scriptId : "stcScript"+transId,
10167                 params : params,
10168                 arg : arg,
10169                 url : url,
10170                 callback : callback,
10171                 scope : scope,
10172                 reader : reader
10173             };
10174             var conn = this;
10175
10176             window[trans.cb] = function(o){
10177                 conn.handleResponse(o, trans);
10178             };
10179
10180             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10181
10182             if(this.autoAbort !== false){
10183                 this.abort();
10184             }
10185
10186             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10187
10188             var script = document.createElement("script");
10189             script.setAttribute("src", url);
10190             script.setAttribute("type", "text/javascript");
10191             script.setAttribute("id", trans.scriptId);
10192             this.head.appendChild(script);
10193
10194             this.trans = trans;
10195         }else{
10196             callback.call(scope||this, null, arg, false);
10197         }
10198     },
10199
10200     // private
10201     isLoading : function(){
10202         return this.trans ? true : false;
10203     },
10204
10205     /**
10206      * Abort the current server request.
10207      */
10208     abort : function(){
10209         if(this.isLoading()){
10210             this.destroyTrans(this.trans);
10211         }
10212     },
10213
10214     // private
10215     destroyTrans : function(trans, isLoaded){
10216         this.head.removeChild(document.getElementById(trans.scriptId));
10217         clearTimeout(trans.timeoutId);
10218         if(isLoaded){
10219             window[trans.cb] = undefined;
10220             try{
10221                 delete window[trans.cb];
10222             }catch(e){}
10223         }else{
10224             // if hasn't been loaded, wait for load to remove it to prevent script error
10225             window[trans.cb] = function(){
10226                 window[trans.cb] = undefined;
10227                 try{
10228                     delete window[trans.cb];
10229                 }catch(e){}
10230             };
10231         }
10232     },
10233
10234     // private
10235     handleResponse : function(o, trans){
10236         this.trans = false;
10237         this.destroyTrans(trans, true);
10238         var result;
10239         try {
10240             result = trans.reader.readRecords(o);
10241         }catch(e){
10242             this.fireEvent("loadexception", this, o, trans.arg, e);
10243             trans.callback.call(trans.scope||window, null, trans.arg, false);
10244             return;
10245         }
10246         this.fireEvent("load", this, o, trans.arg);
10247         trans.callback.call(trans.scope||window, result, trans.arg, true);
10248     },
10249
10250     // private
10251     handleFailure : function(trans){
10252         this.trans = false;
10253         this.destroyTrans(trans, false);
10254         this.fireEvent("loadexception", this, null, trans.arg);
10255         trans.callback.call(trans.scope||window, null, trans.arg, false);
10256     }
10257 });/*
10258  * Based on:
10259  * Ext JS Library 1.1.1
10260  * Copyright(c) 2006-2007, Ext JS, LLC.
10261  *
10262  * Originally Released Under LGPL - original licence link has changed is not relivant.
10263  *
10264  * Fork - LGPL
10265  * <script type="text/javascript">
10266  */
10267
10268 /**
10269  * @class Roo.data.JsonReader
10270  * @extends Roo.data.DataReader
10271  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10272  * based on mappings in a provided Roo.data.Record constructor.
10273  * 
10274  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10275  * in the reply previously. 
10276  * 
10277  * <p>
10278  * Example code:
10279  * <pre><code>
10280 var RecordDef = Roo.data.Record.create([
10281     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10282     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10283 ]);
10284 var myReader = new Roo.data.JsonReader({
10285     totalProperty: "results",    // The property which contains the total dataset size (optional)
10286     root: "rows",                // The property which contains an Array of row objects
10287     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10288 }, RecordDef);
10289 </code></pre>
10290  * <p>
10291  * This would consume a JSON file like this:
10292  * <pre><code>
10293 { 'results': 2, 'rows': [
10294     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10295     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10296 }
10297 </code></pre>
10298  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10299  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10300  * paged from the remote server.
10301  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10302  * @cfg {String} root name of the property which contains the Array of row objects.
10303  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10304  * @constructor
10305  * Create a new JsonReader
10306  * @param {Object} meta Metadata configuration options
10307  * @param {Object} recordType Either an Array of field definition objects,
10308  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10309  */
10310 Roo.data.JsonReader = function(meta, recordType){
10311     
10312     meta = meta || {};
10313     // set some defaults:
10314     Roo.applyIf(meta, {
10315         totalProperty: 'total',
10316         successProperty : 'success',
10317         root : 'data',
10318         id : 'id'
10319     });
10320     
10321     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10322 };
10323 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10324     
10325     /**
10326      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10327      * Used by Store query builder to append _requestMeta to params.
10328      * 
10329      */
10330     metaFromRemote : false,
10331     /**
10332      * This method is only used by a DataProxy which has retrieved data from a remote server.
10333      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10334      * @return {Object} data A data block which is used by an Roo.data.Store object as
10335      * a cache of Roo.data.Records.
10336      */
10337     read : function(response){
10338         var json = response.responseText;
10339        
10340         var o = /* eval:var:o */ eval("("+json+")");
10341         if(!o) {
10342             throw {message: "JsonReader.read: Json object not found"};
10343         }
10344         
10345         if(o.metaData){
10346             
10347             delete this.ef;
10348             this.metaFromRemote = true;
10349             this.meta = o.metaData;
10350             this.recordType = Roo.data.Record.create(o.metaData.fields);
10351             this.onMetaChange(this.meta, this.recordType, o);
10352         }
10353         return this.readRecords(o);
10354     },
10355
10356     // private function a store will implement
10357     onMetaChange : function(meta, recordType, o){
10358
10359     },
10360
10361     /**
10362          * @ignore
10363          */
10364     simpleAccess: function(obj, subsc) {
10365         return obj[subsc];
10366     },
10367
10368         /**
10369          * @ignore
10370          */
10371     getJsonAccessor: function(){
10372         var re = /[\[\.]/;
10373         return function(expr) {
10374             try {
10375                 return(re.test(expr))
10376                     ? new Function("obj", "return obj." + expr)
10377                     : function(obj){
10378                         return obj[expr];
10379                     };
10380             } catch(e){}
10381             return Roo.emptyFn;
10382         };
10383     }(),
10384
10385     /**
10386      * Create a data block containing Roo.data.Records from an XML document.
10387      * @param {Object} o An object which contains an Array of row objects in the property specified
10388      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10389      * which contains the total size of the dataset.
10390      * @return {Object} data A data block which is used by an Roo.data.Store object as
10391      * a cache of Roo.data.Records.
10392      */
10393     readRecords : function(o){
10394         /**
10395          * After any data loads, the raw JSON data is available for further custom processing.
10396          * @type Object
10397          */
10398         this.o = o;
10399         var s = this.meta, Record = this.recordType,
10400             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10401
10402 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10403         if (!this.ef) {
10404             if(s.totalProperty) {
10405                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10406                 }
10407                 if(s.successProperty) {
10408                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10409                 }
10410                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10411                 if (s.id) {
10412                         var g = this.getJsonAccessor(s.id);
10413                         this.getId = function(rec) {
10414                                 var r = g(rec);  
10415                                 return (r === undefined || r === "") ? null : r;
10416                         };
10417                 } else {
10418                         this.getId = function(){return null;};
10419                 }
10420             this.ef = [];
10421             for(var jj = 0; jj < fl; jj++){
10422                 f = fi[jj];
10423                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10424                 this.ef[jj] = this.getJsonAccessor(map);
10425             }
10426         }
10427
10428         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10429         if(s.totalProperty){
10430             var vt = parseInt(this.getTotal(o), 10);
10431             if(!isNaN(vt)){
10432                 totalRecords = vt;
10433             }
10434         }
10435         if(s.successProperty){
10436             var vs = this.getSuccess(o);
10437             if(vs === false || vs === 'false'){
10438                 success = false;
10439             }
10440         }
10441         var records = [];
10442         for(var i = 0; i < c; i++){
10443                 var n = root[i];
10444             var values = {};
10445             var id = this.getId(n);
10446             for(var j = 0; j < fl; j++){
10447                 f = fi[j];
10448             var v = this.ef[j](n);
10449             if (!f.convert) {
10450                 Roo.log('missing convert for ' + f.name);
10451                 Roo.log(f);
10452                 continue;
10453             }
10454             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10455             }
10456             var record = new Record(values, id);
10457             record.json = n;
10458             records[i] = record;
10459         }
10460         return {
10461             raw : o,
10462             success : success,
10463             records : records,
10464             totalRecords : totalRecords
10465         };
10466     }
10467 });/*
10468  * Based on:
10469  * Ext JS Library 1.1.1
10470  * Copyright(c) 2006-2007, Ext JS, LLC.
10471  *
10472  * Originally Released Under LGPL - original licence link has changed is not relivant.
10473  *
10474  * Fork - LGPL
10475  * <script type="text/javascript">
10476  */
10477
10478 /**
10479  * @class Roo.data.ArrayReader
10480  * @extends Roo.data.DataReader
10481  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10482  * Each element of that Array represents a row of data fields. The
10483  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10484  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10485  * <p>
10486  * Example code:.
10487  * <pre><code>
10488 var RecordDef = Roo.data.Record.create([
10489     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10490     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10491 ]);
10492 var myReader = new Roo.data.ArrayReader({
10493     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10494 }, RecordDef);
10495 </code></pre>
10496  * <p>
10497  * This would consume an Array like this:
10498  * <pre><code>
10499 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10500   </code></pre>
10501  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10502  * @constructor
10503  * Create a new JsonReader
10504  * @param {Object} meta Metadata configuration options.
10505  * @param {Object} recordType Either an Array of field definition objects
10506  * as specified to {@link Roo.data.Record#create},
10507  * or an {@link Roo.data.Record} object
10508  * created using {@link Roo.data.Record#create}.
10509  */
10510 Roo.data.ArrayReader = function(meta, recordType){
10511     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10512 };
10513
10514 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10515     /**
10516      * Create a data block containing Roo.data.Records from an XML document.
10517      * @param {Object} o An Array of row objects which represents the dataset.
10518      * @return {Object} data A data block which is used by an Roo.data.Store object as
10519      * a cache of Roo.data.Records.
10520      */
10521     readRecords : function(o){
10522         var sid = this.meta ? this.meta.id : null;
10523         var recordType = this.recordType, fields = recordType.prototype.fields;
10524         var records = [];
10525         var root = o;
10526             for(var i = 0; i < root.length; i++){
10527                     var n = root[i];
10528                 var values = {};
10529                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10530                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10531                 var f = fields.items[j];
10532                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10533                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10534                 v = f.convert(v);
10535                 values[f.name] = v;
10536             }
10537                 var record = new recordType(values, id);
10538                 record.json = n;
10539                 records[records.length] = record;
10540             }
10541             return {
10542                 records : records,
10543                 totalRecords : records.length
10544             };
10545     }
10546 });/*
10547  * - LGPL
10548  * * 
10549  */
10550
10551 /**
10552  * @class Roo.bootstrap.ComboBox
10553  * @extends Roo.bootstrap.TriggerField
10554  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10555  * @cfg {Boolean} append (true|false) default false
10556  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10557  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10558  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10559  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10560  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10561  * @constructor
10562  * Create a new ComboBox.
10563  * @param {Object} config Configuration options
10564  */
10565 Roo.bootstrap.ComboBox = function(config){
10566     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10567     this.addEvents({
10568         /**
10569          * @event expand
10570          * Fires when the dropdown list is expanded
10571              * @param {Roo.bootstrap.ComboBox} combo This combo box
10572              */
10573         'expand' : true,
10574         /**
10575          * @event collapse
10576          * Fires when the dropdown list is collapsed
10577              * @param {Roo.bootstrap.ComboBox} combo This combo box
10578              */
10579         'collapse' : true,
10580         /**
10581          * @event beforeselect
10582          * Fires before a list item is selected. Return false to cancel the selection.
10583              * @param {Roo.bootstrap.ComboBox} combo This combo box
10584              * @param {Roo.data.Record} record The data record returned from the underlying store
10585              * @param {Number} index The index of the selected item in the dropdown list
10586              */
10587         'beforeselect' : true,
10588         /**
10589          * @event select
10590          * Fires when a list item is selected
10591              * @param {Roo.bootstrap.ComboBox} combo This combo box
10592              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10593              * @param {Number} index The index of the selected item in the dropdown list
10594              */
10595         'select' : true,
10596         /**
10597          * @event beforequery
10598          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10599          * The event object passed has these properties:
10600              * @param {Roo.bootstrap.ComboBox} combo This combo box
10601              * @param {String} query The query
10602              * @param {Boolean} forceAll true to force "all" query
10603              * @param {Boolean} cancel true to cancel the query
10604              * @param {Object} e The query event object
10605              */
10606         'beforequery': true,
10607          /**
10608          * @event add
10609          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10610              * @param {Roo.bootstrap.ComboBox} combo This combo box
10611              */
10612         'add' : true,
10613         /**
10614          * @event edit
10615          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10616              * @param {Roo.bootstrap.ComboBox} combo This combo box
10617              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10618              */
10619         'edit' : true,
10620         /**
10621          * @event remove
10622          * Fires when the remove value from the combobox array
10623              * @param {Roo.bootstrap.ComboBox} combo This combo box
10624              */
10625         'remove' : true
10626         
10627     });
10628     
10629     this.item = [];
10630     this.tickItems = [];
10631     
10632     this.selectedIndex = -1;
10633     if(this.mode == 'local'){
10634         if(config.queryDelay === undefined){
10635             this.queryDelay = 10;
10636         }
10637         if(config.minChars === undefined){
10638             this.minChars = 0;
10639         }
10640     }
10641 };
10642
10643 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10644      
10645     /**
10646      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10647      * rendering into an Roo.Editor, defaults to false)
10648      */
10649     /**
10650      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10651      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10652      */
10653     /**
10654      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10655      */
10656     /**
10657      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10658      * the dropdown list (defaults to undefined, with no header element)
10659      */
10660
10661      /**
10662      * @cfg {String/Roo.Template} tpl The template to use to render the output
10663      */
10664      
10665      /**
10666      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10667      */
10668     listWidth: undefined,
10669     /**
10670      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10671      * mode = 'remote' or 'text' if mode = 'local')
10672      */
10673     displayField: undefined,
10674     /**
10675      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10676      * mode = 'remote' or 'value' if mode = 'local'). 
10677      * Note: use of a valueField requires the user make a selection
10678      * in order for a value to be mapped.
10679      */
10680     valueField: undefined,
10681     
10682     
10683     /**
10684      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10685      * field's data value (defaults to the underlying DOM element's name)
10686      */
10687     hiddenName: undefined,
10688     /**
10689      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10690      */
10691     listClass: '',
10692     /**
10693      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10694      */
10695     selectedClass: 'active',
10696     
10697     /**
10698      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10699      */
10700     shadow:'sides',
10701     /**
10702      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10703      * anchor positions (defaults to 'tl-bl')
10704      */
10705     listAlign: 'tl-bl?',
10706     /**
10707      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10708      */
10709     maxHeight: 300,
10710     /**
10711      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10712      * query specified by the allQuery config option (defaults to 'query')
10713      */
10714     triggerAction: 'query',
10715     /**
10716      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10717      * (defaults to 4, does not apply if editable = false)
10718      */
10719     minChars : 4,
10720     /**
10721      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10722      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10723      */
10724     typeAhead: false,
10725     /**
10726      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10727      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10728      */
10729     queryDelay: 500,
10730     /**
10731      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10732      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10733      */
10734     pageSize: 0,
10735     /**
10736      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10737      * when editable = true (defaults to false)
10738      */
10739     selectOnFocus:false,
10740     /**
10741      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10742      */
10743     queryParam: 'query',
10744     /**
10745      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10746      * when mode = 'remote' (defaults to 'Loading...')
10747      */
10748     loadingText: 'Loading...',
10749     /**
10750      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10751      */
10752     resizable: false,
10753     /**
10754      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10755      */
10756     handleHeight : 8,
10757     /**
10758      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10759      * traditional select (defaults to true)
10760      */
10761     editable: true,
10762     /**
10763      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10764      */
10765     allQuery: '',
10766     /**
10767      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10768      */
10769     mode: 'remote',
10770     /**
10771      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10772      * listWidth has a higher value)
10773      */
10774     minListWidth : 70,
10775     /**
10776      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10777      * allow the user to set arbitrary text into the field (defaults to false)
10778      */
10779     forceSelection:false,
10780     /**
10781      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10782      * if typeAhead = true (defaults to 250)
10783      */
10784     typeAheadDelay : 250,
10785     /**
10786      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10787      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10788      */
10789     valueNotFoundText : undefined,
10790     /**
10791      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10792      */
10793     blockFocus : false,
10794     
10795     /**
10796      * @cfg {Boolean} disableClear Disable showing of clear button.
10797      */
10798     disableClear : false,
10799     /**
10800      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10801      */
10802     alwaysQuery : false,
10803     
10804     /**
10805      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10806      */
10807     multiple : false,
10808     
10809     /**
10810      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10811      */
10812     invalidClass : "has-warning",
10813     
10814     /**
10815      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10816      */
10817     validClass : "has-success",
10818     
10819     //private
10820     addicon : false,
10821     editicon: false,
10822     
10823     page: 0,
10824     hasQuery: false,
10825     append: false,
10826     loadNext: false,
10827     autoFocus : true,
10828     tickable : false,
10829     btnPosition : 'right',
10830     triggerList : true,
10831     showToggleBtn : true,
10832     // element that contains real text value.. (when hidden is used..)
10833     
10834     getAutoCreate : function()
10835     {
10836         var cfg = false;
10837         
10838         /*
10839          *  Normal ComboBox
10840          */
10841         if(!this.tickable){
10842             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10843             return cfg;
10844         }
10845         
10846         /*
10847          *  ComboBox with tickable selections
10848          */
10849              
10850         var align = this.labelAlign || this.parentLabelAlign();
10851         
10852         cfg = {
10853             cls : 'form-group roo-combobox-tickable' //input-group
10854         };
10855         
10856         
10857         var buttons = {
10858             tag : 'div',
10859             cls : 'tickable-buttons',
10860             cn : [
10861                 {
10862                     tag : 'button',
10863                     type : 'button',
10864                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10865                     html : 'Edit'
10866                 },
10867                 {
10868                     tag : 'button',
10869                     type : 'button',
10870                     name : 'ok',
10871                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10872                     html : 'Done'
10873                 },
10874                 {
10875                     tag : 'button',
10876                     type : 'button',
10877                     name : 'cancel',
10878                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10879                     html : 'Cancel'
10880                 }
10881             ]
10882         };
10883         
10884         var _this = this;
10885         Roo.each(buttons.cn, function(c){
10886             if (_this.size) {
10887                 c.cls += ' btn-' + _this.size;
10888             }
10889
10890             if (_this.disabled) {
10891                 c.disabled = true;
10892             }
10893         });
10894         
10895         var box = {
10896             tag: 'div',
10897             cn: [
10898                 {
10899                     tag: 'input',
10900                     type : 'hidden',
10901                     cls: 'form-hidden-field'
10902                 },
10903                 {
10904                     tag: 'ul',
10905                     cls: 'select2-choices',
10906                     cn:[
10907                         {
10908                             tag: 'li',
10909                             cls: 'select2-search-field',
10910                             cn: [
10911
10912                                 buttons
10913                             ]
10914                         }
10915                     ]
10916                 }
10917             ]
10918         }
10919         
10920         var combobox = {
10921             cls: 'select2-container input-group select2-container-multi',
10922             cn: [
10923                 box
10924 //                {
10925 //                    tag: 'ul',
10926 //                    cls: 'typeahead typeahead-long dropdown-menu',
10927 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
10928 //                }
10929             ]
10930         };
10931         
10932         if (align ==='left' && this.fieldLabel.length) {
10933             
10934                 Roo.log("left and has label");
10935                 cfg.cn = [
10936                     
10937                     {
10938                         tag: 'label',
10939                         'for' :  id,
10940                         cls : 'control-label col-sm-' + this.labelWidth,
10941                         html : this.fieldLabel
10942                         
10943                     },
10944                     {
10945                         cls : "col-sm-" + (12 - this.labelWidth), 
10946                         cn: [
10947                             combobox
10948                         ]
10949                     }
10950                     
10951                 ];
10952         } else if ( this.fieldLabel.length) {
10953                 Roo.log(" label");
10954                  cfg.cn = [
10955                    
10956                     {
10957                         tag: 'label',
10958                         //cls : 'input-group-addon',
10959                         html : this.fieldLabel
10960                         
10961                     },
10962                     
10963                     combobox
10964                     
10965                 ];
10966
10967         } else {
10968             
10969                 Roo.log(" no label && no align");
10970                 cfg = combobox
10971                      
10972                 
10973         }
10974          
10975         var settings=this;
10976         ['xs','sm','md','lg'].map(function(size){
10977             if (settings[size]) {
10978                 cfg.cls += ' col-' + size + '-' + settings[size];
10979             }
10980         });
10981         
10982         return cfg;
10983         
10984     },
10985     
10986     // private
10987     initEvents: function()
10988     {
10989         
10990         if (!this.store) {
10991             throw "can not find store for combo";
10992         }
10993         this.store = Roo.factory(this.store, Roo.data);
10994         
10995         if(this.tickable){
10996             this.initTickableEvents();
10997             return;
10998         }
10999         
11000         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11001         
11002         if(this.hiddenName){
11003             
11004             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11005             
11006             this.hiddenField.dom.value =
11007                 this.hiddenValue !== undefined ? this.hiddenValue :
11008                 this.value !== undefined ? this.value : '';
11009
11010             // prevent input submission
11011             this.el.dom.removeAttribute('name');
11012             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11013              
11014              
11015         }
11016         //if(Roo.isGecko){
11017         //    this.el.dom.setAttribute('autocomplete', 'off');
11018         //}
11019         
11020         var cls = 'x-combo-list';
11021         
11022         //this.list = new Roo.Layer({
11023         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11024         //});
11025         
11026         var _this = this;
11027         
11028         (function(){
11029             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11030             _this.list.setWidth(lw);
11031         }).defer(100);
11032         
11033         this.list.on('mouseover', this.onViewOver, this);
11034         this.list.on('mousemove', this.onViewMove, this);
11035         
11036         this.list.on('scroll', this.onViewScroll, this);
11037         
11038         /*
11039         this.list.swallowEvent('mousewheel');
11040         this.assetHeight = 0;
11041
11042         if(this.title){
11043             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11044             this.assetHeight += this.header.getHeight();
11045         }
11046
11047         this.innerList = this.list.createChild({cls:cls+'-inner'});
11048         this.innerList.on('mouseover', this.onViewOver, this);
11049         this.innerList.on('mousemove', this.onViewMove, this);
11050         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11051         
11052         if(this.allowBlank && !this.pageSize && !this.disableClear){
11053             this.footer = this.list.createChild({cls:cls+'-ft'});
11054             this.pageTb = new Roo.Toolbar(this.footer);
11055            
11056         }
11057         if(this.pageSize){
11058             this.footer = this.list.createChild({cls:cls+'-ft'});
11059             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11060                     {pageSize: this.pageSize});
11061             
11062         }
11063         
11064         if (this.pageTb && this.allowBlank && !this.disableClear) {
11065             var _this = this;
11066             this.pageTb.add(new Roo.Toolbar.Fill(), {
11067                 cls: 'x-btn-icon x-btn-clear',
11068                 text: '&#160;',
11069                 handler: function()
11070                 {
11071                     _this.collapse();
11072                     _this.clearValue();
11073                     _this.onSelect(false, -1);
11074                 }
11075             });
11076         }
11077         if (this.footer) {
11078             this.assetHeight += this.footer.getHeight();
11079         }
11080         */
11081             
11082         if(!this.tpl){
11083             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11084         }
11085
11086         this.view = new Roo.View(this.list, this.tpl, {
11087             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11088         });
11089         //this.view.wrapEl.setDisplayed(false);
11090         this.view.on('click', this.onViewClick, this);
11091         
11092         
11093         
11094         this.store.on('beforeload', this.onBeforeLoad, this);
11095         this.store.on('load', this.onLoad, this);
11096         this.store.on('loadexception', this.onLoadException, this);
11097         /*
11098         if(this.resizable){
11099             this.resizer = new Roo.Resizable(this.list,  {
11100                pinned:true, handles:'se'
11101             });
11102             this.resizer.on('resize', function(r, w, h){
11103                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11104                 this.listWidth = w;
11105                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11106                 this.restrictHeight();
11107             }, this);
11108             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11109         }
11110         */
11111         if(!this.editable){
11112             this.editable = true;
11113             this.setEditable(false);
11114         }
11115         
11116         /*
11117         
11118         if (typeof(this.events.add.listeners) != 'undefined') {
11119             
11120             this.addicon = this.wrap.createChild(
11121                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11122        
11123             this.addicon.on('click', function(e) {
11124                 this.fireEvent('add', this);
11125             }, this);
11126         }
11127         if (typeof(this.events.edit.listeners) != 'undefined') {
11128             
11129             this.editicon = this.wrap.createChild(
11130                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11131             if (this.addicon) {
11132                 this.editicon.setStyle('margin-left', '40px');
11133             }
11134             this.editicon.on('click', function(e) {
11135                 
11136                 // we fire even  if inothing is selected..
11137                 this.fireEvent('edit', this, this.lastData );
11138                 
11139             }, this);
11140         }
11141         */
11142         
11143         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11144             "up" : function(e){
11145                 this.inKeyMode = true;
11146                 this.selectPrev();
11147             },
11148
11149             "down" : function(e){
11150                 if(!this.isExpanded()){
11151                     this.onTriggerClick();
11152                 }else{
11153                     this.inKeyMode = true;
11154                     this.selectNext();
11155                 }
11156             },
11157
11158             "enter" : function(e){
11159 //                this.onViewClick();
11160                 //return true;
11161                 this.collapse();
11162                 
11163                 if(this.fireEvent("specialkey", this, e)){
11164                     this.onViewClick(false);
11165                 }
11166                 
11167                 return true;
11168             },
11169
11170             "esc" : function(e){
11171                 this.collapse();
11172             },
11173
11174             "tab" : function(e){
11175                 this.collapse();
11176                 
11177                 if(this.fireEvent("specialkey", this, e)){
11178                     this.onViewClick(false);
11179                 }
11180                 
11181                 return true;
11182             },
11183
11184             scope : this,
11185
11186             doRelay : function(foo, bar, hname){
11187                 if(hname == 'down' || this.scope.isExpanded()){
11188                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11189                 }
11190                 return true;
11191             },
11192
11193             forceKeyDown: true
11194         });
11195         
11196         
11197         this.queryDelay = Math.max(this.queryDelay || 10,
11198                 this.mode == 'local' ? 10 : 250);
11199         
11200         
11201         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11202         
11203         if(this.typeAhead){
11204             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11205         }
11206         if(this.editable !== false){
11207             this.inputEl().on("keyup", this.onKeyUp, this);
11208         }
11209         if(this.forceSelection){
11210             this.inputEl().on('blur', this.doForce, this);
11211         }
11212         
11213         if(this.multiple){
11214             this.choices = this.el.select('ul.select2-choices', true).first();
11215             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11216         }
11217     },
11218     
11219     initTickableEvents: function()
11220     {   
11221         this.createList();
11222         
11223         if(this.hiddenName){
11224             
11225             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11226             
11227             this.hiddenField.dom.value =
11228                 this.hiddenValue !== undefined ? this.hiddenValue :
11229                 this.value !== undefined ? this.value : '';
11230
11231             // prevent input submission
11232             this.el.dom.removeAttribute('name');
11233             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11234              
11235              
11236         }
11237         
11238 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11239         
11240         this.choices = this.el.select('ul.select2-choices', true).first();
11241         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11242         if(this.triggerList){
11243             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11244         }
11245          
11246         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11247         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11248         
11249         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11250         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11251         
11252         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11253         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11254         
11255         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11256         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11257         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11258         
11259         this.okBtn.hide();
11260         this.cancelBtn.hide();
11261         
11262         var _this = this;
11263         
11264         (function(){
11265             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11266             _this.list.setWidth(lw);
11267         }).defer(100);
11268         
11269         this.list.on('mouseover', this.onViewOver, this);
11270         this.list.on('mousemove', this.onViewMove, this);
11271         
11272         this.list.on('scroll', this.onViewScroll, this);
11273         
11274         if(!this.tpl){
11275             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>';
11276         }
11277
11278         this.view = new Roo.View(this.list, this.tpl, {
11279             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11280         });
11281         
11282         //this.view.wrapEl.setDisplayed(false);
11283         this.view.on('click', this.onViewClick, this);
11284         
11285         
11286         
11287         this.store.on('beforeload', this.onBeforeLoad, this);
11288         this.store.on('load', this.onLoad, this);
11289         this.store.on('loadexception', this.onLoadException, this);
11290         
11291 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11292 //            "up" : function(e){
11293 //                this.inKeyMode = true;
11294 //                this.selectPrev();
11295 //            },
11296 //
11297 //            "down" : function(e){
11298 //                if(!this.isExpanded()){
11299 //                    this.onTriggerClick();
11300 //                }else{
11301 //                    this.inKeyMode = true;
11302 //                    this.selectNext();
11303 //                }
11304 //            },
11305 //
11306 //            "enter" : function(e){
11307 ////                this.onViewClick();
11308 //                //return true;
11309 //                this.collapse();
11310 //                
11311 //                if(this.fireEvent("specialkey", this, e)){
11312 //                    this.onViewClick(false);
11313 //                }
11314 //                
11315 //                return true;
11316 //            },
11317 //
11318 //            "esc" : function(e){
11319 //                this.collapse();
11320 //            },
11321 //
11322 //            "tab" : function(e){
11323 //                this.collapse();
11324 //                
11325 //                if(this.fireEvent("specialkey", this, e)){
11326 //                    this.onViewClick(false);
11327 //                }
11328 //                
11329 //                return true;
11330 //            },
11331 //
11332 //            scope : this,
11333 //
11334 //            doRelay : function(foo, bar, hname){
11335 //                if(hname == 'down' || this.scope.isExpanded()){
11336 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11337 //                }
11338 //                return true;
11339 //            },
11340 //
11341 //            forceKeyDown: true
11342 //        });
11343         
11344         
11345         this.queryDelay = Math.max(this.queryDelay || 10,
11346                 this.mode == 'local' ? 10 : 250);
11347         
11348         
11349         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11350         
11351         if(this.typeAhead){
11352             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11353         }
11354         
11355     },
11356
11357     onDestroy : function(){
11358         if(this.view){
11359             this.view.setStore(null);
11360             this.view.el.removeAllListeners();
11361             this.view.el.remove();
11362             this.view.purgeListeners();
11363         }
11364         if(this.list){
11365             this.list.dom.innerHTML  = '';
11366         }
11367         
11368         if(this.store){
11369             this.store.un('beforeload', this.onBeforeLoad, this);
11370             this.store.un('load', this.onLoad, this);
11371             this.store.un('loadexception', this.onLoadException, this);
11372         }
11373         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11374     },
11375
11376     // private
11377     fireKey : function(e){
11378         if(e.isNavKeyPress() && !this.list.isVisible()){
11379             this.fireEvent("specialkey", this, e);
11380         }
11381     },
11382
11383     // private
11384     onResize: function(w, h){
11385 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11386 //        
11387 //        if(typeof w != 'number'){
11388 //            // we do not handle it!?!?
11389 //            return;
11390 //        }
11391 //        var tw = this.trigger.getWidth();
11392 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11393 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11394 //        var x = w - tw;
11395 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11396 //            
11397 //        //this.trigger.setStyle('left', x+'px');
11398 //        
11399 //        if(this.list && this.listWidth === undefined){
11400 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11401 //            this.list.setWidth(lw);
11402 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11403 //        }
11404         
11405     
11406         
11407     },
11408
11409     /**
11410      * Allow or prevent the user from directly editing the field text.  If false is passed,
11411      * the user will only be able to select from the items defined in the dropdown list.  This method
11412      * is the runtime equivalent of setting the 'editable' config option at config time.
11413      * @param {Boolean} value True to allow the user to directly edit the field text
11414      */
11415     setEditable : function(value){
11416         if(value == this.editable){
11417             return;
11418         }
11419         this.editable = value;
11420         if(!value){
11421             this.inputEl().dom.setAttribute('readOnly', true);
11422             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11423             this.inputEl().addClass('x-combo-noedit');
11424         }else{
11425             this.inputEl().dom.setAttribute('readOnly', false);
11426             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11427             this.inputEl().removeClass('x-combo-noedit');
11428         }
11429     },
11430
11431     // private
11432     
11433     onBeforeLoad : function(combo,opts){
11434         if(!this.hasFocus){
11435             return;
11436         }
11437          if (!opts.add) {
11438             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11439          }
11440         this.restrictHeight();
11441         this.selectedIndex = -1;
11442     },
11443
11444     // private
11445     onLoad : function(){
11446         
11447         this.hasQuery = false;
11448         
11449         if(!this.hasFocus){
11450             return;
11451         }
11452         
11453         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11454             this.loading.hide();
11455         }
11456         
11457         if(this.store.getCount() > 0){
11458             this.expand();
11459 //            this.restrictHeight();
11460             if(this.lastQuery == this.allQuery){
11461                 if(this.editable && !this.tickable){
11462                     this.inputEl().dom.select();
11463                 }
11464                 
11465                 if(
11466                     !this.selectByValue(this.value, true) &&
11467                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11468                     this.store.lastOptions.add != true)
11469                 ){
11470                     this.select(0, true);
11471                 }
11472             }else{
11473                 if(this.autoFocus){
11474                     this.selectNext();
11475                 }
11476                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11477                     this.taTask.delay(this.typeAheadDelay);
11478                 }
11479             }
11480         }else{
11481             this.onEmptyResults();
11482         }
11483         
11484         //this.el.focus();
11485     },
11486     // private
11487     onLoadException : function()
11488     {
11489         this.hasQuery = false;
11490         
11491         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11492             this.loading.hide();
11493         }
11494         
11495         this.collapse();
11496         Roo.log(this.store.reader.jsonData);
11497         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11498             // fixme
11499             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11500         }
11501         
11502         
11503     },
11504     // private
11505     onTypeAhead : function(){
11506         if(this.store.getCount() > 0){
11507             var r = this.store.getAt(0);
11508             var newValue = r.data[this.displayField];
11509             var len = newValue.length;
11510             var selStart = this.getRawValue().length;
11511             
11512             if(selStart != len){
11513                 this.setRawValue(newValue);
11514                 this.selectText(selStart, newValue.length);
11515             }
11516         }
11517     },
11518
11519     // private
11520     onSelect : function(record, index){
11521         
11522         if(this.fireEvent('beforeselect', this, record, index) !== false){
11523         
11524             this.setFromData(index > -1 ? record.data : false);
11525             
11526             this.collapse();
11527             this.fireEvent('select', this, record, index);
11528         }
11529     },
11530
11531     /**
11532      * Returns the currently selected field value or empty string if no value is set.
11533      * @return {String} value The selected value
11534      */
11535     getValue : function(){
11536         
11537         if(this.multiple){
11538             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11539         }
11540         
11541         if(this.valueField){
11542             return typeof this.value != 'undefined' ? this.value : '';
11543         }else{
11544             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11545         }
11546     },
11547
11548     /**
11549      * Clears any text/value currently set in the field
11550      */
11551     clearValue : function(){
11552         if(this.hiddenField){
11553             this.hiddenField.dom.value = '';
11554         }
11555         this.value = '';
11556         this.setRawValue('');
11557         this.lastSelectionText = '';
11558         this.lastData = false;
11559         
11560     },
11561
11562     /**
11563      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11564      * will be displayed in the field.  If the value does not match the data value of an existing item,
11565      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11566      * Otherwise the field will be blank (although the value will still be set).
11567      * @param {String} value The value to match
11568      */
11569     setValue : function(v){
11570         if(this.multiple){
11571             this.syncValue();
11572             return;
11573         }
11574         
11575         var text = v;
11576         if(this.valueField){
11577             var r = this.findRecord(this.valueField, v);
11578             if(r){
11579                 text = r.data[this.displayField];
11580             }else if(this.valueNotFoundText !== undefined){
11581                 text = this.valueNotFoundText;
11582             }
11583         }
11584         this.lastSelectionText = text;
11585         if(this.hiddenField){
11586             this.hiddenField.dom.value = v;
11587         }
11588         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11589         this.value = v;
11590     },
11591     /**
11592      * @property {Object} the last set data for the element
11593      */
11594     
11595     lastData : false,
11596     /**
11597      * Sets the value of the field based on a object which is related to the record format for the store.
11598      * @param {Object} value the value to set as. or false on reset?
11599      */
11600     setFromData : function(o){
11601         
11602         if(this.multiple){
11603             this.addItem(o);
11604             return;
11605         }
11606             
11607         var dv = ''; // display value
11608         var vv = ''; // value value..
11609         this.lastData = o;
11610         if (this.displayField) {
11611             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11612         } else {
11613             // this is an error condition!!!
11614             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11615         }
11616         
11617         if(this.valueField){
11618             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11619         }
11620         
11621         if(this.hiddenField){
11622             this.hiddenField.dom.value = vv;
11623             
11624             this.lastSelectionText = dv;
11625             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11626             this.value = vv;
11627             return;
11628         }
11629         // no hidden field.. - we store the value in 'value', but still display
11630         // display field!!!!
11631         this.lastSelectionText = dv;
11632         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11633         this.value = vv;
11634         
11635         
11636     },
11637     // private
11638     reset : function(){
11639         // overridden so that last data is reset..
11640         this.setValue(this.originalValue);
11641         this.clearInvalid();
11642         this.lastData = false;
11643         if (this.view) {
11644             this.view.clearSelections();
11645         }
11646     },
11647     // private
11648     findRecord : function(prop, value){
11649         var record;
11650         if(this.store.getCount() > 0){
11651             this.store.each(function(r){
11652                 if(r.data[prop] == value){
11653                     record = r;
11654                     return false;
11655                 }
11656                 return true;
11657             });
11658         }
11659         return record;
11660     },
11661     
11662     getName: function()
11663     {
11664         // returns hidden if it's set..
11665         if (!this.rendered) {return ''};
11666         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11667         
11668     },
11669     // private
11670     onViewMove : function(e, t){
11671         this.inKeyMode = false;
11672     },
11673
11674     // private
11675     onViewOver : function(e, t){
11676         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11677             return;
11678         }
11679         var item = this.view.findItemFromChild(t);
11680         
11681         if(item){
11682             var index = this.view.indexOf(item);
11683             this.select(index, false);
11684         }
11685     },
11686
11687     // private
11688     onViewClick : function(view, doFocus, el, e)
11689     {
11690         var index = this.view.getSelectedIndexes()[0];
11691         
11692         var r = this.store.getAt(index);
11693         
11694         if(this.tickable){
11695             
11696             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11697                 return;
11698             }
11699             
11700             var rm = false;
11701             var _this = this;
11702             
11703             Roo.each(this.tickItems, function(v,k){
11704                 
11705                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11706                     _this.tickItems.splice(k, 1);
11707                     rm = true;
11708                     return;
11709                 }
11710             });
11711             
11712             if(rm){
11713                 return;
11714             }
11715             
11716             this.tickItems.push(r.data);
11717             return;
11718         }
11719         
11720         if(r){
11721             this.onSelect(r, index);
11722         }
11723         if(doFocus !== false && !this.blockFocus){
11724             this.inputEl().focus();
11725         }
11726     },
11727
11728     // private
11729     restrictHeight : function(){
11730         //this.innerList.dom.style.height = '';
11731         //var inner = this.innerList.dom;
11732         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11733         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11734         //this.list.beginUpdate();
11735         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11736         this.list.alignTo(this.inputEl(), this.listAlign);
11737         this.list.alignTo(this.inputEl(), this.listAlign);
11738         //this.list.endUpdate();
11739     },
11740
11741     // private
11742     onEmptyResults : function(){
11743         this.collapse();
11744     },
11745
11746     /**
11747      * Returns true if the dropdown list is expanded, else false.
11748      */
11749     isExpanded : function(){
11750         return this.list.isVisible();
11751     },
11752
11753     /**
11754      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11755      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11756      * @param {String} value The data value of the item to select
11757      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11758      * selected item if it is not currently in view (defaults to true)
11759      * @return {Boolean} True if the value matched an item in the list, else false
11760      */
11761     selectByValue : function(v, scrollIntoView){
11762         if(v !== undefined && v !== null){
11763             var r = this.findRecord(this.valueField || this.displayField, v);
11764             if(r){
11765                 this.select(this.store.indexOf(r), scrollIntoView);
11766                 return true;
11767             }
11768         }
11769         return false;
11770     },
11771
11772     /**
11773      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11774      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11775      * @param {Number} index The zero-based index of the list item to select
11776      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11777      * selected item if it is not currently in view (defaults to true)
11778      */
11779     select : function(index, scrollIntoView){
11780         this.selectedIndex = index;
11781         this.view.select(index);
11782         if(scrollIntoView !== false){
11783             var el = this.view.getNode(index);
11784             if(el && !this.multiple && !this.tickable){
11785                 this.list.scrollChildIntoView(el, false);
11786             }
11787         }
11788     },
11789
11790     // private
11791     selectNext : function(){
11792         var ct = this.store.getCount();
11793         if(ct > 0){
11794             if(this.selectedIndex == -1){
11795                 this.select(0);
11796             }else if(this.selectedIndex < ct-1){
11797                 this.select(this.selectedIndex+1);
11798             }
11799         }
11800     },
11801
11802     // private
11803     selectPrev : function(){
11804         var ct = this.store.getCount();
11805         if(ct > 0){
11806             if(this.selectedIndex == -1){
11807                 this.select(0);
11808             }else if(this.selectedIndex != 0){
11809                 this.select(this.selectedIndex-1);
11810             }
11811         }
11812     },
11813
11814     // private
11815     onKeyUp : function(e){
11816         if(this.editable !== false && !e.isSpecialKey()){
11817             this.lastKey = e.getKey();
11818             this.dqTask.delay(this.queryDelay);
11819         }
11820     },
11821
11822     // private
11823     validateBlur : function(){
11824         return !this.list || !this.list.isVisible();   
11825     },
11826
11827     // private
11828     initQuery : function(){
11829         this.doQuery(this.getRawValue());
11830     },
11831
11832     // private
11833     doForce : function(){
11834         if(this.inputEl().dom.value.length > 0){
11835             this.inputEl().dom.value =
11836                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11837              
11838         }
11839     },
11840
11841     /**
11842      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11843      * query allowing the query action to be canceled if needed.
11844      * @param {String} query The SQL query to execute
11845      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11846      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11847      * saved in the current store (defaults to false)
11848      */
11849     doQuery : function(q, forceAll){
11850         
11851         if(q === undefined || q === null){
11852             q = '';
11853         }
11854         var qe = {
11855             query: q,
11856             forceAll: forceAll,
11857             combo: this,
11858             cancel:false
11859         };
11860         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11861             return false;
11862         }
11863         q = qe.query;
11864         
11865         forceAll = qe.forceAll;
11866         if(forceAll === true || (q.length >= this.minChars)){
11867             
11868             this.hasQuery = true;
11869             
11870             if(this.lastQuery != q || this.alwaysQuery){
11871                 this.lastQuery = q;
11872                 if(this.mode == 'local'){
11873                     this.selectedIndex = -1;
11874                     if(forceAll){
11875                         this.store.clearFilter();
11876                     }else{
11877                         this.store.filter(this.displayField, q);
11878                     }
11879                     this.onLoad();
11880                 }else{
11881                     this.store.baseParams[this.queryParam] = q;
11882                     
11883                     var options = {params : this.getParams(q)};
11884                     
11885                     if(this.loadNext){
11886                         options.add = true;
11887                         options.params.start = this.page * this.pageSize;
11888                     }
11889                     
11890                     this.store.load(options);
11891                     /*
11892                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11893                      *  we should expand the list on onLoad
11894                      *  so command out it
11895                      */
11896 //                    this.expand();
11897                 }
11898             }else{
11899                 this.selectedIndex = -1;
11900                 this.onLoad();   
11901             }
11902         }
11903         
11904         this.loadNext = false;
11905     },
11906
11907     // private
11908     getParams : function(q){
11909         var p = {};
11910         //p[this.queryParam] = q;
11911         
11912         if(this.pageSize){
11913             p.start = 0;
11914             p.limit = this.pageSize;
11915         }
11916         return p;
11917     },
11918
11919     /**
11920      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11921      */
11922     collapse : function(){
11923         if(!this.isExpanded()){
11924             return;
11925         }
11926         
11927         this.list.hide();
11928         
11929         if(this.tickable){
11930             this.hasFocus = false;
11931             this.okBtn.hide();
11932             this.cancelBtn.hide();
11933             this.trigger.show();
11934         }
11935         
11936         Roo.get(document).un('mousedown', this.collapseIf, this);
11937         Roo.get(document).un('mousewheel', this.collapseIf, this);
11938         if (!this.editable) {
11939             Roo.get(document).un('keydown', this.listKeyPress, this);
11940         }
11941         this.fireEvent('collapse', this);
11942     },
11943
11944     // private
11945     collapseIf : function(e){
11946         var in_combo  = e.within(this.el);
11947         var in_list =  e.within(this.list);
11948         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11949         
11950         if (in_combo || in_list || is_list) {
11951             //e.stopPropagation();
11952             return;
11953         }
11954         
11955         if(this.tickable){
11956             this.onTickableFooterButtonClick(e, false, false);
11957         }
11958
11959         this.collapse();
11960         
11961     },
11962
11963     /**
11964      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11965      */
11966     expand : function(){
11967        
11968         if(this.isExpanded() || !this.hasFocus){
11969             return;
11970         }
11971         
11972         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11973         this.list.setWidth(lw);
11974         
11975         
11976          Roo.log('expand');
11977         
11978         this.list.show();
11979         
11980         this.restrictHeight();
11981         
11982         if(this.tickable){
11983             
11984             this.tickItems = Roo.apply([], this.item);
11985             
11986             this.okBtn.show();
11987             this.cancelBtn.show();
11988             this.trigger.hide();
11989             
11990         }
11991         
11992         Roo.get(document).on('mousedown', this.collapseIf, this);
11993         Roo.get(document).on('mousewheel', this.collapseIf, this);
11994         if (!this.editable) {
11995             Roo.get(document).on('keydown', this.listKeyPress, this);
11996         }
11997         
11998         this.fireEvent('expand', this);
11999     },
12000
12001     // private
12002     // Implements the default empty TriggerField.onTriggerClick function
12003     onTriggerClick : function(e)
12004     {
12005         Roo.log('trigger click');
12006         
12007         if(this.disabled || !this.triggerList){
12008             return;
12009         }
12010         
12011         this.page = 0;
12012         this.loadNext = false;
12013         
12014         if(this.isExpanded()){
12015             this.collapse();
12016             if (!this.blockFocus) {
12017                 this.inputEl().focus();
12018             }
12019             
12020         }else {
12021             this.hasFocus = true;
12022             if(this.triggerAction == 'all') {
12023                 this.doQuery(this.allQuery, true);
12024             } else {
12025                 this.doQuery(this.getRawValue());
12026             }
12027             if (!this.blockFocus) {
12028                 this.inputEl().focus();
12029             }
12030         }
12031     },
12032     
12033     onTickableTriggerClick : function(e)
12034     {
12035         if(this.disabled){
12036             return;
12037         }
12038         
12039         this.page = 0;
12040         this.loadNext = false;
12041         this.hasFocus = true;
12042         
12043         if(this.triggerAction == 'all') {
12044             this.doQuery(this.allQuery, true);
12045         } else {
12046             this.doQuery(this.getRawValue());
12047         }
12048     },
12049     
12050     onSearchFieldClick : function(e)
12051     {
12052         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12053             this.onTickableFooterButtonClick(e, false, false);
12054             return;
12055         }
12056         
12057         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12058             return;
12059         }
12060         
12061         this.page = 0;
12062         this.loadNext = false;
12063         this.hasFocus = true;
12064         
12065         if(this.triggerAction == 'all') {
12066             this.doQuery(this.allQuery, true);
12067         } else {
12068             this.doQuery(this.getRawValue());
12069         }
12070     },
12071     
12072     listKeyPress : function(e)
12073     {
12074         //Roo.log('listkeypress');
12075         // scroll to first matching element based on key pres..
12076         if (e.isSpecialKey()) {
12077             return false;
12078         }
12079         var k = String.fromCharCode(e.getKey()).toUpperCase();
12080         //Roo.log(k);
12081         var match  = false;
12082         var csel = this.view.getSelectedNodes();
12083         var cselitem = false;
12084         if (csel.length) {
12085             var ix = this.view.indexOf(csel[0]);
12086             cselitem  = this.store.getAt(ix);
12087             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12088                 cselitem = false;
12089             }
12090             
12091         }
12092         
12093         this.store.each(function(v) { 
12094             if (cselitem) {
12095                 // start at existing selection.
12096                 if (cselitem.id == v.id) {
12097                     cselitem = false;
12098                 }
12099                 return true;
12100             }
12101                 
12102             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12103                 match = this.store.indexOf(v);
12104                 return false;
12105             }
12106             return true;
12107         }, this);
12108         
12109         if (match === false) {
12110             return true; // no more action?
12111         }
12112         // scroll to?
12113         this.view.select(match);
12114         var sn = Roo.get(this.view.getSelectedNodes()[0])
12115         sn.scrollIntoView(sn.dom.parentNode, false);
12116     },
12117     
12118     onViewScroll : function(e, t){
12119         
12120         if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12121             return;
12122         }
12123         
12124         this.hasQuery = true;
12125         
12126         this.loading = this.list.select('.loading', true).first();
12127         
12128         if(this.loading === null){
12129             this.list.createChild({
12130                 tag: 'div',
12131                 cls: 'loading select2-more-results select2-active',
12132                 html: 'Loading more results...'
12133             })
12134             
12135             this.loading = this.list.select('.loading', true).first();
12136             
12137             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12138             
12139             this.loading.hide();
12140         }
12141         
12142         this.loading.show();
12143         
12144         var _combo = this;
12145         
12146         this.page++;
12147         this.loadNext = true;
12148         
12149         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12150         
12151         return;
12152     },
12153     
12154     addItem : function(o)
12155     {   
12156         var dv = ''; // display value
12157         
12158         if (this.displayField) {
12159             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12160         } else {
12161             // this is an error condition!!!
12162             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12163         }
12164         
12165         if(!dv.length){
12166             return;
12167         }
12168         
12169         var choice = this.choices.createChild({
12170             tag: 'li',
12171             cls: 'select2-search-choice',
12172             cn: [
12173                 {
12174                     tag: 'div',
12175                     html: dv
12176                 },
12177                 {
12178                     tag: 'a',
12179                     href: '#',
12180                     cls: 'select2-search-choice-close',
12181                     tabindex: '-1'
12182                 }
12183             ]
12184             
12185         }, this.searchField);
12186         
12187         var close = choice.select('a.select2-search-choice-close', true).first()
12188         
12189         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12190         
12191         this.item.push(o);
12192         
12193         this.lastData = o;
12194         
12195         this.syncValue();
12196         
12197         this.inputEl().dom.value = '';
12198         
12199         this.validate();
12200     },
12201     
12202     onRemoveItem : function(e, _self, o)
12203     {
12204         e.preventDefault();
12205         
12206         this.lastItem = Roo.apply([], this.item);
12207         
12208         var index = this.item.indexOf(o.data) * 1;
12209         
12210         if( index < 0){
12211             Roo.log('not this item?!');
12212             return;
12213         }
12214         
12215         this.item.splice(index, 1);
12216         o.item.remove();
12217         
12218         this.syncValue();
12219         
12220         this.fireEvent('remove', this, e);
12221         
12222         this.validate();
12223         
12224     },
12225     
12226     syncValue : function()
12227     {
12228         if(!this.item.length){
12229             this.clearValue();
12230             return;
12231         }
12232             
12233         var value = [];
12234         var _this = this;
12235         Roo.each(this.item, function(i){
12236             if(_this.valueField){
12237                 value.push(i[_this.valueField]);
12238                 return;
12239             }
12240
12241             value.push(i);
12242         });
12243
12244         this.value = value.join(',');
12245
12246         if(this.hiddenField){
12247             this.hiddenField.dom.value = this.value;
12248         }
12249     },
12250     
12251     clearItem : function()
12252     {
12253         if(!this.multiple){
12254             return;
12255         }
12256         
12257         this.item = [];
12258         
12259         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12260            c.remove();
12261         });
12262         
12263         this.syncValue();
12264         
12265         this.validate();
12266     },
12267     
12268     inputEl: function ()
12269     {
12270         if(this.tickable){
12271             return this.searchField;
12272         }
12273         return this.el.select('input.form-control',true).first();
12274     },
12275     
12276     
12277     onTickableFooterButtonClick : function(e, btn, el)
12278     {
12279         e.preventDefault();
12280         
12281         this.lastItem = Roo.apply([], this.item);
12282         
12283         if(btn && btn.name == 'cancel'){
12284             this.tickItems = Roo.apply([], this.item);
12285             this.collapse();
12286             return;
12287         }
12288         
12289         this.clearItem();
12290         
12291         var _this = this;
12292         
12293         Roo.each(this.tickItems, function(o){
12294             _this.addItem(o);
12295         });
12296         
12297         this.collapse();
12298         
12299     },
12300     
12301     validate : function()
12302     {
12303         var v = this.getRawValue();
12304         
12305         if(this.multiple){
12306             v = this.getValue();
12307         }
12308         
12309         if(this.disabled || this.allowBlank || v.length){
12310             this.markValid();
12311             return true;
12312         }
12313         
12314         this.markInvalid();
12315         return false;
12316     }
12317     
12318     
12319
12320     /** 
12321     * @cfg {Boolean} grow 
12322     * @hide 
12323     */
12324     /** 
12325     * @cfg {Number} growMin 
12326     * @hide 
12327     */
12328     /** 
12329     * @cfg {Number} growMax 
12330     * @hide 
12331     */
12332     /**
12333      * @hide
12334      * @method autoSize
12335      */
12336 });
12337 /*
12338  * Based on:
12339  * Ext JS Library 1.1.1
12340  * Copyright(c) 2006-2007, Ext JS, LLC.
12341  *
12342  * Originally Released Under LGPL - original licence link has changed is not relivant.
12343  *
12344  * Fork - LGPL
12345  * <script type="text/javascript">
12346  */
12347
12348 /**
12349  * @class Roo.View
12350  * @extends Roo.util.Observable
12351  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12352  * This class also supports single and multi selection modes. <br>
12353  * Create a data model bound view:
12354  <pre><code>
12355  var store = new Roo.data.Store(...);
12356
12357  var view = new Roo.View({
12358     el : "my-element",
12359     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12360  
12361     singleSelect: true,
12362     selectedClass: "ydataview-selected",
12363     store: store
12364  });
12365
12366  // listen for node click?
12367  view.on("click", function(vw, index, node, e){
12368  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12369  });
12370
12371  // load XML data
12372  dataModel.load("foobar.xml");
12373  </code></pre>
12374  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12375  * <br><br>
12376  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12377  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12378  * 
12379  * Note: old style constructor is still suported (container, template, config)
12380  * 
12381  * @constructor
12382  * Create a new View
12383  * @param {Object} config The config object
12384  * 
12385  */
12386 Roo.View = function(config, depreciated_tpl, depreciated_config){
12387     
12388     this.parent = false;
12389     
12390     if (typeof(depreciated_tpl) == 'undefined') {
12391         // new way.. - universal constructor.
12392         Roo.apply(this, config);
12393         this.el  = Roo.get(this.el);
12394     } else {
12395         // old format..
12396         this.el  = Roo.get(config);
12397         this.tpl = depreciated_tpl;
12398         Roo.apply(this, depreciated_config);
12399     }
12400     this.wrapEl  = this.el.wrap().wrap();
12401     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12402     
12403     
12404     if(typeof(this.tpl) == "string"){
12405         this.tpl = new Roo.Template(this.tpl);
12406     } else {
12407         // support xtype ctors..
12408         this.tpl = new Roo.factory(this.tpl, Roo);
12409     }
12410     
12411     
12412     this.tpl.compile();
12413     
12414     /** @private */
12415     this.addEvents({
12416         /**
12417          * @event beforeclick
12418          * Fires before a click is processed. Returns false to cancel the default action.
12419          * @param {Roo.View} this
12420          * @param {Number} index The index of the target node
12421          * @param {HTMLElement} node The target node
12422          * @param {Roo.EventObject} e The raw event object
12423          */
12424             "beforeclick" : true,
12425         /**
12426          * @event click
12427          * Fires when a template node is clicked.
12428          * @param {Roo.View} this
12429          * @param {Number} index The index of the target node
12430          * @param {HTMLElement} node The target node
12431          * @param {Roo.EventObject} e The raw event object
12432          */
12433             "click" : true,
12434         /**
12435          * @event dblclick
12436          * Fires when a template node is double clicked.
12437          * @param {Roo.View} this
12438          * @param {Number} index The index of the target node
12439          * @param {HTMLElement} node The target node
12440          * @param {Roo.EventObject} e The raw event object
12441          */
12442             "dblclick" : true,
12443         /**
12444          * @event contextmenu
12445          * Fires when a template node is right clicked.
12446          * @param {Roo.View} this
12447          * @param {Number} index The index of the target node
12448          * @param {HTMLElement} node The target node
12449          * @param {Roo.EventObject} e The raw event object
12450          */
12451             "contextmenu" : true,
12452         /**
12453          * @event selectionchange
12454          * Fires when the selected nodes change.
12455          * @param {Roo.View} this
12456          * @param {Array} selections Array of the selected nodes
12457          */
12458             "selectionchange" : true,
12459     
12460         /**
12461          * @event beforeselect
12462          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12463          * @param {Roo.View} this
12464          * @param {HTMLElement} node The node to be selected
12465          * @param {Array} selections Array of currently selected nodes
12466          */
12467             "beforeselect" : true,
12468         /**
12469          * @event preparedata
12470          * Fires on every row to render, to allow you to change the data.
12471          * @param {Roo.View} this
12472          * @param {Object} data to be rendered (change this)
12473          */
12474           "preparedata" : true
12475           
12476           
12477         });
12478
12479
12480
12481     this.el.on({
12482         "click": this.onClick,
12483         "dblclick": this.onDblClick,
12484         "contextmenu": this.onContextMenu,
12485         scope:this
12486     });
12487
12488     this.selections = [];
12489     this.nodes = [];
12490     this.cmp = new Roo.CompositeElementLite([]);
12491     if(this.store){
12492         this.store = Roo.factory(this.store, Roo.data);
12493         this.setStore(this.store, true);
12494     }
12495     
12496     if ( this.footer && this.footer.xtype) {
12497            
12498          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12499         
12500         this.footer.dataSource = this.store
12501         this.footer.container = fctr;
12502         this.footer = Roo.factory(this.footer, Roo);
12503         fctr.insertFirst(this.el);
12504         
12505         // this is a bit insane - as the paging toolbar seems to detach the el..
12506 //        dom.parentNode.parentNode.parentNode
12507          // they get detached?
12508     }
12509     
12510     
12511     Roo.View.superclass.constructor.call(this);
12512     
12513     
12514 };
12515
12516 Roo.extend(Roo.View, Roo.util.Observable, {
12517     
12518      /**
12519      * @cfg {Roo.data.Store} store Data store to load data from.
12520      */
12521     store : false,
12522     
12523     /**
12524      * @cfg {String|Roo.Element} el The container element.
12525      */
12526     el : '',
12527     
12528     /**
12529      * @cfg {String|Roo.Template} tpl The template used by this View 
12530      */
12531     tpl : false,
12532     /**
12533      * @cfg {String} dataName the named area of the template to use as the data area
12534      *                          Works with domtemplates roo-name="name"
12535      */
12536     dataName: false,
12537     /**
12538      * @cfg {String} selectedClass The css class to add to selected nodes
12539      */
12540     selectedClass : "x-view-selected",
12541      /**
12542      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12543      */
12544     emptyText : "",
12545     
12546     /**
12547      * @cfg {String} text to display on mask (default Loading)
12548      */
12549     mask : false,
12550     /**
12551      * @cfg {Boolean} multiSelect Allow multiple selection
12552      */
12553     multiSelect : false,
12554     /**
12555      * @cfg {Boolean} singleSelect Allow single selection
12556      */
12557     singleSelect:  false,
12558     
12559     /**
12560      * @cfg {Boolean} toggleSelect - selecting 
12561      */
12562     toggleSelect : false,
12563     
12564     /**
12565      * @cfg {Boolean} tickable - selecting 
12566      */
12567     tickable : false,
12568     
12569     /**
12570      * Returns the element this view is bound to.
12571      * @return {Roo.Element}
12572      */
12573     getEl : function(){
12574         return this.wrapEl;
12575     },
12576     
12577     
12578
12579     /**
12580      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12581      */
12582     refresh : function(){
12583         //Roo.log('refresh');
12584         var t = this.tpl;
12585         
12586         // if we are using something like 'domtemplate', then
12587         // the what gets used is:
12588         // t.applySubtemplate(NAME, data, wrapping data..)
12589         // the outer template then get' applied with
12590         //     the store 'extra data'
12591         // and the body get's added to the
12592         //      roo-name="data" node?
12593         //      <span class='roo-tpl-{name}'></span> ?????
12594         
12595         
12596         
12597         this.clearSelections();
12598         this.el.update("");
12599         var html = [];
12600         var records = this.store.getRange();
12601         if(records.length < 1) {
12602             
12603             // is this valid??  = should it render a template??
12604             
12605             this.el.update(this.emptyText);
12606             return;
12607         }
12608         var el = this.el;
12609         if (this.dataName) {
12610             this.el.update(t.apply(this.store.meta)); //????
12611             el = this.el.child('.roo-tpl-' + this.dataName);
12612         }
12613         
12614         for(var i = 0, len = records.length; i < len; i++){
12615             var data = this.prepareData(records[i].data, i, records[i]);
12616             this.fireEvent("preparedata", this, data, i, records[i]);
12617             
12618             var d = Roo.apply({}, data);
12619             
12620             if(this.tickable){
12621                 Roo.apply(d, {'roo-id' : Roo.id()});
12622                 
12623                 var _this = this;
12624             
12625                 Roo.each(this.parent.item, function(item){
12626                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12627                         return;
12628                     }
12629                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12630                 });
12631             }
12632             
12633             html[html.length] = Roo.util.Format.trim(
12634                 this.dataName ?
12635                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12636                     t.apply(d)
12637             );
12638         }
12639         
12640         
12641         
12642         el.update(html.join(""));
12643         this.nodes = el.dom.childNodes;
12644         this.updateIndexes(0);
12645     },
12646     
12647
12648     /**
12649      * Function to override to reformat the data that is sent to
12650      * the template for each node.
12651      * DEPRICATED - use the preparedata event handler.
12652      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12653      * a JSON object for an UpdateManager bound view).
12654      */
12655     prepareData : function(data, index, record)
12656     {
12657         this.fireEvent("preparedata", this, data, index, record);
12658         return data;
12659     },
12660
12661     onUpdate : function(ds, record){
12662         // Roo.log('on update');   
12663         this.clearSelections();
12664         var index = this.store.indexOf(record);
12665         var n = this.nodes[index];
12666         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12667         n.parentNode.removeChild(n);
12668         this.updateIndexes(index, index);
12669     },
12670
12671     
12672     
12673 // --------- FIXME     
12674     onAdd : function(ds, records, index)
12675     {
12676         //Roo.log(['on Add', ds, records, index] );        
12677         this.clearSelections();
12678         if(this.nodes.length == 0){
12679             this.refresh();
12680             return;
12681         }
12682         var n = this.nodes[index];
12683         for(var i = 0, len = records.length; i < len; i++){
12684             var d = this.prepareData(records[i].data, i, records[i]);
12685             if(n){
12686                 this.tpl.insertBefore(n, d);
12687             }else{
12688                 
12689                 this.tpl.append(this.el, d);
12690             }
12691         }
12692         this.updateIndexes(index);
12693     },
12694
12695     onRemove : function(ds, record, index){
12696        // Roo.log('onRemove');
12697         this.clearSelections();
12698         var el = this.dataName  ?
12699             this.el.child('.roo-tpl-' + this.dataName) :
12700             this.el; 
12701         
12702         el.dom.removeChild(this.nodes[index]);
12703         this.updateIndexes(index);
12704     },
12705
12706     /**
12707      * Refresh an individual node.
12708      * @param {Number} index
12709      */
12710     refreshNode : function(index){
12711         this.onUpdate(this.store, this.store.getAt(index));
12712     },
12713
12714     updateIndexes : function(startIndex, endIndex){
12715         var ns = this.nodes;
12716         startIndex = startIndex || 0;
12717         endIndex = endIndex || ns.length - 1;
12718         for(var i = startIndex; i <= endIndex; i++){
12719             ns[i].nodeIndex = i;
12720         }
12721     },
12722
12723     /**
12724      * Changes the data store this view uses and refresh the view.
12725      * @param {Store} store
12726      */
12727     setStore : function(store, initial){
12728         if(!initial && this.store){
12729             this.store.un("datachanged", this.refresh);
12730             this.store.un("add", this.onAdd);
12731             this.store.un("remove", this.onRemove);
12732             this.store.un("update", this.onUpdate);
12733             this.store.un("clear", this.refresh);
12734             this.store.un("beforeload", this.onBeforeLoad);
12735             this.store.un("load", this.onLoad);
12736             this.store.un("loadexception", this.onLoad);
12737         }
12738         if(store){
12739           
12740             store.on("datachanged", this.refresh, this);
12741             store.on("add", this.onAdd, this);
12742             store.on("remove", this.onRemove, this);
12743             store.on("update", this.onUpdate, this);
12744             store.on("clear", this.refresh, this);
12745             store.on("beforeload", this.onBeforeLoad, this);
12746             store.on("load", this.onLoad, this);
12747             store.on("loadexception", this.onLoad, this);
12748         }
12749         
12750         if(store){
12751             this.refresh();
12752         }
12753     },
12754     /**
12755      * onbeforeLoad - masks the loading area.
12756      *
12757      */
12758     onBeforeLoad : function(store,opts)
12759     {
12760          //Roo.log('onBeforeLoad');   
12761         if (!opts.add) {
12762             this.el.update("");
12763         }
12764         this.el.mask(this.mask ? this.mask : "Loading" ); 
12765     },
12766     onLoad : function ()
12767     {
12768         this.el.unmask();
12769     },
12770     
12771
12772     /**
12773      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12774      * @param {HTMLElement} node
12775      * @return {HTMLElement} The template node
12776      */
12777     findItemFromChild : function(node){
12778         var el = this.dataName  ?
12779             this.el.child('.roo-tpl-' + this.dataName,true) :
12780             this.el.dom; 
12781         
12782         if(!node || node.parentNode == el){
12783                     return node;
12784             }
12785             var p = node.parentNode;
12786             while(p && p != el){
12787             if(p.parentNode == el){
12788                 return p;
12789             }
12790             p = p.parentNode;
12791         }
12792             return null;
12793     },
12794
12795     /** @ignore */
12796     onClick : function(e){
12797         var item = this.findItemFromChild(e.getTarget());
12798         if(item){
12799             var index = this.indexOf(item);
12800             if(this.onItemClick(item, index, e) !== false){
12801                 this.fireEvent("click", this, index, item, e);
12802             }
12803         }else{
12804             this.clearSelections();
12805         }
12806     },
12807
12808     /** @ignore */
12809     onContextMenu : function(e){
12810         var item = this.findItemFromChild(e.getTarget());
12811         if(item){
12812             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12813         }
12814     },
12815
12816     /** @ignore */
12817     onDblClick : function(e){
12818         var item = this.findItemFromChild(e.getTarget());
12819         if(item){
12820             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12821         }
12822     },
12823
12824     onItemClick : function(item, index, e)
12825     {
12826         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12827             return false;
12828         }
12829         if (this.toggleSelect) {
12830             var m = this.isSelected(item) ? 'unselect' : 'select';
12831             //Roo.log(m);
12832             var _t = this;
12833             _t[m](item, true, false);
12834             return true;
12835         }
12836         if(this.multiSelect || this.singleSelect){
12837             if(this.multiSelect && e.shiftKey && this.lastSelection){
12838                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12839             }else{
12840                 this.select(item, this.multiSelect && e.ctrlKey);
12841                 this.lastSelection = item;
12842             }
12843             
12844             if(!this.tickable){
12845                 e.preventDefault();
12846             }
12847             
12848         }
12849         return true;
12850     },
12851
12852     /**
12853      * Get the number of selected nodes.
12854      * @return {Number}
12855      */
12856     getSelectionCount : function(){
12857         return this.selections.length;
12858     },
12859
12860     /**
12861      * Get the currently selected nodes.
12862      * @return {Array} An array of HTMLElements
12863      */
12864     getSelectedNodes : function(){
12865         return this.selections;
12866     },
12867
12868     /**
12869      * Get the indexes of the selected nodes.
12870      * @return {Array}
12871      */
12872     getSelectedIndexes : function(){
12873         var indexes = [], s = this.selections;
12874         for(var i = 0, len = s.length; i < len; i++){
12875             indexes.push(s[i].nodeIndex);
12876         }
12877         return indexes;
12878     },
12879
12880     /**
12881      * Clear all selections
12882      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12883      */
12884     clearSelections : function(suppressEvent){
12885         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12886             this.cmp.elements = this.selections;
12887             this.cmp.removeClass(this.selectedClass);
12888             this.selections = [];
12889             if(!suppressEvent){
12890                 this.fireEvent("selectionchange", this, this.selections);
12891             }
12892         }
12893     },
12894
12895     /**
12896      * Returns true if the passed node is selected
12897      * @param {HTMLElement/Number} node The node or node index
12898      * @return {Boolean}
12899      */
12900     isSelected : function(node){
12901         var s = this.selections;
12902         if(s.length < 1){
12903             return false;
12904         }
12905         node = this.getNode(node);
12906         return s.indexOf(node) !== -1;
12907     },
12908
12909     /**
12910      * Selects nodes.
12911      * @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
12912      * @param {Boolean} keepExisting (optional) true to keep existing selections
12913      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12914      */
12915     select : function(nodeInfo, keepExisting, suppressEvent){
12916         if(nodeInfo instanceof Array){
12917             if(!keepExisting){
12918                 this.clearSelections(true);
12919             }
12920             for(var i = 0, len = nodeInfo.length; i < len; i++){
12921                 this.select(nodeInfo[i], true, true);
12922             }
12923             return;
12924         } 
12925         var node = this.getNode(nodeInfo);
12926         if(!node || this.isSelected(node)){
12927             return; // already selected.
12928         }
12929         if(!keepExisting){
12930             this.clearSelections(true);
12931         }
12932         
12933         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12934             Roo.fly(node).addClass(this.selectedClass);
12935             this.selections.push(node);
12936             if(!suppressEvent){
12937                 this.fireEvent("selectionchange", this, this.selections);
12938             }
12939         }
12940         
12941         
12942     },
12943       /**
12944      * Unselects nodes.
12945      * @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
12946      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12947      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12948      */
12949     unselect : function(nodeInfo, keepExisting, suppressEvent)
12950     {
12951         if(nodeInfo instanceof Array){
12952             Roo.each(this.selections, function(s) {
12953                 this.unselect(s, nodeInfo);
12954             }, this);
12955             return;
12956         }
12957         var node = this.getNode(nodeInfo);
12958         if(!node || !this.isSelected(node)){
12959             //Roo.log("not selected");
12960             return; // not selected.
12961         }
12962         // fireevent???
12963         var ns = [];
12964         Roo.each(this.selections, function(s) {
12965             if (s == node ) {
12966                 Roo.fly(node).removeClass(this.selectedClass);
12967
12968                 return;
12969             }
12970             ns.push(s);
12971         },this);
12972         
12973         this.selections= ns;
12974         this.fireEvent("selectionchange", this, this.selections);
12975     },
12976
12977     /**
12978      * Gets a template node.
12979      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12980      * @return {HTMLElement} The node or null if it wasn't found
12981      */
12982     getNode : function(nodeInfo){
12983         if(typeof nodeInfo == "string"){
12984             return document.getElementById(nodeInfo);
12985         }else if(typeof nodeInfo == "number"){
12986             return this.nodes[nodeInfo];
12987         }
12988         return nodeInfo;
12989     },
12990
12991     /**
12992      * Gets a range template nodes.
12993      * @param {Number} startIndex
12994      * @param {Number} endIndex
12995      * @return {Array} An array of nodes
12996      */
12997     getNodes : function(start, end){
12998         var ns = this.nodes;
12999         start = start || 0;
13000         end = typeof end == "undefined" ? ns.length - 1 : end;
13001         var nodes = [];
13002         if(start <= end){
13003             for(var i = start; i <= end; i++){
13004                 nodes.push(ns[i]);
13005             }
13006         } else{
13007             for(var i = start; i >= end; i--){
13008                 nodes.push(ns[i]);
13009             }
13010         }
13011         return nodes;
13012     },
13013
13014     /**
13015      * Finds the index of the passed node
13016      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13017      * @return {Number} The index of the node or -1
13018      */
13019     indexOf : function(node){
13020         node = this.getNode(node);
13021         if(typeof node.nodeIndex == "number"){
13022             return node.nodeIndex;
13023         }
13024         var ns = this.nodes;
13025         for(var i = 0, len = ns.length; i < len; i++){
13026             if(ns[i] == node){
13027                 return i;
13028             }
13029         }
13030         return -1;
13031     }
13032 });
13033 /*
13034  * - LGPL
13035  *
13036  * based on jquery fullcalendar
13037  * 
13038  */
13039
13040 Roo.bootstrap = Roo.bootstrap || {};
13041 /**
13042  * @class Roo.bootstrap.Calendar
13043  * @extends Roo.bootstrap.Component
13044  * Bootstrap Calendar class
13045  * @cfg {Boolean} loadMask (true|false) default false
13046  * @cfg {Object} header generate the user specific header of the calendar, default false
13047
13048  * @constructor
13049  * Create a new Container
13050  * @param {Object} config The config object
13051  */
13052
13053
13054
13055 Roo.bootstrap.Calendar = function(config){
13056     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13057      this.addEvents({
13058         /**
13059              * @event select
13060              * Fires when a date is selected
13061              * @param {DatePicker} this
13062              * @param {Date} date The selected date
13063              */
13064         'select': true,
13065         /**
13066              * @event monthchange
13067              * Fires when the displayed month changes 
13068              * @param {DatePicker} this
13069              * @param {Date} date The selected month
13070              */
13071         'monthchange': true,
13072         /**
13073              * @event evententer
13074              * Fires when mouse over an event
13075              * @param {Calendar} this
13076              * @param {event} Event
13077              */
13078         'evententer': true,
13079         /**
13080              * @event eventleave
13081              * Fires when the mouse leaves an
13082              * @param {Calendar} this
13083              * @param {event}
13084              */
13085         'eventleave': true,
13086         /**
13087              * @event eventclick
13088              * Fires when the mouse click an
13089              * @param {Calendar} this
13090              * @param {event}
13091              */
13092         'eventclick': true
13093         
13094     });
13095
13096 };
13097
13098 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13099     
13100      /**
13101      * @cfg {Number} startDay
13102      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13103      */
13104     startDay : 0,
13105     
13106     loadMask : false,
13107     
13108     header : false,
13109       
13110     getAutoCreate : function(){
13111         
13112         
13113         var fc_button = function(name, corner, style, content ) {
13114             return Roo.apply({},{
13115                 tag : 'span',
13116                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13117                          (corner.length ?
13118                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13119                             ''
13120                         ),
13121                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13122                 unselectable: 'on'
13123             });
13124         };
13125         
13126         var header = {};
13127         
13128         if(!this.header){
13129             header = {
13130                 tag : 'table',
13131                 cls : 'fc-header',
13132                 style : 'width:100%',
13133                 cn : [
13134                     {
13135                         tag: 'tr',
13136                         cn : [
13137                             {
13138                                 tag : 'td',
13139                                 cls : 'fc-header-left',
13140                                 cn : [
13141                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13142                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13143                                     { tag: 'span', cls: 'fc-header-space' },
13144                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13145
13146
13147                                 ]
13148                             },
13149
13150                             {
13151                                 tag : 'td',
13152                                 cls : 'fc-header-center',
13153                                 cn : [
13154                                     {
13155                                         tag: 'span',
13156                                         cls: 'fc-header-title',
13157                                         cn : {
13158                                             tag: 'H2',
13159                                             html : 'month / year'
13160                                         }
13161                                     }
13162
13163                                 ]
13164                             },
13165                             {
13166                                 tag : 'td',
13167                                 cls : 'fc-header-right',
13168                                 cn : [
13169                               /*      fc_button('month', 'left', '', 'month' ),
13170                                     fc_button('week', '', '', 'week' ),
13171                                     fc_button('day', 'right', '', 'day' )
13172                                 */    
13173
13174                                 ]
13175                             }
13176
13177                         ]
13178                     }
13179                 ]
13180             };
13181         }
13182         
13183         header = this.header;
13184         
13185        
13186         var cal_heads = function() {
13187             var ret = [];
13188             // fixme - handle this.
13189             
13190             for (var i =0; i < Date.dayNames.length; i++) {
13191                 var d = Date.dayNames[i];
13192                 ret.push({
13193                     tag: 'th',
13194                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13195                     html : d.substring(0,3)
13196                 });
13197                 
13198             }
13199             ret[0].cls += ' fc-first';
13200             ret[6].cls += ' fc-last';
13201             return ret;
13202         };
13203         var cal_cell = function(n) {
13204             return  {
13205                 tag: 'td',
13206                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13207                 cn : [
13208                     {
13209                         cn : [
13210                             {
13211                                 cls: 'fc-day-number',
13212                                 html: 'D'
13213                             },
13214                             {
13215                                 cls: 'fc-day-content',
13216                              
13217                                 cn : [
13218                                      {
13219                                         style: 'position: relative;' // height: 17px;
13220                                     }
13221                                 ]
13222                             }
13223                             
13224                             
13225                         ]
13226                     }
13227                 ]
13228                 
13229             }
13230         };
13231         var cal_rows = function() {
13232             
13233             var ret = [];
13234             for (var r = 0; r < 6; r++) {
13235                 var row= {
13236                     tag : 'tr',
13237                     cls : 'fc-week',
13238                     cn : []
13239                 };
13240                 
13241                 for (var i =0; i < Date.dayNames.length; i++) {
13242                     var d = Date.dayNames[i];
13243                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13244
13245                 }
13246                 row.cn[0].cls+=' fc-first';
13247                 row.cn[0].cn[0].style = 'min-height:90px';
13248                 row.cn[6].cls+=' fc-last';
13249                 ret.push(row);
13250                 
13251             }
13252             ret[0].cls += ' fc-first';
13253             ret[4].cls += ' fc-prev-last';
13254             ret[5].cls += ' fc-last';
13255             return ret;
13256             
13257         };
13258         
13259         var cal_table = {
13260             tag: 'table',
13261             cls: 'fc-border-separate',
13262             style : 'width:100%',
13263             cellspacing  : 0,
13264             cn : [
13265                 { 
13266                     tag: 'thead',
13267                     cn : [
13268                         { 
13269                             tag: 'tr',
13270                             cls : 'fc-first fc-last',
13271                             cn : cal_heads()
13272                         }
13273                     ]
13274                 },
13275                 { 
13276                     tag: 'tbody',
13277                     cn : cal_rows()
13278                 }
13279                   
13280             ]
13281         };
13282          
13283          var cfg = {
13284             cls : 'fc fc-ltr',
13285             cn : [
13286                 header,
13287                 {
13288                     cls : 'fc-content',
13289                     style : "position: relative;",
13290                     cn : [
13291                         {
13292                             cls : 'fc-view fc-view-month fc-grid',
13293                             style : 'position: relative',
13294                             unselectable : 'on',
13295                             cn : [
13296                                 {
13297                                     cls : 'fc-event-container',
13298                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13299                                 },
13300                                 cal_table
13301                             ]
13302                         }
13303                     ]
13304     
13305                 }
13306            ] 
13307             
13308         };
13309         
13310          
13311         
13312         return cfg;
13313     },
13314     
13315     
13316     initEvents : function()
13317     {
13318         if(!this.store){
13319             throw "can not find store for calendar";
13320         }
13321         
13322         var mark = {
13323             tag: "div",
13324             cls:"x-dlg-mask",
13325             style: "text-align:center",
13326             cn: [
13327                 {
13328                     tag: "div",
13329                     style: "background-color:white;width:50%;margin:250 auto",
13330                     cn: [
13331                         {
13332                             tag: "img",
13333                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13334                         },
13335                         {
13336                             tag: "span",
13337                             html: "Loading"
13338                         }
13339                         
13340                     ]
13341                 }
13342             ]
13343         }
13344         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13345         
13346         var size = this.el.select('.fc-content', true).first().getSize();
13347         this.maskEl.setSize(size.width, size.height);
13348         this.maskEl.enableDisplayMode("block");
13349         if(!this.loadMask){
13350             this.maskEl.hide();
13351         }
13352         
13353         this.store = Roo.factory(this.store, Roo.data);
13354         this.store.on('load', this.onLoad, this);
13355         this.store.on('beforeload', this.onBeforeLoad, this);
13356         
13357         this.resize();
13358         
13359         this.cells = this.el.select('.fc-day',true);
13360         //Roo.log(this.cells);
13361         this.textNodes = this.el.query('.fc-day-number');
13362         this.cells.addClassOnOver('fc-state-hover');
13363         
13364         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13365         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13366         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13367         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13368         
13369         this.on('monthchange', this.onMonthChange, this);
13370         
13371         this.update(new Date().clearTime());
13372     },
13373     
13374     resize : function() {
13375         var sz  = this.el.getSize();
13376         
13377         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13378         this.el.select('.fc-day-content div',true).setHeight(34);
13379     },
13380     
13381     
13382     // private
13383     showPrevMonth : function(e){
13384         this.update(this.activeDate.add("mo", -1));
13385     },
13386     showToday : function(e){
13387         this.update(new Date().clearTime());
13388     },
13389     // private
13390     showNextMonth : function(e){
13391         this.update(this.activeDate.add("mo", 1));
13392     },
13393
13394     // private
13395     showPrevYear : function(){
13396         this.update(this.activeDate.add("y", -1));
13397     },
13398
13399     // private
13400     showNextYear : function(){
13401         this.update(this.activeDate.add("y", 1));
13402     },
13403
13404     
13405    // private
13406     update : function(date)
13407     {
13408         var vd = this.activeDate;
13409         this.activeDate = date;
13410 //        if(vd && this.el){
13411 //            var t = date.getTime();
13412 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13413 //                Roo.log('using add remove');
13414 //                
13415 //                this.fireEvent('monthchange', this, date);
13416 //                
13417 //                this.cells.removeClass("fc-state-highlight");
13418 //                this.cells.each(function(c){
13419 //                   if(c.dateValue == t){
13420 //                       c.addClass("fc-state-highlight");
13421 //                       setTimeout(function(){
13422 //                            try{c.dom.firstChild.focus();}catch(e){}
13423 //                       }, 50);
13424 //                       return false;
13425 //                   }
13426 //                   return true;
13427 //                });
13428 //                return;
13429 //            }
13430 //        }
13431         
13432         var days = date.getDaysInMonth();
13433         
13434         var firstOfMonth = date.getFirstDateOfMonth();
13435         var startingPos = firstOfMonth.getDay()-this.startDay;
13436         
13437         if(startingPos < this.startDay){
13438             startingPos += 7;
13439         }
13440         
13441         var pm = date.add(Date.MONTH, -1);
13442         var prevStart = pm.getDaysInMonth()-startingPos;
13443 //        
13444         this.cells = this.el.select('.fc-day',true);
13445         this.textNodes = this.el.query('.fc-day-number');
13446         this.cells.addClassOnOver('fc-state-hover');
13447         
13448         var cells = this.cells.elements;
13449         var textEls = this.textNodes;
13450         
13451         Roo.each(cells, function(cell){
13452             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13453         });
13454         
13455         days += startingPos;
13456
13457         // convert everything to numbers so it's fast
13458         var day = 86400000;
13459         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13460         //Roo.log(d);
13461         //Roo.log(pm);
13462         //Roo.log(prevStart);
13463         
13464         var today = new Date().clearTime().getTime();
13465         var sel = date.clearTime().getTime();
13466         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13467         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13468         var ddMatch = this.disabledDatesRE;
13469         var ddText = this.disabledDatesText;
13470         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13471         var ddaysText = this.disabledDaysText;
13472         var format = this.format;
13473         
13474         var setCellClass = function(cal, cell){
13475             cell.row = 0;
13476             cell.events = [];
13477             cell.more = [];
13478             //Roo.log('set Cell Class');
13479             cell.title = "";
13480             var t = d.getTime();
13481             
13482             //Roo.log(d);
13483             
13484             cell.dateValue = t;
13485             if(t == today){
13486                 cell.className += " fc-today";
13487                 cell.className += " fc-state-highlight";
13488                 cell.title = cal.todayText;
13489             }
13490             if(t == sel){
13491                 // disable highlight in other month..
13492                 //cell.className += " fc-state-highlight";
13493                 
13494             }
13495             // disabling
13496             if(t < min) {
13497                 cell.className = " fc-state-disabled";
13498                 cell.title = cal.minText;
13499                 return;
13500             }
13501             if(t > max) {
13502                 cell.className = " fc-state-disabled";
13503                 cell.title = cal.maxText;
13504                 return;
13505             }
13506             if(ddays){
13507                 if(ddays.indexOf(d.getDay()) != -1){
13508                     cell.title = ddaysText;
13509                     cell.className = " fc-state-disabled";
13510                 }
13511             }
13512             if(ddMatch && format){
13513                 var fvalue = d.dateFormat(format);
13514                 if(ddMatch.test(fvalue)){
13515                     cell.title = ddText.replace("%0", fvalue);
13516                     cell.className = " fc-state-disabled";
13517                 }
13518             }
13519             
13520             if (!cell.initialClassName) {
13521                 cell.initialClassName = cell.dom.className;
13522             }
13523             
13524             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13525         };
13526
13527         var i = 0;
13528         
13529         for(; i < startingPos; i++) {
13530             textEls[i].innerHTML = (++prevStart);
13531             d.setDate(d.getDate()+1);
13532             
13533             cells[i].className = "fc-past fc-other-month";
13534             setCellClass(this, cells[i]);
13535         }
13536         
13537         var intDay = 0;
13538         
13539         for(; i < days; i++){
13540             intDay = i - startingPos + 1;
13541             textEls[i].innerHTML = (intDay);
13542             d.setDate(d.getDate()+1);
13543             
13544             cells[i].className = ''; // "x-date-active";
13545             setCellClass(this, cells[i]);
13546         }
13547         var extraDays = 0;
13548         
13549         for(; i < 42; i++) {
13550             textEls[i].innerHTML = (++extraDays);
13551             d.setDate(d.getDate()+1);
13552             
13553             cells[i].className = "fc-future fc-other-month";
13554             setCellClass(this, cells[i]);
13555         }
13556         
13557         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13558         
13559         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13560         
13561         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13562         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13563         
13564         if(totalRows != 6){
13565             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13566             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13567         }
13568         
13569         this.fireEvent('monthchange', this, date);
13570         
13571         
13572         /*
13573         if(!this.internalRender){
13574             var main = this.el.dom.firstChild;
13575             var w = main.offsetWidth;
13576             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13577             Roo.fly(main).setWidth(w);
13578             this.internalRender = true;
13579             // opera does not respect the auto grow header center column
13580             // then, after it gets a width opera refuses to recalculate
13581             // without a second pass
13582             if(Roo.isOpera && !this.secondPass){
13583                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13584                 this.secondPass = true;
13585                 this.update.defer(10, this, [date]);
13586             }
13587         }
13588         */
13589         
13590     },
13591     
13592     findCell : function(dt) {
13593         dt = dt.clearTime().getTime();
13594         var ret = false;
13595         this.cells.each(function(c){
13596             //Roo.log("check " +c.dateValue + '?=' + dt);
13597             if(c.dateValue == dt){
13598                 ret = c;
13599                 return false;
13600             }
13601             return true;
13602         });
13603         
13604         return ret;
13605     },
13606     
13607     findCells : function(ev) {
13608         var s = ev.start.clone().clearTime().getTime();
13609        // Roo.log(s);
13610         var e= ev.end.clone().clearTime().getTime();
13611        // Roo.log(e);
13612         var ret = [];
13613         this.cells.each(function(c){
13614              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13615             
13616             if(c.dateValue > e){
13617                 return ;
13618             }
13619             if(c.dateValue < s){
13620                 return ;
13621             }
13622             ret.push(c);
13623         });
13624         
13625         return ret;    
13626     },
13627     
13628 //    findBestRow: function(cells)
13629 //    {
13630 //        var ret = 0;
13631 //        
13632 //        for (var i =0 ; i < cells.length;i++) {
13633 //            ret  = Math.max(cells[i].rows || 0,ret);
13634 //        }
13635 //        return ret;
13636 //        
13637 //    },
13638     
13639     
13640     addItem : function(ev)
13641     {
13642         // look for vertical location slot in
13643         var cells = this.findCells(ev);
13644         
13645 //        ev.row = this.findBestRow(cells);
13646         
13647         // work out the location.
13648         
13649         var crow = false;
13650         var rows = [];
13651         for(var i =0; i < cells.length; i++) {
13652             
13653             cells[i].row = cells[0].row;
13654             
13655             if(i == 0){
13656                 cells[i].row = cells[i].row + 1;
13657             }
13658             
13659             if (!crow) {
13660                 crow = {
13661                     start : cells[i],
13662                     end :  cells[i]
13663                 };
13664                 continue;
13665             }
13666             if (crow.start.getY() == cells[i].getY()) {
13667                 // on same row.
13668                 crow.end = cells[i];
13669                 continue;
13670             }
13671             // different row.
13672             rows.push(crow);
13673             crow = {
13674                 start: cells[i],
13675                 end : cells[i]
13676             };
13677             
13678         }
13679         
13680         rows.push(crow);
13681         ev.els = [];
13682         ev.rows = rows;
13683         ev.cells = cells;
13684         
13685         cells[0].events.push(ev);
13686         
13687         this.calevents.push(ev);
13688     },
13689     
13690     clearEvents: function() {
13691         
13692         if(!this.calevents){
13693             return;
13694         }
13695         
13696         Roo.each(this.cells.elements, function(c){
13697             c.row = 0;
13698             c.events = [];
13699             c.more = [];
13700         });
13701         
13702         Roo.each(this.calevents, function(e) {
13703             Roo.each(e.els, function(el) {
13704                 el.un('mouseenter' ,this.onEventEnter, this);
13705                 el.un('mouseleave' ,this.onEventLeave, this);
13706                 el.remove();
13707             },this);
13708         },this);
13709         
13710         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13711             e.remove();
13712         });
13713         
13714     },
13715     
13716     renderEvents: function()
13717     {   
13718         var _this = this;
13719         
13720         this.cells.each(function(c) {
13721             
13722             if(c.row < 5){
13723                 return;
13724             }
13725             
13726             var ev = c.events;
13727             
13728             var r = 4;
13729             if(c.row != c.events.length){
13730                 r = 4 - (4 - (c.row - c.events.length));
13731             }
13732             
13733             c.events = ev.slice(0, r);
13734             c.more = ev.slice(r);
13735             
13736             if(c.more.length && c.more.length == 1){
13737                 c.events.push(c.more.pop());
13738             }
13739             
13740             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13741             
13742         });
13743             
13744         this.cells.each(function(c) {
13745             
13746             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13747             
13748             
13749             for (var e = 0; e < c.events.length; e++){
13750                 var ev = c.events[e];
13751                 var rows = ev.rows;
13752                 
13753                 for(var i = 0; i < rows.length; i++) {
13754                 
13755                     // how many rows should it span..
13756
13757                     var  cfg = {
13758                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13759                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13760
13761                         unselectable : "on",
13762                         cn : [
13763                             {
13764                                 cls: 'fc-event-inner',
13765                                 cn : [
13766     //                                {
13767     //                                  tag:'span',
13768     //                                  cls: 'fc-event-time',
13769     //                                  html : cells.length > 1 ? '' : ev.time
13770     //                                },
13771                                     {
13772                                       tag:'span',
13773                                       cls: 'fc-event-title',
13774                                       html : String.format('{0}', ev.title)
13775                                     }
13776
13777
13778                                 ]
13779                             },
13780                             {
13781                                 cls: 'ui-resizable-handle ui-resizable-e',
13782                                 html : '&nbsp;&nbsp;&nbsp'
13783                             }
13784
13785                         ]
13786                     };
13787
13788                     if (i == 0) {
13789                         cfg.cls += ' fc-event-start';
13790                     }
13791                     if ((i+1) == rows.length) {
13792                         cfg.cls += ' fc-event-end';
13793                     }
13794
13795                     var ctr = _this.el.select('.fc-event-container',true).first();
13796                     var cg = ctr.createChild(cfg);
13797
13798                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13799                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13800
13801                     var r = (c.more.length) ? 1 : 0;
13802                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13803                     cg.setWidth(ebox.right - sbox.x -2);
13804
13805                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13806                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13807                     cg.on('click', _this.onEventClick, _this, ev);
13808
13809                     ev.els.push(cg);
13810                     
13811                 }
13812                 
13813             }
13814             
13815             
13816             if(c.more.length){
13817                 var  cfg = {
13818                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13819                     style : 'position: absolute',
13820                     unselectable : "on",
13821                     cn : [
13822                         {
13823                             cls: 'fc-event-inner',
13824                             cn : [
13825                                 {
13826                                   tag:'span',
13827                                   cls: 'fc-event-title',
13828                                   html : 'More'
13829                                 }
13830
13831
13832                             ]
13833                         },
13834                         {
13835                             cls: 'ui-resizable-handle ui-resizable-e',
13836                             html : '&nbsp;&nbsp;&nbsp'
13837                         }
13838
13839                     ]
13840                 };
13841
13842                 var ctr = _this.el.select('.fc-event-container',true).first();
13843                 var cg = ctr.createChild(cfg);
13844
13845                 var sbox = c.select('.fc-day-content',true).first().getBox();
13846                 var ebox = c.select('.fc-day-content',true).first().getBox();
13847                 //Roo.log(cg);
13848                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13849                 cg.setWidth(ebox.right - sbox.x -2);
13850
13851                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13852                 
13853             }
13854             
13855         });
13856         
13857         
13858         
13859     },
13860     
13861     onEventEnter: function (e, el,event,d) {
13862         this.fireEvent('evententer', this, el, event);
13863     },
13864     
13865     onEventLeave: function (e, el,event,d) {
13866         this.fireEvent('eventleave', this, el, event);
13867     },
13868     
13869     onEventClick: function (e, el,event,d) {
13870         this.fireEvent('eventclick', this, el, event);
13871     },
13872     
13873     onMonthChange: function () {
13874         this.store.load();
13875     },
13876     
13877     onMoreEventClick: function(e, el, more)
13878     {
13879         var _this = this;
13880         
13881         this.calpopover.placement = 'right';
13882         this.calpopover.setTitle('More');
13883         
13884         this.calpopover.setContent('');
13885         
13886         var ctr = this.calpopover.el.select('.popover-content', true).first();
13887         
13888         Roo.each(more, function(m){
13889             var cfg = {
13890                 cls : 'fc-event-hori fc-event-draggable',
13891                 html : m.title
13892             }
13893             var cg = ctr.createChild(cfg);
13894             
13895             cg.on('click', _this.onEventClick, _this, m);
13896         });
13897         
13898         this.calpopover.show(el);
13899         
13900         
13901     },
13902     
13903     onLoad: function () 
13904     {   
13905         this.calevents = [];
13906         var cal = this;
13907         
13908         if(this.store.getCount() > 0){
13909             this.store.data.each(function(d){
13910                cal.addItem({
13911                     id : d.data.id,
13912                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13913                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13914                     time : d.data.start_time,
13915                     title : d.data.title,
13916                     description : d.data.description,
13917                     venue : d.data.venue
13918                 });
13919             });
13920         }
13921         
13922         this.renderEvents();
13923         
13924         if(this.calevents.length && this.loadMask){
13925             this.maskEl.hide();
13926         }
13927     },
13928     
13929     onBeforeLoad: function()
13930     {
13931         this.clearEvents();
13932         if(this.loadMask){
13933             this.maskEl.show();
13934         }
13935     }
13936 });
13937
13938  
13939  /*
13940  * - LGPL
13941  *
13942  * element
13943  * 
13944  */
13945
13946 /**
13947  * @class Roo.bootstrap.Popover
13948  * @extends Roo.bootstrap.Component
13949  * Bootstrap Popover class
13950  * @cfg {String} html contents of the popover   (or false to use children..)
13951  * @cfg {String} title of popover (or false to hide)
13952  * @cfg {String} placement how it is placed
13953  * @cfg {String} trigger click || hover (or false to trigger manually)
13954  * @cfg {String} over what (parent or false to trigger manually.)
13955  * @cfg {Number} delay - delay before showing
13956  
13957  * @constructor
13958  * Create a new Popover
13959  * @param {Object} config The config object
13960  */
13961
13962 Roo.bootstrap.Popover = function(config){
13963     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13964 };
13965
13966 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13967     
13968     title: 'Fill in a title',
13969     html: false,
13970     
13971     placement : 'right',
13972     trigger : 'hover', // hover
13973     
13974     delay : 0,
13975     
13976     over: 'parent',
13977     
13978     can_build_overlaid : false,
13979     
13980     getChildContainer : function()
13981     {
13982         return this.el.select('.popover-content',true).first();
13983     },
13984     
13985     getAutoCreate : function(){
13986          Roo.log('make popover?');
13987         var cfg = {
13988            cls : 'popover roo-dynamic',
13989            style: 'display:block',
13990            cn : [
13991                 {
13992                     cls : 'arrow'
13993                 },
13994                 {
13995                     cls : 'popover-inner',
13996                     cn : [
13997                         {
13998                             tag: 'h3',
13999                             cls: 'popover-title',
14000                             html : this.title
14001                         },
14002                         {
14003                             cls : 'popover-content',
14004                             html : this.html
14005                         }
14006                     ]
14007                     
14008                 }
14009            ]
14010         };
14011         
14012         return cfg;
14013     },
14014     setTitle: function(str)
14015     {
14016         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14017     },
14018     setContent: function(str)
14019     {
14020         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14021     },
14022     // as it get's added to the bottom of the page.
14023     onRender : function(ct, position)
14024     {
14025         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14026         if(!this.el){
14027             var cfg = Roo.apply({},  this.getAutoCreate());
14028             cfg.id = Roo.id();
14029             
14030             if (this.cls) {
14031                 cfg.cls += ' ' + this.cls;
14032             }
14033             if (this.style) {
14034                 cfg.style = this.style;
14035             }
14036             Roo.log("adding to ")
14037             this.el = Roo.get(document.body).createChild(cfg, position);
14038             Roo.log(this.el);
14039         }
14040         this.initEvents();
14041     },
14042     
14043     initEvents : function()
14044     {
14045         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14046         this.el.enableDisplayMode('block');
14047         this.el.hide();
14048         if (this.over === false) {
14049             return; 
14050         }
14051         if (this.triggers === false) {
14052             return;
14053         }
14054         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14055         var triggers = this.trigger ? this.trigger.split(' ') : [];
14056         Roo.each(triggers, function(trigger) {
14057         
14058             if (trigger == 'click') {
14059                 on_el.on('click', this.toggle, this);
14060             } else if (trigger != 'manual') {
14061                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14062                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14063       
14064                 on_el.on(eventIn  ,this.enter, this);
14065                 on_el.on(eventOut, this.leave, this);
14066             }
14067         }, this);
14068         
14069     },
14070     
14071     
14072     // private
14073     timeout : null,
14074     hoverState : null,
14075     
14076     toggle : function () {
14077         this.hoverState == 'in' ? this.leave() : this.enter();
14078     },
14079     
14080     enter : function () {
14081        
14082     
14083         clearTimeout(this.timeout);
14084     
14085         this.hoverState = 'in';
14086     
14087         if (!this.delay || !this.delay.show) {
14088             this.show();
14089             return;
14090         }
14091         var _t = this;
14092         this.timeout = setTimeout(function () {
14093             if (_t.hoverState == 'in') {
14094                 _t.show();
14095             }
14096         }, this.delay.show)
14097     },
14098     leave : function() {
14099         clearTimeout(this.timeout);
14100     
14101         this.hoverState = 'out';
14102     
14103         if (!this.delay || !this.delay.hide) {
14104             this.hide();
14105             return;
14106         }
14107         var _t = this;
14108         this.timeout = setTimeout(function () {
14109             if (_t.hoverState == 'out') {
14110                 _t.hide();
14111             }
14112         }, this.delay.hide)
14113     },
14114     
14115     show : function (on_el)
14116     {
14117         if (!on_el) {
14118             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14119         }
14120         // set content.
14121         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14122         if (this.html !== false) {
14123             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14124         }
14125         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14126         if (!this.title.length) {
14127             this.el.select('.popover-title',true).hide();
14128         }
14129         
14130         var placement = typeof this.placement == 'function' ?
14131             this.placement.call(this, this.el, on_el) :
14132             this.placement;
14133             
14134         var autoToken = /\s?auto?\s?/i;
14135         var autoPlace = autoToken.test(placement);
14136         if (autoPlace) {
14137             placement = placement.replace(autoToken, '') || 'top';
14138         }
14139         
14140         //this.el.detach()
14141         //this.el.setXY([0,0]);
14142         this.el.show();
14143         this.el.dom.style.display='block';
14144         this.el.addClass(placement);
14145         
14146         //this.el.appendTo(on_el);
14147         
14148         var p = this.getPosition();
14149         var box = this.el.getBox();
14150         
14151         if (autoPlace) {
14152             // fixme..
14153         }
14154         var align = Roo.bootstrap.Popover.alignment[placement];
14155         this.el.alignTo(on_el, align[0],align[1]);
14156         //var arrow = this.el.select('.arrow',true).first();
14157         //arrow.set(align[2], 
14158         
14159         this.el.addClass('in');
14160         this.hoverState = null;
14161         
14162         if (this.el.hasClass('fade')) {
14163             // fade it?
14164         }
14165         
14166     },
14167     hide : function()
14168     {
14169         this.el.setXY([0,0]);
14170         this.el.removeClass('in');
14171         this.el.hide();
14172         
14173     }
14174     
14175 });
14176
14177 Roo.bootstrap.Popover.alignment = {
14178     'left' : ['r-l', [-10,0], 'right'],
14179     'right' : ['l-r', [10,0], 'left'],
14180     'bottom' : ['t-b', [0,10], 'top'],
14181     'top' : [ 'b-t', [0,-10], 'bottom']
14182 };
14183
14184  /*
14185  * - LGPL
14186  *
14187  * Progress
14188  * 
14189  */
14190
14191 /**
14192  * @class Roo.bootstrap.Progress
14193  * @extends Roo.bootstrap.Component
14194  * Bootstrap Progress class
14195  * @cfg {Boolean} striped striped of the progress bar
14196  * @cfg {Boolean} active animated of the progress bar
14197  * 
14198  * 
14199  * @constructor
14200  * Create a new Progress
14201  * @param {Object} config The config object
14202  */
14203
14204 Roo.bootstrap.Progress = function(config){
14205     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14206 };
14207
14208 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14209     
14210     striped : false,
14211     active: false,
14212     
14213     getAutoCreate : function(){
14214         var cfg = {
14215             tag: 'div',
14216             cls: 'progress'
14217         };
14218         
14219         
14220         if(this.striped){
14221             cfg.cls += ' progress-striped';
14222         }
14223       
14224         if(this.active){
14225             cfg.cls += ' active';
14226         }
14227         
14228         
14229         return cfg;
14230     }
14231    
14232 });
14233
14234  
14235
14236  /*
14237  * - LGPL
14238  *
14239  * ProgressBar
14240  * 
14241  */
14242
14243 /**
14244  * @class Roo.bootstrap.ProgressBar
14245  * @extends Roo.bootstrap.Component
14246  * Bootstrap ProgressBar class
14247  * @cfg {Number} aria_valuenow aria-value now
14248  * @cfg {Number} aria_valuemin aria-value min
14249  * @cfg {Number} aria_valuemax aria-value max
14250  * @cfg {String} label label for the progress bar
14251  * @cfg {String} panel (success | info | warning | danger )
14252  * @cfg {String} role role of the progress bar
14253  * @cfg {String} sr_only text
14254  * 
14255  * 
14256  * @constructor
14257  * Create a new ProgressBar
14258  * @param {Object} config The config object
14259  */
14260
14261 Roo.bootstrap.ProgressBar = function(config){
14262     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14263 };
14264
14265 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14266     
14267     aria_valuenow : 0,
14268     aria_valuemin : 0,
14269     aria_valuemax : 100,
14270     label : false,
14271     panel : false,
14272     role : false,
14273     sr_only: false,
14274     
14275     getAutoCreate : function()
14276     {
14277         
14278         var cfg = {
14279             tag: 'div',
14280             cls: 'progress-bar',
14281             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14282         };
14283         
14284         if(this.sr_only){
14285             cfg.cn = {
14286                 tag: 'span',
14287                 cls: 'sr-only',
14288                 html: this.sr_only
14289             }
14290         }
14291         
14292         if(this.role){
14293             cfg.role = this.role;
14294         }
14295         
14296         if(this.aria_valuenow){
14297             cfg['aria-valuenow'] = this.aria_valuenow;
14298         }
14299         
14300         if(this.aria_valuemin){
14301             cfg['aria-valuemin'] = this.aria_valuemin;
14302         }
14303         
14304         if(this.aria_valuemax){
14305             cfg['aria-valuemax'] = this.aria_valuemax;
14306         }
14307         
14308         if(this.label && !this.sr_only){
14309             cfg.html = this.label;
14310         }
14311         
14312         if(this.panel){
14313             cfg.cls += ' progress-bar-' + this.panel;
14314         }
14315         
14316         return cfg;
14317     },
14318     
14319     update : function(aria_valuenow)
14320     {
14321         this.aria_valuenow = aria_valuenow;
14322         
14323         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14324     }
14325    
14326 });
14327
14328  
14329
14330  /*
14331  * - LGPL
14332  *
14333  * column
14334  * 
14335  */
14336
14337 /**
14338  * @class Roo.bootstrap.TabGroup
14339  * @extends Roo.bootstrap.Column
14340  * Bootstrap Column class
14341  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14342  * @cfg {Boolean} carousel true to make the group behave like a carousel
14343  * 
14344  * @constructor
14345  * Create a new TabGroup
14346  * @param {Object} config The config object
14347  */
14348
14349 Roo.bootstrap.TabGroup = function(config){
14350     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14351     if (!this.navId) {
14352         this.navId = Roo.id();
14353     }
14354     this.tabs = [];
14355     Roo.bootstrap.TabGroup.register(this);
14356     
14357 };
14358
14359 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14360     
14361     carousel : false,
14362     transition : false,
14363      
14364     getAutoCreate : function()
14365     {
14366         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14367         
14368         cfg.cls += ' tab-content';
14369         
14370         if (this.carousel) {
14371             cfg.cls += ' carousel slide';
14372             cfg.cn = [{
14373                cls : 'carousel-inner'
14374             }]
14375         }
14376         
14377         
14378         return cfg;
14379     },
14380     getChildContainer : function()
14381     {
14382         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14383     },
14384     
14385     /**
14386     * register a Navigation item
14387     * @param {Roo.bootstrap.NavItem} the navitem to add
14388     */
14389     register : function(item)
14390     {
14391         this.tabs.push( item);
14392         item.navId = this.navId; // not really needed..
14393     
14394     },
14395     
14396     getActivePanel : function()
14397     {
14398         var r = false;
14399         Roo.each(this.tabs, function(t) {
14400             if (t.active) {
14401                 r = t;
14402                 return false;
14403             }
14404             return null;
14405         });
14406         return r;
14407         
14408     },
14409     getPanelByName : function(n)
14410     {
14411         var r = false;
14412         Roo.each(this.tabs, function(t) {
14413             if (t.tabId == n) {
14414                 r = t;
14415                 return false;
14416             }
14417             return null;
14418         });
14419         return r;
14420     },
14421     indexOfPanel : function(p)
14422     {
14423         var r = false;
14424         Roo.each(this.tabs, function(t,i) {
14425             if (t.tabId == p.tabId) {
14426                 r = i;
14427                 return false;
14428             }
14429             return null;
14430         });
14431         return r;
14432     },
14433     /**
14434      * show a specific panel
14435      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14436      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14437      */
14438     showPanel : function (pan)
14439     {
14440         
14441         if (typeof(pan) == 'number') {
14442             pan = this.tabs[pan];
14443         }
14444         if (typeof(pan) == 'string') {
14445             pan = this.getPanelByName(pan);
14446         }
14447         if (pan.tabId == this.getActivePanel().tabId) {
14448             return true;
14449         }
14450         var cur = this.getActivePanel();
14451         
14452         if (false === cur.fireEvent('beforedeactivate')) {
14453             return false;
14454         }
14455         
14456         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14457             
14458             this.transition = true;
14459             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14460             var lr = dir == 'next' ? 'left' : 'right';
14461             pan.el.addClass(dir); // or prev
14462             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14463             cur.el.addClass(lr); // or right
14464             pan.el.addClass(lr);
14465             
14466             var _this = this;
14467             cur.el.on('transitionend', function() {
14468                 Roo.log("trans end?");
14469                 
14470                 pan.el.removeClass([lr,dir]);
14471                 pan.setActive(true);
14472                 
14473                 cur.el.removeClass([lr]);
14474                 cur.setActive(false);
14475                 
14476                 _this.transition = false;
14477                 
14478             }, this, { single:  true } );
14479             return true;
14480         }
14481         
14482         cur.setActive(false);
14483         pan.setActive(true);
14484         return true;
14485         
14486     },
14487     showPanelNext : function()
14488     {
14489         var i = this.indexOfPanel(this.getActivePanel());
14490         if (i > this.tabs.length) {
14491             return;
14492         }
14493         this.showPanel(this.tabs[i+1]);
14494     },
14495     showPanelPrev : function()
14496     {
14497         var i = this.indexOfPanel(this.getActivePanel());
14498         if (i  < 1) {
14499             return;
14500         }
14501         this.showPanel(this.tabs[i-1]);
14502     }
14503     
14504     
14505   
14506 });
14507
14508  
14509
14510  
14511  
14512 Roo.apply(Roo.bootstrap.TabGroup, {
14513     
14514     groups: {},
14515      /**
14516     * register a Navigation Group
14517     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14518     */
14519     register : function(navgrp)
14520     {
14521         this.groups[navgrp.navId] = navgrp;
14522         
14523     },
14524     /**
14525     * fetch a Navigation Group based on the navigation ID
14526     * if one does not exist , it will get created.
14527     * @param {string} the navgroup to add
14528     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14529     */
14530     get: function(navId) {
14531         if (typeof(this.groups[navId]) == 'undefined') {
14532             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14533         }
14534         return this.groups[navId] ;
14535     }
14536     
14537     
14538     
14539 });
14540
14541  /*
14542  * - LGPL
14543  *
14544  * TabPanel
14545  * 
14546  */
14547
14548 /**
14549  * @class Roo.bootstrap.TabPanel
14550  * @extends Roo.bootstrap.Component
14551  * Bootstrap TabPanel class
14552  * @cfg {Boolean} active panel active
14553  * @cfg {String} html panel content
14554  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14555  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14556  * 
14557  * 
14558  * @constructor
14559  * Create a new TabPanel
14560  * @param {Object} config The config object
14561  */
14562
14563 Roo.bootstrap.TabPanel = function(config){
14564     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14565     this.addEvents({
14566         /**
14567              * @event changed
14568              * Fires when the active status changes
14569              * @param {Roo.bootstrap.TabPanel} this
14570              * @param {Boolean} state the new state
14571             
14572          */
14573         'changed': true,
14574         /**
14575              * @event beforedeactivate
14576              * Fires before a tab is de-activated - can be used to do validation on a form.
14577              * @param {Roo.bootstrap.TabPanel} this
14578              * @return {Boolean} false if there is an error
14579             
14580          */
14581         'beforedeactivate': true
14582      });
14583     
14584     this.tabId = this.tabId || Roo.id();
14585   
14586 };
14587
14588 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14589     
14590     active: false,
14591     html: false,
14592     tabId: false,
14593     navId : false,
14594     
14595     getAutoCreate : function(){
14596         var cfg = {
14597             tag: 'div',
14598             // item is needed for carousel - not sure if it has any effect otherwise
14599             cls: 'tab-pane item',
14600             html: this.html || ''
14601         };
14602         
14603         if(this.active){
14604             cfg.cls += ' active';
14605         }
14606         
14607         if(this.tabId){
14608             cfg.tabId = this.tabId;
14609         }
14610         
14611         
14612         return cfg;
14613     },
14614     
14615     initEvents:  function()
14616     {
14617         Roo.log('-------- init events on tab panel ---------');
14618         
14619         var p = this.parent();
14620         this.navId = this.navId || p.navId;
14621         
14622         if (typeof(this.navId) != 'undefined') {
14623             // not really needed.. but just in case.. parent should be a NavGroup.
14624             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14625             Roo.log(['register', tg, this]);
14626             tg.register(this);
14627         }
14628     },
14629     
14630     
14631     onRender : function(ct, position)
14632     {
14633        // Roo.log("Call onRender: " + this.xtype);
14634         
14635         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14636         
14637         
14638         
14639         
14640         
14641     },
14642     
14643     setActive: function(state)
14644     {
14645         Roo.log("panel - set active " + this.tabId + "=" + state);
14646         
14647         this.active = state;
14648         if (!state) {
14649             this.el.removeClass('active');
14650             
14651         } else  if (!this.el.hasClass('active')) {
14652             this.el.addClass('active');
14653         }
14654         this.fireEvent('changed', this, state);
14655     }
14656     
14657     
14658 });
14659  
14660
14661  
14662
14663  /*
14664  * - LGPL
14665  *
14666  * DateField
14667  * 
14668  */
14669
14670 /**
14671  * @class Roo.bootstrap.DateField
14672  * @extends Roo.bootstrap.Input
14673  * Bootstrap DateField class
14674  * @cfg {Number} weekStart default 0
14675  * @cfg {String} viewMode default empty, (months|years)
14676  * @cfg {String} minViewMode default empty, (months|years)
14677  * @cfg {Number} startDate default -Infinity
14678  * @cfg {Number} endDate default Infinity
14679  * @cfg {Boolean} todayHighlight default false
14680  * @cfg {Boolean} todayBtn default false
14681  * @cfg {Boolean} calendarWeeks default false
14682  * @cfg {Object} daysOfWeekDisabled default empty
14683  * @cfg {Boolean} singleMode default false (true | false)
14684  * 
14685  * @cfg {Boolean} keyboardNavigation default true
14686  * @cfg {String} language default en
14687  * 
14688  * @constructor
14689  * Create a new DateField
14690  * @param {Object} config The config object
14691  */
14692
14693 Roo.bootstrap.DateField = function(config){
14694     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14695      this.addEvents({
14696             /**
14697              * @event show
14698              * Fires when this field show.
14699              * @param {Roo.bootstrap.DateField} this
14700              * @param {Mixed} date The date value
14701              */
14702             show : true,
14703             /**
14704              * @event show
14705              * Fires when this field hide.
14706              * @param {Roo.bootstrap.DateField} this
14707              * @param {Mixed} date The date value
14708              */
14709             hide : true,
14710             /**
14711              * @event select
14712              * Fires when select a date.
14713              * @param {Roo.bootstrap.DateField} this
14714              * @param {Mixed} date The date value
14715              */
14716             select : true
14717         });
14718 };
14719
14720 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14721     
14722     /**
14723      * @cfg {String} format
14724      * The default date format string which can be overriden for localization support.  The format must be
14725      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14726      */
14727     format : "m/d/y",
14728     /**
14729      * @cfg {String} altFormats
14730      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14731      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14732      */
14733     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14734     
14735     weekStart : 0,
14736     
14737     viewMode : '',
14738     
14739     minViewMode : '',
14740     
14741     todayHighlight : false,
14742     
14743     todayBtn: false,
14744     
14745     language: 'en',
14746     
14747     keyboardNavigation: true,
14748     
14749     calendarWeeks: false,
14750     
14751     startDate: -Infinity,
14752     
14753     endDate: Infinity,
14754     
14755     daysOfWeekDisabled: [],
14756     
14757     _events: [],
14758     
14759     singleMode : false,
14760     
14761     UTCDate: function()
14762     {
14763         return new Date(Date.UTC.apply(Date, arguments));
14764     },
14765     
14766     UTCToday: function()
14767     {
14768         var today = new Date();
14769         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14770     },
14771     
14772     getDate: function() {
14773             var d = this.getUTCDate();
14774             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14775     },
14776     
14777     getUTCDate: function() {
14778             return this.date;
14779     },
14780     
14781     setDate: function(d) {
14782             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14783     },
14784     
14785     setUTCDate: function(d) {
14786             this.date = d;
14787             this.setValue(this.formatDate(this.date));
14788     },
14789         
14790     onRender: function(ct, position)
14791     {
14792         
14793         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14794         
14795         this.language = this.language || 'en';
14796         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14797         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14798         
14799         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14800         this.format = this.format || 'm/d/y';
14801         this.isInline = false;
14802         this.isInput = true;
14803         this.component = this.el.select('.add-on', true).first() || false;
14804         this.component = (this.component && this.component.length === 0) ? false : this.component;
14805         this.hasInput = this.component && this.inputEL().length;
14806         
14807         if (typeof(this.minViewMode === 'string')) {
14808             switch (this.minViewMode) {
14809                 case 'months':
14810                     this.minViewMode = 1;
14811                     break;
14812                 case 'years':
14813                     this.minViewMode = 2;
14814                     break;
14815                 default:
14816                     this.minViewMode = 0;
14817                     break;
14818             }
14819         }
14820         
14821         if (typeof(this.viewMode === 'string')) {
14822             switch (this.viewMode) {
14823                 case 'months':
14824                     this.viewMode = 1;
14825                     break;
14826                 case 'years':
14827                     this.viewMode = 2;
14828                     break;
14829                 default:
14830                     this.viewMode = 0;
14831                     break;
14832             }
14833         }
14834                 
14835         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14836         
14837 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14838         
14839         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14840         
14841         this.picker().on('mousedown', this.onMousedown, this);
14842         this.picker().on('click', this.onClick, this);
14843         
14844         this.picker().addClass('datepicker-dropdown');
14845         
14846         this.startViewMode = this.viewMode;
14847         
14848         if(this.singleMode){
14849             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14850                 v.setVisibilityMode(Roo.Element.DISPLAY)
14851                 v.hide();
14852             });
14853             
14854             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14855                 v.setStyle('width', '189px');
14856             });
14857         }
14858         
14859         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14860             if(!this.calendarWeeks){
14861                 v.remove();
14862                 return;
14863             }
14864             
14865             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14866             v.attr('colspan', function(i, val){
14867                 return parseInt(val) + 1;
14868             });
14869         })
14870                         
14871         
14872         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14873         
14874         this.setStartDate(this.startDate);
14875         this.setEndDate(this.endDate);
14876         
14877         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14878         
14879         this.fillDow();
14880         this.fillMonths();
14881         this.update();
14882         this.showMode();
14883         
14884         if(this.isInline) {
14885             this.show();
14886         }
14887     },
14888     
14889     picker : function()
14890     {
14891         return this.pickerEl;
14892 //        return this.el.select('.datepicker', true).first();
14893     },
14894     
14895     fillDow: function()
14896     {
14897         var dowCnt = this.weekStart;
14898         
14899         var dow = {
14900             tag: 'tr',
14901             cn: [
14902                 
14903             ]
14904         };
14905         
14906         if(this.calendarWeeks){
14907             dow.cn.push({
14908                 tag: 'th',
14909                 cls: 'cw',
14910                 html: '&nbsp;'
14911             })
14912         }
14913         
14914         while (dowCnt < this.weekStart + 7) {
14915             dow.cn.push({
14916                 tag: 'th',
14917                 cls: 'dow',
14918                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14919             });
14920         }
14921         
14922         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14923     },
14924     
14925     fillMonths: function()
14926     {    
14927         var i = 0;
14928         var months = this.picker().select('>.datepicker-months td', true).first();
14929         
14930         months.dom.innerHTML = '';
14931         
14932         while (i < 12) {
14933             var month = {
14934                 tag: 'span',
14935                 cls: 'month',
14936                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14937             }
14938             
14939             months.createChild(month);
14940         }
14941         
14942     },
14943     
14944     update: function()
14945     {
14946         this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14947         
14948         if (this.date < this.startDate) {
14949             this.viewDate = new Date(this.startDate);
14950         } else if (this.date > this.endDate) {
14951             this.viewDate = new Date(this.endDate);
14952         } else {
14953             this.viewDate = new Date(this.date);
14954         }
14955         
14956         this.fill();
14957     },
14958     
14959     fill: function() 
14960     {
14961         var d = new Date(this.viewDate),
14962                 year = d.getUTCFullYear(),
14963                 month = d.getUTCMonth(),
14964                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14965                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14966                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14967                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14968                 currentDate = this.date && this.date.valueOf(),
14969                 today = this.UTCToday();
14970         
14971         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14972         
14973 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14974         
14975 //        this.picker.select('>tfoot th.today').
14976 //                                              .text(dates[this.language].today)
14977 //                                              .toggle(this.todayBtn !== false);
14978     
14979         this.updateNavArrows();
14980         this.fillMonths();
14981                                                 
14982         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14983         
14984         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14985          
14986         prevMonth.setUTCDate(day);
14987         
14988         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14989         
14990         var nextMonth = new Date(prevMonth);
14991         
14992         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14993         
14994         nextMonth = nextMonth.valueOf();
14995         
14996         var fillMonths = false;
14997         
14998         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14999         
15000         while(prevMonth.valueOf() < nextMonth) {
15001             var clsName = '';
15002             
15003             if (prevMonth.getUTCDay() === this.weekStart) {
15004                 if(fillMonths){
15005                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15006                 }
15007                     
15008                 fillMonths = {
15009                     tag: 'tr',
15010                     cn: []
15011                 };
15012                 
15013                 if(this.calendarWeeks){
15014                     // ISO 8601: First week contains first thursday.
15015                     // ISO also states week starts on Monday, but we can be more abstract here.
15016                     var
15017                     // Start of current week: based on weekstart/current date
15018                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15019                     // Thursday of this week
15020                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15021                     // First Thursday of year, year from thursday
15022                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15023                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15024                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15025                     
15026                     fillMonths.cn.push({
15027                         tag: 'td',
15028                         cls: 'cw',
15029                         html: calWeek
15030                     });
15031                 }
15032             }
15033             
15034             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15035                 clsName += ' old';
15036             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15037                 clsName += ' new';
15038             }
15039             if (this.todayHighlight &&
15040                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15041                 prevMonth.getUTCMonth() == today.getMonth() &&
15042                 prevMonth.getUTCDate() == today.getDate()) {
15043                 clsName += ' today';
15044             }
15045             
15046             if (currentDate && prevMonth.valueOf() === currentDate) {
15047                 clsName += ' active';
15048             }
15049             
15050             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15051                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15052                     clsName += ' disabled';
15053             }
15054             
15055             fillMonths.cn.push({
15056                 tag: 'td',
15057                 cls: 'day ' + clsName,
15058                 html: prevMonth.getDate()
15059             })
15060             
15061             prevMonth.setDate(prevMonth.getDate()+1);
15062         }
15063           
15064         var currentYear = this.date && this.date.getUTCFullYear();
15065         var currentMonth = this.date && this.date.getUTCMonth();
15066         
15067         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15068         
15069         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15070             v.removeClass('active');
15071             
15072             if(currentYear === year && k === currentMonth){
15073                 v.addClass('active');
15074             }
15075             
15076             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15077                 v.addClass('disabled');
15078             }
15079             
15080         });
15081         
15082         
15083         year = parseInt(year/10, 10) * 10;
15084         
15085         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15086         
15087         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15088         
15089         year -= 1;
15090         for (var i = -1; i < 11; i++) {
15091             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15092                 tag: 'span',
15093                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15094                 html: year
15095             })
15096             
15097             year += 1;
15098         }
15099     },
15100     
15101     showMode: function(dir) 
15102     {
15103         if (dir) {
15104             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15105         }
15106         
15107         Roo.each(this.picker().select('>div',true).elements, function(v){
15108             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15109             v.hide();
15110         });
15111         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15112     },
15113     
15114     place: function()
15115     {
15116         if(this.isInline) return;
15117         
15118         this.picker().removeClass(['bottom', 'top']);
15119         
15120         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15121             /*
15122              * place to the top of element!
15123              *
15124              */
15125             
15126             this.picker().addClass('top');
15127             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15128             
15129             return;
15130         }
15131         
15132         this.picker().addClass('bottom');
15133         
15134         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15135     },
15136     
15137     parseDate : function(value)
15138     {
15139         if(!value || value instanceof Date){
15140             return value;
15141         }
15142         var v = Date.parseDate(value, this.format);
15143         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15144             v = Date.parseDate(value, 'Y-m-d');
15145         }
15146         if(!v && this.altFormats){
15147             if(!this.altFormatsArray){
15148                 this.altFormatsArray = this.altFormats.split("|");
15149             }
15150             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15151                 v = Date.parseDate(value, this.altFormatsArray[i]);
15152             }
15153         }
15154         return v;
15155     },
15156     
15157     formatDate : function(date, fmt)
15158     {   
15159         return (!date || !(date instanceof Date)) ?
15160         date : date.dateFormat(fmt || this.format);
15161     },
15162     
15163     onFocus : function()
15164     {
15165         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15166         this.show();
15167     },
15168     
15169     onBlur : function()
15170     {
15171         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15172         
15173         var d = this.inputEl().getValue();
15174         
15175         this.setValue(d);
15176                 
15177         this.hide();
15178     },
15179     
15180     show : function()
15181     {
15182         this.picker().show();
15183         this.update();
15184         this.place();
15185         
15186         this.fireEvent('show', this, this.date);
15187     },
15188     
15189     hide : function()
15190     {
15191         if(this.isInline) return;
15192         this.picker().hide();
15193         this.viewMode = this.startViewMode;
15194         this.showMode();
15195         
15196         this.fireEvent('hide', this, this.date);
15197         
15198     },
15199     
15200     onMousedown: function(e)
15201     {
15202         e.stopPropagation();
15203         e.preventDefault();
15204     },
15205     
15206     keyup: function(e)
15207     {
15208         Roo.bootstrap.DateField.superclass.keyup.call(this);
15209         this.update();
15210     },
15211
15212     setValue: function(v)
15213     {
15214         
15215         // v can be a string or a date..
15216         
15217         
15218         var d = new Date(this.parseDate(v) ).clearTime();
15219         
15220         if(isNaN(d.getTime())){
15221             this.date = this.viewDate = '';
15222             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15223             return;
15224         }
15225         
15226         v = this.formatDate(d);
15227         
15228         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15229         
15230         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15231      
15232         this.update();
15233
15234         this.fireEvent('select', this, this.date);
15235         
15236     },
15237     
15238     getValue: function()
15239     {
15240         return this.formatDate(this.date);
15241     },
15242     
15243     fireKey: function(e)
15244     {
15245         if (!this.picker().isVisible()){
15246             if (e.keyCode == 27) // allow escape to hide and re-show picker
15247                 this.show();
15248             return;
15249         }
15250         
15251         var dateChanged = false,
15252         dir, day, month,
15253         newDate, newViewDate;
15254         
15255         switch(e.keyCode){
15256             case 27: // escape
15257                 this.hide();
15258                 e.preventDefault();
15259                 break;
15260             case 37: // left
15261             case 39: // right
15262                 if (!this.keyboardNavigation) break;
15263                 dir = e.keyCode == 37 ? -1 : 1;
15264                 
15265                 if (e.ctrlKey){
15266                     newDate = this.moveYear(this.date, dir);
15267                     newViewDate = this.moveYear(this.viewDate, dir);
15268                 } else if (e.shiftKey){
15269                     newDate = this.moveMonth(this.date, dir);
15270                     newViewDate = this.moveMonth(this.viewDate, dir);
15271                 } else {
15272                     newDate = new Date(this.date);
15273                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15274                     newViewDate = new Date(this.viewDate);
15275                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15276                 }
15277                 if (this.dateWithinRange(newDate)){
15278                     this.date = newDate;
15279                     this.viewDate = newViewDate;
15280                     this.setValue(this.formatDate(this.date));
15281 //                    this.update();
15282                     e.preventDefault();
15283                     dateChanged = true;
15284                 }
15285                 break;
15286             case 38: // up
15287             case 40: // down
15288                 if (!this.keyboardNavigation) break;
15289                 dir = e.keyCode == 38 ? -1 : 1;
15290                 if (e.ctrlKey){
15291                     newDate = this.moveYear(this.date, dir);
15292                     newViewDate = this.moveYear(this.viewDate, dir);
15293                 } else if (e.shiftKey){
15294                     newDate = this.moveMonth(this.date, dir);
15295                     newViewDate = this.moveMonth(this.viewDate, dir);
15296                 } else {
15297                     newDate = new Date(this.date);
15298                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15299                     newViewDate = new Date(this.viewDate);
15300                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15301                 }
15302                 if (this.dateWithinRange(newDate)){
15303                     this.date = newDate;
15304                     this.viewDate = newViewDate;
15305                     this.setValue(this.formatDate(this.date));
15306 //                    this.update();
15307                     e.preventDefault();
15308                     dateChanged = true;
15309                 }
15310                 break;
15311             case 13: // enter
15312                 this.setValue(this.formatDate(this.date));
15313                 this.hide();
15314                 e.preventDefault();
15315                 break;
15316             case 9: // tab
15317                 this.setValue(this.formatDate(this.date));
15318                 this.hide();
15319                 break;
15320             case 16: // shift
15321             case 17: // ctrl
15322             case 18: // alt
15323                 break;
15324             default :
15325                 this.hide();
15326                 
15327         }
15328     },
15329     
15330     
15331     onClick: function(e) 
15332     {
15333         e.stopPropagation();
15334         e.preventDefault();
15335         
15336         var target = e.getTarget();
15337         
15338         if(target.nodeName.toLowerCase() === 'i'){
15339             target = Roo.get(target).dom.parentNode;
15340         }
15341         
15342         var nodeName = target.nodeName;
15343         var className = target.className;
15344         var html = target.innerHTML;
15345         //Roo.log(nodeName);
15346         
15347         switch(nodeName.toLowerCase()) {
15348             case 'th':
15349                 switch(className) {
15350                     case 'switch':
15351                         this.showMode(1);
15352                         break;
15353                     case 'prev':
15354                     case 'next':
15355                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15356                         switch(this.viewMode){
15357                                 case 0:
15358                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15359                                         break;
15360                                 case 1:
15361                                 case 2:
15362                                         this.viewDate = this.moveYear(this.viewDate, dir);
15363                                         break;
15364                         }
15365                         this.fill();
15366                         break;
15367                     case 'today':
15368                         var date = new Date();
15369                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15370 //                        this.fill()
15371                         this.setValue(this.formatDate(this.date));
15372                         
15373                         this.hide();
15374                         break;
15375                 }
15376                 break;
15377             case 'span':
15378                 if (className.indexOf('disabled') < 0) {
15379                     this.viewDate.setUTCDate(1);
15380                     if (className.indexOf('month') > -1) {
15381                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15382                     } else {
15383                         var year = parseInt(html, 10) || 0;
15384                         this.viewDate.setUTCFullYear(year);
15385                         
15386                     }
15387                     
15388                     if(this.singleMode){
15389                         this.setValue(this.formatDate(this.viewDate));
15390                         this.hide();
15391                         return;
15392                     }
15393                     
15394                     this.showMode(-1);
15395                     this.fill();
15396                 }
15397                 break;
15398                 
15399             case 'td':
15400                 //Roo.log(className);
15401                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15402                     var day = parseInt(html, 10) || 1;
15403                     var year = this.viewDate.getUTCFullYear(),
15404                         month = this.viewDate.getUTCMonth();
15405
15406                     if (className.indexOf('old') > -1) {
15407                         if(month === 0 ){
15408                             month = 11;
15409                             year -= 1;
15410                         }else{
15411                             month -= 1;
15412                         }
15413                     } else if (className.indexOf('new') > -1) {
15414                         if (month == 11) {
15415                             month = 0;
15416                             year += 1;
15417                         } else {
15418                             month += 1;
15419                         }
15420                     }
15421                     //Roo.log([year,month,day]);
15422                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15423                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15424 //                    this.fill();
15425                     //Roo.log(this.formatDate(this.date));
15426                     this.setValue(this.formatDate(this.date));
15427                     this.hide();
15428                 }
15429                 break;
15430         }
15431     },
15432     
15433     setStartDate: function(startDate)
15434     {
15435         this.startDate = startDate || -Infinity;
15436         if (this.startDate !== -Infinity) {
15437             this.startDate = this.parseDate(this.startDate);
15438         }
15439         this.update();
15440         this.updateNavArrows();
15441     },
15442
15443     setEndDate: function(endDate)
15444     {
15445         this.endDate = endDate || Infinity;
15446         if (this.endDate !== Infinity) {
15447             this.endDate = this.parseDate(this.endDate);
15448         }
15449         this.update();
15450         this.updateNavArrows();
15451     },
15452     
15453     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15454     {
15455         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15456         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15457             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15458         }
15459         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15460             return parseInt(d, 10);
15461         });
15462         this.update();
15463         this.updateNavArrows();
15464     },
15465     
15466     updateNavArrows: function() 
15467     {
15468         if(this.singleMode){
15469             return;
15470         }
15471         
15472         var d = new Date(this.viewDate),
15473         year = d.getUTCFullYear(),
15474         month = d.getUTCMonth();
15475         
15476         Roo.each(this.picker().select('.prev', true).elements, function(v){
15477             v.show();
15478             switch (this.viewMode) {
15479                 case 0:
15480
15481                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15482                         v.hide();
15483                     }
15484                     break;
15485                 case 1:
15486                 case 2:
15487                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15488                         v.hide();
15489                     }
15490                     break;
15491             }
15492         });
15493         
15494         Roo.each(this.picker().select('.next', true).elements, function(v){
15495             v.show();
15496             switch (this.viewMode) {
15497                 case 0:
15498
15499                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15500                         v.hide();
15501                     }
15502                     break;
15503                 case 1:
15504                 case 2:
15505                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15506                         v.hide();
15507                     }
15508                     break;
15509             }
15510         })
15511     },
15512     
15513     moveMonth: function(date, dir)
15514     {
15515         if (!dir) return date;
15516         var new_date = new Date(date.valueOf()),
15517         day = new_date.getUTCDate(),
15518         month = new_date.getUTCMonth(),
15519         mag = Math.abs(dir),
15520         new_month, test;
15521         dir = dir > 0 ? 1 : -1;
15522         if (mag == 1){
15523             test = dir == -1
15524             // If going back one month, make sure month is not current month
15525             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15526             ? function(){
15527                 return new_date.getUTCMonth() == month;
15528             }
15529             // If going forward one month, make sure month is as expected
15530             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15531             : function(){
15532                 return new_date.getUTCMonth() != new_month;
15533             };
15534             new_month = month + dir;
15535             new_date.setUTCMonth(new_month);
15536             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15537             if (new_month < 0 || new_month > 11)
15538                 new_month = (new_month + 12) % 12;
15539         } else {
15540             // For magnitudes >1, move one month at a time...
15541             for (var i=0; i<mag; i++)
15542                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15543                 new_date = this.moveMonth(new_date, dir);
15544             // ...then reset the day, keeping it in the new month
15545             new_month = new_date.getUTCMonth();
15546             new_date.setUTCDate(day);
15547             test = function(){
15548                 return new_month != new_date.getUTCMonth();
15549             };
15550         }
15551         // Common date-resetting loop -- if date is beyond end of month, make it
15552         // end of month
15553         while (test()){
15554             new_date.setUTCDate(--day);
15555             new_date.setUTCMonth(new_month);
15556         }
15557         return new_date;
15558     },
15559
15560     moveYear: function(date, dir)
15561     {
15562         return this.moveMonth(date, dir*12);
15563     },
15564
15565     dateWithinRange: function(date)
15566     {
15567         return date >= this.startDate && date <= this.endDate;
15568     },
15569
15570     
15571     remove: function() 
15572     {
15573         this.picker().remove();
15574     }
15575    
15576 });
15577
15578 Roo.apply(Roo.bootstrap.DateField,  {
15579     
15580     head : {
15581         tag: 'thead',
15582         cn: [
15583         {
15584             tag: 'tr',
15585             cn: [
15586             {
15587                 tag: 'th',
15588                 cls: 'prev',
15589                 html: '<i class="fa fa-arrow-left"/>'
15590             },
15591             {
15592                 tag: 'th',
15593                 cls: 'switch',
15594                 colspan: '5'
15595             },
15596             {
15597                 tag: 'th',
15598                 cls: 'next',
15599                 html: '<i class="fa fa-arrow-right"/>'
15600             }
15601
15602             ]
15603         }
15604         ]
15605     },
15606     
15607     content : {
15608         tag: 'tbody',
15609         cn: [
15610         {
15611             tag: 'tr',
15612             cn: [
15613             {
15614                 tag: 'td',
15615                 colspan: '7'
15616             }
15617             ]
15618         }
15619         ]
15620     },
15621     
15622     footer : {
15623         tag: 'tfoot',
15624         cn: [
15625         {
15626             tag: 'tr',
15627             cn: [
15628             {
15629                 tag: 'th',
15630                 colspan: '7',
15631                 cls: 'today'
15632             }
15633                     
15634             ]
15635         }
15636         ]
15637     },
15638     
15639     dates:{
15640         en: {
15641             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15642             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15643             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15644             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15645             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15646             today: "Today"
15647         }
15648     },
15649     
15650     modes: [
15651     {
15652         clsName: 'days',
15653         navFnc: 'Month',
15654         navStep: 1
15655     },
15656     {
15657         clsName: 'months',
15658         navFnc: 'FullYear',
15659         navStep: 1
15660     },
15661     {
15662         clsName: 'years',
15663         navFnc: 'FullYear',
15664         navStep: 10
15665     }]
15666 });
15667
15668 Roo.apply(Roo.bootstrap.DateField,  {
15669   
15670     template : {
15671         tag: 'div',
15672         cls: 'datepicker dropdown-menu roo-dynamic',
15673         cn: [
15674         {
15675             tag: 'div',
15676             cls: 'datepicker-days',
15677             cn: [
15678             {
15679                 tag: 'table',
15680                 cls: 'table-condensed',
15681                 cn:[
15682                 Roo.bootstrap.DateField.head,
15683                 {
15684                     tag: 'tbody'
15685                 },
15686                 Roo.bootstrap.DateField.footer
15687                 ]
15688             }
15689             ]
15690         },
15691         {
15692             tag: 'div',
15693             cls: 'datepicker-months',
15694             cn: [
15695             {
15696                 tag: 'table',
15697                 cls: 'table-condensed',
15698                 cn:[
15699                 Roo.bootstrap.DateField.head,
15700                 Roo.bootstrap.DateField.content,
15701                 Roo.bootstrap.DateField.footer
15702                 ]
15703             }
15704             ]
15705         },
15706         {
15707             tag: 'div',
15708             cls: 'datepicker-years',
15709             cn: [
15710             {
15711                 tag: 'table',
15712                 cls: 'table-condensed',
15713                 cn:[
15714                 Roo.bootstrap.DateField.head,
15715                 Roo.bootstrap.DateField.content,
15716                 Roo.bootstrap.DateField.footer
15717                 ]
15718             }
15719             ]
15720         }
15721         ]
15722     }
15723 });
15724
15725  
15726
15727  /*
15728  * - LGPL
15729  *
15730  * TimeField
15731  * 
15732  */
15733
15734 /**
15735  * @class Roo.bootstrap.TimeField
15736  * @extends Roo.bootstrap.Input
15737  * Bootstrap DateField class
15738  * 
15739  * 
15740  * @constructor
15741  * Create a new TimeField
15742  * @param {Object} config The config object
15743  */
15744
15745 Roo.bootstrap.TimeField = function(config){
15746     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15747     this.addEvents({
15748             /**
15749              * @event show
15750              * Fires when this field show.
15751              * @param {Roo.bootstrap.DateField} thisthis
15752              * @param {Mixed} date The date value
15753              */
15754             show : true,
15755             /**
15756              * @event show
15757              * Fires when this field hide.
15758              * @param {Roo.bootstrap.DateField} this
15759              * @param {Mixed} date The date value
15760              */
15761             hide : true,
15762             /**
15763              * @event select
15764              * Fires when select a date.
15765              * @param {Roo.bootstrap.DateField} this
15766              * @param {Mixed} date The date value
15767              */
15768             select : true
15769         });
15770 };
15771
15772 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15773     
15774     /**
15775      * @cfg {String} format
15776      * The default time format string which can be overriden for localization support.  The format must be
15777      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15778      */
15779     format : "H:i",
15780        
15781     onRender: function(ct, position)
15782     {
15783         
15784         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15785                 
15786         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15787         
15788         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15789         
15790         this.pop = this.picker().select('>.datepicker-time',true).first();
15791         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15792         
15793         this.picker().on('mousedown', this.onMousedown, this);
15794         this.picker().on('click', this.onClick, this);
15795         
15796         this.picker().addClass('datepicker-dropdown');
15797     
15798         this.fillTime();
15799         this.update();
15800             
15801         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15802         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15803         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15804         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15805         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15806         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15807
15808     },
15809     
15810     fireKey: function(e){
15811         if (!this.picker().isVisible()){
15812             if (e.keyCode == 27) { // allow escape to hide and re-show picker
15813                 this.show();
15814             }
15815             return;
15816         }
15817
15818         e.preventDefault();
15819         
15820         switch(e.keyCode){
15821             case 27: // escape
15822                 this.hide();
15823                 break;
15824             case 37: // left
15825             case 39: // right
15826                 this.onTogglePeriod();
15827                 break;
15828             case 38: // up
15829                 this.onIncrementMinutes();
15830                 break;
15831             case 40: // down
15832                 this.onDecrementMinutes();
15833                 break;
15834             case 13: // enter
15835             case 9: // tab
15836                 this.setTime();
15837                 break;
15838         }
15839     },
15840     
15841     onClick: function(e) {
15842         e.stopPropagation();
15843         e.preventDefault();
15844     },
15845     
15846     picker : function()
15847     {
15848         return this.el.select('.datepicker', true).first();
15849     },
15850     
15851     fillTime: function()
15852     {    
15853         var time = this.pop.select('tbody', true).first();
15854         
15855         time.dom.innerHTML = '';
15856         
15857         time.createChild({
15858             tag: 'tr',
15859             cn: [
15860                 {
15861                     tag: 'td',
15862                     cn: [
15863                         {
15864                             tag: 'a',
15865                             href: '#',
15866                             cls: 'btn',
15867                             cn: [
15868                                 {
15869                                     tag: 'span',
15870                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15871                                 }
15872                             ]
15873                         } 
15874                     ]
15875                 },
15876                 {
15877                     tag: 'td',
15878                     cls: 'separator'
15879                 },
15880                 {
15881                     tag: 'td',
15882                     cn: [
15883                         {
15884                             tag: 'a',
15885                             href: '#',
15886                             cls: 'btn',
15887                             cn: [
15888                                 {
15889                                     tag: 'span',
15890                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15891                                 }
15892                             ]
15893                         }
15894                     ]
15895                 },
15896                 {
15897                     tag: 'td',
15898                     cls: 'separator'
15899                 }
15900             ]
15901         });
15902         
15903         time.createChild({
15904             tag: 'tr',
15905             cn: [
15906                 {
15907                     tag: 'td',
15908                     cn: [
15909                         {
15910                             tag: 'span',
15911                             cls: 'timepicker-hour',
15912                             html: '00'
15913                         }  
15914                     ]
15915                 },
15916                 {
15917                     tag: 'td',
15918                     cls: 'separator',
15919                     html: ':'
15920                 },
15921                 {
15922                     tag: 'td',
15923                     cn: [
15924                         {
15925                             tag: 'span',
15926                             cls: 'timepicker-minute',
15927                             html: '00'
15928                         }  
15929                     ]
15930                 },
15931                 {
15932                     tag: 'td',
15933                     cls: 'separator'
15934                 },
15935                 {
15936                     tag: 'td',
15937                     cn: [
15938                         {
15939                             tag: 'button',
15940                             type: 'button',
15941                             cls: 'btn btn-primary period',
15942                             html: 'AM'
15943                             
15944                         }
15945                     ]
15946                 }
15947             ]
15948         });
15949         
15950         time.createChild({
15951             tag: 'tr',
15952             cn: [
15953                 {
15954                     tag: 'td',
15955                     cn: [
15956                         {
15957                             tag: 'a',
15958                             href: '#',
15959                             cls: 'btn',
15960                             cn: [
15961                                 {
15962                                     tag: 'span',
15963                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
15964                                 }
15965                             ]
15966                         }
15967                     ]
15968                 },
15969                 {
15970                     tag: 'td',
15971                     cls: 'separator'
15972                 },
15973                 {
15974                     tag: 'td',
15975                     cn: [
15976                         {
15977                             tag: 'a',
15978                             href: '#',
15979                             cls: 'btn',
15980                             cn: [
15981                                 {
15982                                     tag: 'span',
15983                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
15984                                 }
15985                             ]
15986                         }
15987                     ]
15988                 },
15989                 {
15990                     tag: 'td',
15991                     cls: 'separator'
15992                 }
15993             ]
15994         });
15995         
15996     },
15997     
15998     update: function()
15999     {
16000         
16001         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16002         
16003         this.fill();
16004     },
16005     
16006     fill: function() 
16007     {
16008         var hours = this.time.getHours();
16009         var minutes = this.time.getMinutes();
16010         var period = 'AM';
16011         
16012         if(hours > 11){
16013             period = 'PM';
16014         }
16015         
16016         if(hours == 0){
16017             hours = 12;
16018         }
16019         
16020         
16021         if(hours > 12){
16022             hours = hours - 12;
16023         }
16024         
16025         if(hours < 10){
16026             hours = '0' + hours;
16027         }
16028         
16029         if(minutes < 10){
16030             minutes = '0' + minutes;
16031         }
16032         
16033         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16034         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16035         this.pop.select('button', true).first().dom.innerHTML = period;
16036         
16037     },
16038     
16039     place: function()
16040     {   
16041         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16042         
16043         var cls = ['bottom'];
16044         
16045         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16046             cls.pop();
16047             cls.push('top');
16048         }
16049         
16050         cls.push('right');
16051         
16052         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16053             cls.pop();
16054             cls.push('left');
16055         }
16056         
16057         this.picker().addClass(cls.join('-'));
16058         
16059         var _this = this;
16060         
16061         Roo.each(cls, function(c){
16062             if(c == 'bottom'){
16063                 _this.picker().setTop(_this.inputEl().getHeight());
16064                 return;
16065             }
16066             if(c == 'top'){
16067                 _this.picker().setTop(0 - _this.picker().getHeight());
16068                 return;
16069             }
16070             
16071             if(c == 'left'){
16072                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16073                 return;
16074             }
16075             if(c == 'right'){
16076                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16077                 return;
16078             }
16079         });
16080         
16081     },
16082   
16083     onFocus : function()
16084     {
16085         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16086         this.show();
16087     },
16088     
16089     onBlur : function()
16090     {
16091         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16092         this.hide();
16093     },
16094     
16095     show : function()
16096     {
16097         this.picker().show();
16098         this.pop.show();
16099         this.update();
16100         this.place();
16101         
16102         this.fireEvent('show', this, this.date);
16103     },
16104     
16105     hide : function()
16106     {
16107         this.picker().hide();
16108         this.pop.hide();
16109         
16110         this.fireEvent('hide', this, this.date);
16111     },
16112     
16113     setTime : function()
16114     {
16115         this.hide();
16116         this.setValue(this.time.format(this.format));
16117         
16118         this.fireEvent('select', this, this.date);
16119         
16120         
16121     },
16122     
16123     onMousedown: function(e){
16124         e.stopPropagation();
16125         e.preventDefault();
16126     },
16127     
16128     onIncrementHours: function()
16129     {
16130         Roo.log('onIncrementHours');
16131         this.time = this.time.add(Date.HOUR, 1);
16132         this.update();
16133         
16134     },
16135     
16136     onDecrementHours: function()
16137     {
16138         Roo.log('onDecrementHours');
16139         this.time = this.time.add(Date.HOUR, -1);
16140         this.update();
16141     },
16142     
16143     onIncrementMinutes: function()
16144     {
16145         Roo.log('onIncrementMinutes');
16146         this.time = this.time.add(Date.MINUTE, 1);
16147         this.update();
16148     },
16149     
16150     onDecrementMinutes: function()
16151     {
16152         Roo.log('onDecrementMinutes');
16153         this.time = this.time.add(Date.MINUTE, -1);
16154         this.update();
16155     },
16156     
16157     onTogglePeriod: function()
16158     {
16159         Roo.log('onTogglePeriod');
16160         this.time = this.time.add(Date.HOUR, 12);
16161         this.update();
16162     }
16163     
16164    
16165 });
16166
16167 Roo.apply(Roo.bootstrap.TimeField,  {
16168     
16169     content : {
16170         tag: 'tbody',
16171         cn: [
16172             {
16173                 tag: 'tr',
16174                 cn: [
16175                 {
16176                     tag: 'td',
16177                     colspan: '7'
16178                 }
16179                 ]
16180             }
16181         ]
16182     },
16183     
16184     footer : {
16185         tag: 'tfoot',
16186         cn: [
16187             {
16188                 tag: 'tr',
16189                 cn: [
16190                 {
16191                     tag: 'th',
16192                     colspan: '7',
16193                     cls: '',
16194                     cn: [
16195                         {
16196                             tag: 'button',
16197                             cls: 'btn btn-info ok',
16198                             html: 'OK'
16199                         }
16200                     ]
16201                 }
16202
16203                 ]
16204             }
16205         ]
16206     }
16207 });
16208
16209 Roo.apply(Roo.bootstrap.TimeField,  {
16210   
16211     template : {
16212         tag: 'div',
16213         cls: 'datepicker dropdown-menu',
16214         cn: [
16215             {
16216                 tag: 'div',
16217                 cls: 'datepicker-time',
16218                 cn: [
16219                 {
16220                     tag: 'table',
16221                     cls: 'table-condensed',
16222                     cn:[
16223                     Roo.bootstrap.TimeField.content,
16224                     Roo.bootstrap.TimeField.footer
16225                     ]
16226                 }
16227                 ]
16228             }
16229         ]
16230     }
16231 });
16232
16233  
16234
16235  /*
16236  * - LGPL
16237  *
16238  * MonthField
16239  * 
16240  */
16241
16242 /**
16243  * @class Roo.bootstrap.MonthField
16244  * @extends Roo.bootstrap.Input
16245  * Bootstrap MonthField class
16246  * 
16247  * @cfg {String} language default en
16248  * 
16249  * @constructor
16250  * Create a new MonthField
16251  * @param {Object} config The config object
16252  */
16253
16254 Roo.bootstrap.MonthField = function(config){
16255     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16256     
16257     this.addEvents({
16258         /**
16259          * @event show
16260          * Fires when this field show.
16261          * @param {Roo.bootstrap.MonthField} this
16262          * @param {Mixed} date The date value
16263          */
16264         show : true,
16265         /**
16266          * @event show
16267          * Fires when this field hide.
16268          * @param {Roo.bootstrap.MonthField} this
16269          * @param {Mixed} date The date value
16270          */
16271         hide : true,
16272         /**
16273          * @event select
16274          * Fires when select a date.
16275          * @param {Roo.bootstrap.MonthField} this
16276          * @param {Mixed} date The date value
16277          */
16278         select : true
16279     });
16280 };
16281
16282 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16283     
16284     onRender: function(ct, position)
16285     {
16286         
16287         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16288         
16289         this.language = this.language || 'en';
16290         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16291         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16292         
16293         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16294         this.isInline = false;
16295         this.isInput = true;
16296         this.component = this.el.select('.add-on', true).first() || false;
16297         this.component = (this.component && this.component.length === 0) ? false : this.component;
16298         this.hasInput = this.component && this.inputEL().length;
16299         
16300         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16301         
16302         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16303         
16304         this.picker().on('mousedown', this.onMousedown, this);
16305         this.picker().on('click', this.onClick, this);
16306         
16307         this.picker().addClass('datepicker-dropdown');
16308         
16309         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16310             v.setStyle('width', '189px');
16311         });
16312         
16313         this.fillMonths();
16314         
16315         this.update();
16316         
16317         if(this.isInline) {
16318             this.show();
16319         }
16320         
16321     },
16322     
16323     setValue: function(v)
16324     {   
16325         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16326         
16327         this.update();
16328
16329         this.fireEvent('select', this, this.date);
16330         
16331     },
16332     
16333     getValue: function()
16334     {
16335         return this.value;
16336     },
16337     
16338     onClick: function(e) 
16339     {
16340         e.stopPropagation();
16341         e.preventDefault();
16342         
16343         var target = e.getTarget();
16344         
16345         if(target.nodeName.toLowerCase() === 'i'){
16346             target = Roo.get(target).dom.parentNode;
16347         }
16348         
16349         var nodeName = target.nodeName;
16350         var className = target.className;
16351         var html = target.innerHTML;
16352         
16353         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16354             return;
16355         }
16356         
16357         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16358         
16359         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16360         
16361         this.hide();
16362                         
16363     },
16364     
16365     picker : function()
16366     {
16367         return this.pickerEl;
16368     },
16369     
16370     fillMonths: function()
16371     {    
16372         var i = 0;
16373         var months = this.picker().select('>.datepicker-months td', true).first();
16374         
16375         months.dom.innerHTML = '';
16376         
16377         while (i < 12) {
16378             var month = {
16379                 tag: 'span',
16380                 cls: 'month',
16381                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16382             }
16383             
16384             months.createChild(month);
16385         }
16386         
16387     },
16388     
16389     update: function()
16390     {
16391         var _this = this;
16392         
16393         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16394             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16395         }
16396         
16397         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16398             e.removeClass('active');
16399             
16400             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16401                 e.addClass('active');
16402             }
16403         })
16404     },
16405     
16406     place: function()
16407     {
16408         if(this.isInline) return;
16409         
16410         this.picker().removeClass(['bottom', 'top']);
16411         
16412         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16413             /*
16414              * place to the top of element!
16415              *
16416              */
16417             
16418             this.picker().addClass('top');
16419             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16420             
16421             return;
16422         }
16423         
16424         this.picker().addClass('bottom');
16425         
16426         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16427     },
16428     
16429     onFocus : function()
16430     {
16431         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16432         this.show();
16433     },
16434     
16435     onBlur : function()
16436     {
16437         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16438         
16439         var d = this.inputEl().getValue();
16440         
16441         this.setValue(d);
16442                 
16443         this.hide();
16444     },
16445     
16446     show : function()
16447     {
16448         this.picker().show();
16449         this.picker().select('>.datepicker-months', true).first().show();
16450         this.update();
16451         this.place();
16452         
16453         this.fireEvent('show', this, this.date);
16454     },
16455     
16456     hide : function()
16457     {
16458         if(this.isInline) return;
16459         this.picker().hide();
16460         this.fireEvent('hide', this, this.date);
16461         
16462     },
16463     
16464     onMousedown: function(e)
16465     {
16466         e.stopPropagation();
16467         e.preventDefault();
16468     },
16469     
16470     keyup: function(e)
16471     {
16472         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16473         this.update();
16474     },
16475
16476     fireKey: function(e)
16477     {
16478         if (!this.picker().isVisible()){
16479             if (e.keyCode == 27) // allow escape to hide and re-show picker
16480                 this.show();
16481             return;
16482         }
16483         
16484         var dir;
16485         
16486         switch(e.keyCode){
16487             case 27: // escape
16488                 this.hide();
16489                 e.preventDefault();
16490                 break;
16491             case 37: // left
16492             case 39: // right
16493                 dir = e.keyCode == 37 ? -1 : 1;
16494                 
16495                 this.vIndex = this.vIndex + dir;
16496                 
16497                 if(this.vIndex < 0){
16498                     this.vIndex = 0;
16499                 }
16500                 
16501                 if(this.vIndex > 11){
16502                     this.vIndex = 11;
16503                 }
16504                 
16505                 if(isNaN(this.vIndex)){
16506                     this.vIndex = 0;
16507                 }
16508                 
16509                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16510                 
16511                 break;
16512             case 38: // up
16513             case 40: // down
16514                 
16515                 dir = e.keyCode == 38 ? -1 : 1;
16516                 
16517                 this.vIndex = this.vIndex + dir * 4;
16518                 
16519                 if(this.vIndex < 0){
16520                     this.vIndex = 0;
16521                 }
16522                 
16523                 if(this.vIndex > 11){
16524                     this.vIndex = 11;
16525                 }
16526                 
16527                 if(isNaN(this.vIndex)){
16528                     this.vIndex = 0;
16529                 }
16530                 
16531                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16532                 break;
16533                 
16534             case 13: // enter
16535                 
16536                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16537                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16538                 }
16539                 
16540                 this.hide();
16541                 e.preventDefault();
16542                 break;
16543             case 9: // tab
16544                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16545                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16546                 }
16547                 this.hide();
16548                 break;
16549             case 16: // shift
16550             case 17: // ctrl
16551             case 18: // alt
16552                 break;
16553             default :
16554                 this.hide();
16555                 
16556         }
16557     },
16558     
16559     remove: function() 
16560     {
16561         this.picker().remove();
16562     }
16563    
16564 });
16565
16566 Roo.apply(Roo.bootstrap.MonthField,  {
16567     
16568     content : {
16569         tag: 'tbody',
16570         cn: [
16571         {
16572             tag: 'tr',
16573             cn: [
16574             {
16575                 tag: 'td',
16576                 colspan: '7'
16577             }
16578             ]
16579         }
16580         ]
16581     },
16582     
16583     dates:{
16584         en: {
16585             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16586             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16587         }
16588     }
16589 });
16590
16591 Roo.apply(Roo.bootstrap.MonthField,  {
16592   
16593     template : {
16594         tag: 'div',
16595         cls: 'datepicker dropdown-menu roo-dynamic',
16596         cn: [
16597             {
16598                 tag: 'div',
16599                 cls: 'datepicker-months',
16600                 cn: [
16601                 {
16602                     tag: 'table',
16603                     cls: 'table-condensed',
16604                     cn:[
16605                         Roo.bootstrap.DateField.content
16606                     ]
16607                 }
16608                 ]
16609             }
16610         ]
16611     }
16612 });
16613
16614  
16615
16616  
16617  /*
16618  * - LGPL
16619  *
16620  * CheckBox
16621  * 
16622  */
16623
16624 /**
16625  * @class Roo.bootstrap.CheckBox
16626  * @extends Roo.bootstrap.Input
16627  * Bootstrap CheckBox class
16628  * 
16629  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16630  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16631  * @cfg {String} boxLabel The text that appears beside the checkbox
16632  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16633  * @cfg {Boolean} checked initnal the element
16634  * @cfg {Boolean} inline inline the element (default false)
16635  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16636  * 
16637  * @constructor
16638  * Create a new CheckBox
16639  * @param {Object} config The config object
16640  */
16641
16642 Roo.bootstrap.CheckBox = function(config){
16643     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16644    
16645     this.addEvents({
16646         /**
16647         * @event check
16648         * Fires when the element is checked or unchecked.
16649         * @param {Roo.bootstrap.CheckBox} this This input
16650         * @param {Boolean} checked The new checked value
16651         */
16652        check : true
16653     });
16654     
16655 };
16656
16657 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16658   
16659     inputType: 'checkbox',
16660     inputValue: 1,
16661     valueOff: 0,
16662     boxLabel: false,
16663     checked: false,
16664     weight : false,
16665     inline: false,
16666     
16667     getAutoCreate : function()
16668     {
16669         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16670         
16671         var id = Roo.id();
16672         
16673         var cfg = {};
16674         
16675         cfg.cls = 'form-group ' + this.inputType; //input-group
16676         
16677         if(this.inline){
16678             cfg.cls += ' ' + this.inputType + '-inline';
16679         }
16680         
16681         var input =  {
16682             tag: 'input',
16683             id : id,
16684             type : this.inputType,
16685             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16686             cls : 'roo-' + this.inputType, //'form-box',
16687             placeholder : this.placeholder || ''
16688             
16689         };
16690         
16691         if (this.weight) { // Validity check?
16692             cfg.cls += " " + this.inputType + "-" + this.weight;
16693         }
16694         
16695         if (this.disabled) {
16696             input.disabled=true;
16697         }
16698         
16699         if(this.checked){
16700             input.checked = this.checked;
16701         }
16702         
16703         if (this.name) {
16704             input.name = this.name;
16705         }
16706         
16707         if (this.size) {
16708             input.cls += ' input-' + this.size;
16709         }
16710         
16711         var settings=this;
16712         
16713         ['xs','sm','md','lg'].map(function(size){
16714             if (settings[size]) {
16715                 cfg.cls += ' col-' + size + '-' + settings[size];
16716             }
16717         });
16718         
16719         var inputblock = input;
16720          
16721         if (this.before || this.after) {
16722             
16723             inputblock = {
16724                 cls : 'input-group',
16725                 cn :  [] 
16726             };
16727             
16728             if (this.before) {
16729                 inputblock.cn.push({
16730                     tag :'span',
16731                     cls : 'input-group-addon',
16732                     html : this.before
16733                 });
16734             }
16735             
16736             inputblock.cn.push(input);
16737             
16738             if (this.after) {
16739                 inputblock.cn.push({
16740                     tag :'span',
16741                     cls : 'input-group-addon',
16742                     html : this.after
16743                 });
16744             }
16745             
16746         }
16747         
16748         if (align ==='left' && this.fieldLabel.length) {
16749                 Roo.log("left and has label");
16750                 cfg.cn = [
16751                     
16752                     {
16753                         tag: 'label',
16754                         'for' :  id,
16755                         cls : 'control-label col-md-' + this.labelWidth,
16756                         html : this.fieldLabel
16757                         
16758                     },
16759                     {
16760                         cls : "col-md-" + (12 - this.labelWidth), 
16761                         cn: [
16762                             inputblock
16763                         ]
16764                     }
16765                     
16766                 ];
16767         } else if ( this.fieldLabel.length) {
16768                 Roo.log(" label");
16769                 cfg.cn = [
16770                    
16771                     {
16772                         tag: this.boxLabel ? 'span' : 'label',
16773                         'for': id,
16774                         cls: 'control-label box-input-label',
16775                         //cls : 'input-group-addon',
16776                         html : this.fieldLabel
16777                         
16778                     },
16779                     
16780                     inputblock
16781                     
16782                 ];
16783
16784         } else {
16785             
16786                 Roo.log(" no label && no align");
16787                 cfg.cn = [  inputblock ] ;
16788                 
16789                 
16790         }
16791         if(this.boxLabel){
16792              var boxLabelCfg = {
16793                 tag: 'label',
16794                 //'for': id, // box label is handled by onclick - so no for...
16795                 cls: 'box-label',
16796                 html: this.boxLabel
16797             }
16798             
16799             if(this.tooltip){
16800                 boxLabelCfg.tooltip = this.tooltip;
16801             }
16802              
16803             cfg.cn.push(boxLabelCfg);
16804         }
16805         
16806         
16807        
16808         return cfg;
16809         
16810     },
16811     
16812     /**
16813      * return the real input element.
16814      */
16815     inputEl: function ()
16816     {
16817         return this.el.select('input.roo-' + this.inputType,true).first();
16818     },
16819     
16820     labelEl: function()
16821     {
16822         return this.el.select('label.control-label',true).first();
16823     },
16824     /* depricated... */
16825     
16826     label: function()
16827     {
16828         return this.labelEl();
16829     },
16830     
16831     initEvents : function()
16832     {
16833 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16834         
16835         this.inputEl().on('click', this.onClick,  this);
16836         
16837         if (this.boxLabel) { 
16838             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
16839         }
16840         
16841         this.startValue = this.getValue();
16842         
16843         if(this.groupId){
16844             Roo.bootstrap.CheckBox.register(this);
16845         }
16846     },
16847     
16848     onClick : function()
16849     {   
16850         this.setChecked(!this.checked);
16851     },
16852     
16853     setChecked : function(state,suppressEvent)
16854     {
16855         this.startValue = this.getValue();
16856         
16857         if(this.inputType == 'radio'){
16858             
16859             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16860                 e.dom.checked = false;
16861             });
16862             
16863             this.inputEl().dom.checked = true;
16864             
16865             this.inputEl().dom.value = this.inputValue;
16866             
16867             if(suppressEvent !== true){
16868                 this.fireEvent('check', this, true);
16869             }
16870             
16871             this.validate();
16872             
16873             return;
16874         }
16875         
16876         this.checked = state;
16877         
16878         this.inputEl().dom.checked = state;
16879         
16880         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16881         
16882         if(suppressEvent !== true){
16883             this.fireEvent('check', this, state);
16884         }
16885         
16886         this.validate();
16887     },
16888     
16889     getValue : function()
16890     {
16891         if(this.inputType == 'radio'){
16892             return this.getGroupValue();
16893         }
16894         
16895         return this.inputEl().getValue();
16896         
16897     },
16898     
16899     getGroupValue : function()
16900     {
16901         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16902             return '';
16903         }
16904         
16905         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16906     },
16907     
16908     setValue : function(v,suppressEvent)
16909     {
16910         if(this.inputType == 'radio'){
16911             this.setGroupValue(v, suppressEvent);
16912             return;
16913         }
16914         
16915         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16916         
16917         this.validate();
16918     },
16919     
16920     setGroupValue : function(v, suppressEvent)
16921     {
16922         this.startValue = this.getValue();
16923         
16924         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16925             e.dom.checked = false;
16926             
16927             if(e.dom.value == v){
16928                 e.dom.checked = true;
16929             }
16930         });
16931         
16932         if(suppressEvent !== true){
16933             this.fireEvent('check', this, true);
16934         }
16935
16936         this.validate();
16937         
16938         return;
16939     },
16940     
16941     validate : function()
16942     {
16943         if(
16944                 this.disabled || 
16945                 (this.inputType == 'radio' && this.getValue().length) ||
16946                 (this.inputType == 'checkbox' && this.validateGroup())
16947         ){
16948             this.markValid();
16949             return true;
16950         }
16951         
16952         this.markInvalid();
16953         return false;
16954     },
16955     
16956     validateGroup : function()
16957     {
16958         if(!this.groupId){
16959             return (this.getValue() == this.inputValue) ? true : false;
16960         }
16961         
16962         var group = Roo.bootstrap.CheckBox.get(this.groupId);
16963         
16964         if(!group){
16965             return false;
16966         }
16967         
16968         var r = false;
16969         
16970         for(var i in group){
16971             if(r){
16972                 break;
16973             }
16974             
16975             r = (group[i].getValue() == group[i].inputValue) ? true : false;
16976         }
16977         
16978         return r;
16979     },
16980     
16981     /**
16982      * Mark this field as valid
16983      */
16984     markValid : function()
16985     {
16986         var _this = this;
16987         
16988         this.fireEvent('valid', this);
16989         
16990         if(this.inputType == 'radio'){
16991             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16992                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
16993                 e.findParent('.form-group', false, true).addClass(_this.validClass);
16994             });
16995             
16996             return;
16997         }
16998         
16999         if(!this.groupId){
17000             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17001             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17002             return;
17003         }
17004         
17005         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17006             
17007         if(!group){
17008             return;
17009         }
17010         
17011         for(var i in group){
17012             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17013             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17014         }
17015     },
17016     
17017      /**
17018      * Mark this field as invalid
17019      * @param {String} msg The validation message
17020      */
17021     markInvalid : function(msg)
17022     {
17023         var _this = this;
17024         
17025         this.fireEvent('invalid', this, msg);
17026         
17027         if(this.inputType == 'radio'){
17028             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17029                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17030                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17031             });
17032             
17033             return;
17034         }
17035         
17036         if(!this.groupId){
17037             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17038             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17039             return;
17040         }
17041         
17042         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17043             
17044         if(!group){
17045             return;
17046         }
17047         
17048         for(var i in group){
17049             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17050             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17051         }
17052         
17053     }
17054     
17055 });
17056
17057 Roo.apply(Roo.bootstrap.CheckBox, {
17058     
17059     groups: {},
17060     
17061      /**
17062     * register a CheckBox Group
17063     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17064     */
17065     register : function(checkbox)
17066     {
17067         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17068             this.groups[checkbox.groupId] = {};
17069         }
17070         
17071         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17072             return;
17073         }
17074         
17075         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17076         
17077     },
17078     /**
17079     * fetch a CheckBox Group based on the group ID
17080     * @param {string} the group ID
17081     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17082     */
17083     get: function(groupId) {
17084         if (typeof(this.groups[groupId]) == 'undefined') {
17085             return false;
17086         }
17087         
17088         return this.groups[groupId] ;
17089     }
17090     
17091     
17092 });
17093 /*
17094  * - LGPL
17095  *
17096  * Radio
17097  *
17098  *
17099  * not inline
17100  *<div class="radio">
17101   <label>
17102     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17103     Option one is this and that&mdash;be sure to include why it's great
17104   </label>
17105 </div>
17106  *
17107  *
17108  *inline
17109  *<span>
17110  *<label class="radio-inline">fieldLabel</label>
17111  *<label class="radio-inline">
17112   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17113 </label>
17114 <span>
17115  * 
17116  * 
17117  */
17118
17119 /**
17120  * @class Roo.bootstrap.Radio
17121  * @extends Roo.bootstrap.CheckBox
17122  * Bootstrap Radio class
17123
17124  * @constructor
17125  * Create a new Radio
17126  * @param {Object} config The config object
17127  */
17128
17129 Roo.bootstrap.Radio = function(config){
17130     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17131    
17132 };
17133
17134 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17135     
17136     inputType: 'radio',
17137     inputValue: '',
17138     valueOff: '',
17139     
17140     getAutoCreate : function()
17141     {
17142         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17143         align = align || 'left'; // default...
17144         
17145         
17146         
17147         var id = Roo.id();
17148         
17149         var cfg = {
17150                 tag : this.inline ? 'span' : 'div',
17151                 cls : '',
17152                 cn : []
17153         };
17154         
17155         var inline = this.inline ? ' radio-inline' : '';
17156         
17157         var lbl = {
17158                 tag: 'label' ,
17159                 // does not need for, as we wrap the input with it..
17160                 'for' : id,
17161                 cls : 'control-label box-label' + inline,
17162                 cn : []
17163         };
17164         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17165         
17166         var fieldLabel = {
17167             tag: 'label' ,
17168             //cls : 'control-label' + inline,
17169             html : this.fieldLabel,
17170             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17171         };
17172         
17173  
17174         
17175         
17176         var input =  {
17177             tag: 'input',
17178             id : id,
17179             type : this.inputType,
17180             //value : (!this.checked) ? this.valueOff : this.inputValue,
17181             value : this.inputValue,
17182             cls : 'roo-radio',
17183             placeholder : this.placeholder || '' // ?? needed????
17184             
17185         };
17186         if (this.weight) { // Validity check?
17187             input.cls += " radio-" + this.weight;
17188         }
17189         if (this.disabled) {
17190             input.disabled=true;
17191         }
17192         
17193         if(this.checked){
17194             input.checked = this.checked;
17195         }
17196         
17197         if (this.name) {
17198             input.name = this.name;
17199         }
17200         
17201         if (this.size) {
17202             input.cls += ' input-' + this.size;
17203         }
17204         
17205         //?? can span's inline have a width??
17206         
17207         var settings=this;
17208         ['xs','sm','md','lg'].map(function(size){
17209             if (settings[size]) {
17210                 cfg.cls += ' col-' + size + '-' + settings[size];
17211             }
17212         });
17213         
17214         var inputblock = input;
17215         
17216         if (this.before || this.after) {
17217             
17218             inputblock = {
17219                 cls : 'input-group',
17220                 tag : 'span',
17221                 cn :  [] 
17222             };
17223             if (this.before) {
17224                 inputblock.cn.push({
17225                     tag :'span',
17226                     cls : 'input-group-addon',
17227                     html : this.before
17228                 });
17229             }
17230             inputblock.cn.push(input);
17231             if (this.after) {
17232                 inputblock.cn.push({
17233                     tag :'span',
17234                     cls : 'input-group-addon',
17235                     html : this.after
17236                 });
17237             }
17238             
17239         };
17240         
17241         
17242         if (this.fieldLabel && this.fieldLabel.length) {
17243             cfg.cn.push(fieldLabel);
17244         }
17245        
17246         // normal bootstrap puts the input inside the label.
17247         // however with our styled version - it has to go after the input.
17248        
17249         //lbl.cn.push(inputblock);
17250         
17251         var lblwrap =  {
17252             tag: 'span',
17253             cls: 'radio' + inline,
17254             cn: [
17255                 inputblock,
17256                 lbl
17257             ]
17258         };
17259         
17260         cfg.cn.push( lblwrap);
17261         
17262         if(this.boxLabel){
17263             lbl.cn.push({
17264                 tag: 'span',
17265                 html: this.boxLabel
17266             })
17267         }
17268          
17269         
17270         return cfg;
17271         
17272     },
17273     
17274     initEvents : function()
17275     {
17276 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17277         
17278         this.inputEl().on('click', this.onClick,  this);
17279         if (this.boxLabel) {
17280             Roo.log('find label')
17281             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17282         }
17283         
17284     },
17285     
17286     inputEl: function ()
17287     {
17288         return this.el.select('input.roo-radio',true).first();
17289     },
17290     onClick : function()
17291     {   
17292         Roo.log("click");
17293         this.setChecked(true);
17294     },
17295     
17296     setChecked : function(state,suppressEvent)
17297     {
17298         if(state){
17299             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17300                 v.dom.checked = false;
17301             });
17302         }
17303         Roo.log(this.inputEl().dom);
17304         this.checked = state;
17305         this.inputEl().dom.checked = state;
17306         
17307         if(suppressEvent !== true){
17308             this.fireEvent('check', this, state);
17309         }
17310         
17311         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17312         
17313     },
17314     
17315     getGroupValue : function()
17316     {
17317         var value = '';
17318         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17319             if(v.dom.checked == true){
17320                 value = v.dom.value;
17321             }
17322         });
17323         
17324         return value;
17325     },
17326     
17327     /**
17328      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17329      * @return {Mixed} value The field value
17330      */
17331     getValue : function(){
17332         return this.getGroupValue();
17333     }
17334     
17335 });
17336
17337  
17338 //<script type="text/javascript">
17339
17340 /*
17341  * Based  Ext JS Library 1.1.1
17342  * Copyright(c) 2006-2007, Ext JS, LLC.
17343  * LGPL
17344  *
17345  */
17346  
17347 /**
17348  * @class Roo.HtmlEditorCore
17349  * @extends Roo.Component
17350  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17351  *
17352  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17353  */
17354
17355 Roo.HtmlEditorCore = function(config){
17356     
17357     
17358     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17359     
17360     
17361     this.addEvents({
17362         /**
17363          * @event initialize
17364          * Fires when the editor is fully initialized (including the iframe)
17365          * @param {Roo.HtmlEditorCore} this
17366          */
17367         initialize: true,
17368         /**
17369          * @event activate
17370          * Fires when the editor is first receives the focus. Any insertion must wait
17371          * until after this event.
17372          * @param {Roo.HtmlEditorCore} this
17373          */
17374         activate: true,
17375          /**
17376          * @event beforesync
17377          * Fires before the textarea is updated with content from the editor iframe. Return false
17378          * to cancel the sync.
17379          * @param {Roo.HtmlEditorCore} this
17380          * @param {String} html
17381          */
17382         beforesync: true,
17383          /**
17384          * @event beforepush
17385          * Fires before the iframe editor is updated with content from the textarea. Return false
17386          * to cancel the push.
17387          * @param {Roo.HtmlEditorCore} this
17388          * @param {String} html
17389          */
17390         beforepush: true,
17391          /**
17392          * @event sync
17393          * Fires when the textarea is updated with content from the editor iframe.
17394          * @param {Roo.HtmlEditorCore} this
17395          * @param {String} html
17396          */
17397         sync: true,
17398          /**
17399          * @event push
17400          * Fires when the iframe editor is updated with content from the textarea.
17401          * @param {Roo.HtmlEditorCore} this
17402          * @param {String} html
17403          */
17404         push: true,
17405         
17406         /**
17407          * @event editorevent
17408          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17409          * @param {Roo.HtmlEditorCore} this
17410          */
17411         editorevent: true
17412         
17413     });
17414     
17415     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17416     
17417     // defaults : white / black...
17418     this.applyBlacklists();
17419     
17420     
17421     
17422 };
17423
17424
17425 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17426
17427
17428      /**
17429      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17430      */
17431     
17432     owner : false,
17433     
17434      /**
17435      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17436      *                        Roo.resizable.
17437      */
17438     resizable : false,
17439      /**
17440      * @cfg {Number} height (in pixels)
17441      */   
17442     height: 300,
17443    /**
17444      * @cfg {Number} width (in pixels)
17445      */   
17446     width: 500,
17447     
17448     /**
17449      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17450      * 
17451      */
17452     stylesheets: false,
17453     
17454     // id of frame..
17455     frameId: false,
17456     
17457     // private properties
17458     validationEvent : false,
17459     deferHeight: true,
17460     initialized : false,
17461     activated : false,
17462     sourceEditMode : false,
17463     onFocus : Roo.emptyFn,
17464     iframePad:3,
17465     hideMode:'offsets',
17466     
17467     clearUp: true,
17468     
17469     // blacklist + whitelisted elements..
17470     black: false,
17471     white: false,
17472      
17473     
17474
17475     /**
17476      * Protected method that will not generally be called directly. It
17477      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17478      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17479      */
17480     getDocMarkup : function(){
17481         // body styles..
17482         var st = '';
17483         
17484         // inherit styels from page...?? 
17485         if (this.stylesheets === false) {
17486             
17487             Roo.get(document.head).select('style').each(function(node) {
17488                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17489             });
17490             
17491             Roo.get(document.head).select('link').each(function(node) { 
17492                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17493             });
17494             
17495         } else if (!this.stylesheets.length) {
17496                 // simple..
17497                 st = '<style type="text/css">' +
17498                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17499                    '</style>';
17500         } else { 
17501             
17502         }
17503         
17504         st +=  '<style type="text/css">' +
17505             'IMG { cursor: pointer } ' +
17506         '</style>';
17507
17508         
17509         return '<html><head>' + st  +
17510             //<style type="text/css">' +
17511             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17512             //'</style>' +
17513             ' </head><body class="roo-htmleditor-body"></body></html>';
17514     },
17515
17516     // private
17517     onRender : function(ct, position)
17518     {
17519         var _t = this;
17520         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17521         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17522         
17523         
17524         this.el.dom.style.border = '0 none';
17525         this.el.dom.setAttribute('tabIndex', -1);
17526         this.el.addClass('x-hidden hide');
17527         
17528         
17529         
17530         if(Roo.isIE){ // fix IE 1px bogus margin
17531             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17532         }
17533        
17534         
17535         this.frameId = Roo.id();
17536         
17537          
17538         
17539         var iframe = this.owner.wrap.createChild({
17540             tag: 'iframe',
17541             cls: 'form-control', // bootstrap..
17542             id: this.frameId,
17543             name: this.frameId,
17544             frameBorder : 'no',
17545             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17546         }, this.el
17547         );
17548         
17549         
17550         this.iframe = iframe.dom;
17551
17552          this.assignDocWin();
17553         
17554         this.doc.designMode = 'on';
17555        
17556         this.doc.open();
17557         this.doc.write(this.getDocMarkup());
17558         this.doc.close();
17559
17560         
17561         var task = { // must defer to wait for browser to be ready
17562             run : function(){
17563                 //console.log("run task?" + this.doc.readyState);
17564                 this.assignDocWin();
17565                 if(this.doc.body || this.doc.readyState == 'complete'){
17566                     try {
17567                         this.doc.designMode="on";
17568                     } catch (e) {
17569                         return;
17570                     }
17571                     Roo.TaskMgr.stop(task);
17572                     this.initEditor.defer(10, this);
17573                 }
17574             },
17575             interval : 10,
17576             duration: 10000,
17577             scope: this
17578         };
17579         Roo.TaskMgr.start(task);
17580
17581     },
17582
17583     // private
17584     onResize : function(w, h)
17585     {
17586          Roo.log('resize: ' +w + ',' + h );
17587         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17588         if(!this.iframe){
17589             return;
17590         }
17591         if(typeof w == 'number'){
17592             
17593             this.iframe.style.width = w + 'px';
17594         }
17595         if(typeof h == 'number'){
17596             
17597             this.iframe.style.height = h + 'px';
17598             if(this.doc){
17599                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17600             }
17601         }
17602         
17603     },
17604
17605     /**
17606      * Toggles the editor between standard and source edit mode.
17607      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17608      */
17609     toggleSourceEdit : function(sourceEditMode){
17610         
17611         this.sourceEditMode = sourceEditMode === true;
17612         
17613         if(this.sourceEditMode){
17614  
17615             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17616             
17617         }else{
17618             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17619             //this.iframe.className = '';
17620             this.deferFocus();
17621         }
17622         //this.setSize(this.owner.wrap.getSize());
17623         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17624     },
17625
17626     
17627   
17628
17629     /**
17630      * Protected method that will not generally be called directly. If you need/want
17631      * custom HTML cleanup, this is the method you should override.
17632      * @param {String} html The HTML to be cleaned
17633      * return {String} The cleaned HTML
17634      */
17635     cleanHtml : function(html){
17636         html = String(html);
17637         if(html.length > 5){
17638             if(Roo.isSafari){ // strip safari nonsense
17639                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17640             }
17641         }
17642         if(html == '&nbsp;'){
17643             html = '';
17644         }
17645         return html;
17646     },
17647
17648     /**
17649      * HTML Editor -> Textarea
17650      * Protected method that will not generally be called directly. Syncs the contents
17651      * of the editor iframe with the textarea.
17652      */
17653     syncValue : function(){
17654         if(this.initialized){
17655             var bd = (this.doc.body || this.doc.documentElement);
17656             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17657             var html = bd.innerHTML;
17658             if(Roo.isSafari){
17659                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17660                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17661                 if(m && m[1]){
17662                     html = '<div style="'+m[0]+'">' + html + '</div>';
17663                 }
17664             }
17665             html = this.cleanHtml(html);
17666             // fix up the special chars.. normaly like back quotes in word...
17667             // however we do not want to do this with chinese..
17668             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17669                 var cc = b.charCodeAt();
17670                 if (
17671                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17672                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17673                     (cc >= 0xf900 && cc < 0xfb00 )
17674                 ) {
17675                         return b;
17676                 }
17677                 return "&#"+cc+";" 
17678             });
17679             if(this.owner.fireEvent('beforesync', this, html) !== false){
17680                 this.el.dom.value = html;
17681                 this.owner.fireEvent('sync', this, html);
17682             }
17683         }
17684     },
17685
17686     /**
17687      * Protected method that will not generally be called directly. Pushes the value of the textarea
17688      * into the iframe editor.
17689      */
17690     pushValue : function(){
17691         if(this.initialized){
17692             var v = this.el.dom.value.trim();
17693             
17694 //            if(v.length < 1){
17695 //                v = '&#160;';
17696 //            }
17697             
17698             if(this.owner.fireEvent('beforepush', this, v) !== false){
17699                 var d = (this.doc.body || this.doc.documentElement);
17700                 d.innerHTML = v;
17701                 this.cleanUpPaste();
17702                 this.el.dom.value = d.innerHTML;
17703                 this.owner.fireEvent('push', this, v);
17704             }
17705         }
17706     },
17707
17708     // private
17709     deferFocus : function(){
17710         this.focus.defer(10, this);
17711     },
17712
17713     // doc'ed in Field
17714     focus : function(){
17715         if(this.win && !this.sourceEditMode){
17716             this.win.focus();
17717         }else{
17718             this.el.focus();
17719         }
17720     },
17721     
17722     assignDocWin: function()
17723     {
17724         var iframe = this.iframe;
17725         
17726          if(Roo.isIE){
17727             this.doc = iframe.contentWindow.document;
17728             this.win = iframe.contentWindow;
17729         } else {
17730 //            if (!Roo.get(this.frameId)) {
17731 //                return;
17732 //            }
17733 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17734 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17735             
17736             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17737                 return;
17738             }
17739             
17740             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17741             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17742         }
17743     },
17744     
17745     // private
17746     initEditor : function(){
17747         //console.log("INIT EDITOR");
17748         this.assignDocWin();
17749         
17750         
17751         
17752         this.doc.designMode="on";
17753         this.doc.open();
17754         this.doc.write(this.getDocMarkup());
17755         this.doc.close();
17756         
17757         var dbody = (this.doc.body || this.doc.documentElement);
17758         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17759         // this copies styles from the containing element into thsi one..
17760         // not sure why we need all of this..
17761         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17762         
17763         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17764         //ss['background-attachment'] = 'fixed'; // w3c
17765         dbody.bgProperties = 'fixed'; // ie
17766         //Roo.DomHelper.applyStyles(dbody, ss);
17767         Roo.EventManager.on(this.doc, {
17768             //'mousedown': this.onEditorEvent,
17769             'mouseup': this.onEditorEvent,
17770             'dblclick': this.onEditorEvent,
17771             'click': this.onEditorEvent,
17772             'keyup': this.onEditorEvent,
17773             buffer:100,
17774             scope: this
17775         });
17776         if(Roo.isGecko){
17777             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17778         }
17779         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17780             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17781         }
17782         this.initialized = true;
17783
17784         this.owner.fireEvent('initialize', this);
17785         this.pushValue();
17786     },
17787
17788     // private
17789     onDestroy : function(){
17790         
17791         
17792         
17793         if(this.rendered){
17794             
17795             //for (var i =0; i < this.toolbars.length;i++) {
17796             //    // fixme - ask toolbars for heights?
17797             //    this.toolbars[i].onDestroy();
17798            // }
17799             
17800             //this.wrap.dom.innerHTML = '';
17801             //this.wrap.remove();
17802         }
17803     },
17804
17805     // private
17806     onFirstFocus : function(){
17807         
17808         this.assignDocWin();
17809         
17810         
17811         this.activated = true;
17812          
17813     
17814         if(Roo.isGecko){ // prevent silly gecko errors
17815             this.win.focus();
17816             var s = this.win.getSelection();
17817             if(!s.focusNode || s.focusNode.nodeType != 3){
17818                 var r = s.getRangeAt(0);
17819                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17820                 r.collapse(true);
17821                 this.deferFocus();
17822             }
17823             try{
17824                 this.execCmd('useCSS', true);
17825                 this.execCmd('styleWithCSS', false);
17826             }catch(e){}
17827         }
17828         this.owner.fireEvent('activate', this);
17829     },
17830
17831     // private
17832     adjustFont: function(btn){
17833         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17834         //if(Roo.isSafari){ // safari
17835         //    adjust *= 2;
17836        // }
17837         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17838         if(Roo.isSafari){ // safari
17839             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17840             v =  (v < 10) ? 10 : v;
17841             v =  (v > 48) ? 48 : v;
17842             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17843             
17844         }
17845         
17846         
17847         v = Math.max(1, v+adjust);
17848         
17849         this.execCmd('FontSize', v  );
17850     },
17851
17852     onEditorEvent : function(e){
17853         this.owner.fireEvent('editorevent', this, e);
17854       //  this.updateToolbar();
17855         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17856     },
17857
17858     insertTag : function(tg)
17859     {
17860         // could be a bit smarter... -> wrap the current selected tRoo..
17861         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17862             
17863             range = this.createRange(this.getSelection());
17864             var wrappingNode = this.doc.createElement(tg.toLowerCase());
17865             wrappingNode.appendChild(range.extractContents());
17866             range.insertNode(wrappingNode);
17867
17868             return;
17869             
17870             
17871             
17872         }
17873         this.execCmd("formatblock",   tg);
17874         
17875     },
17876     
17877     insertText : function(txt)
17878     {
17879         
17880         
17881         var range = this.createRange();
17882         range.deleteContents();
17883                //alert(Sender.getAttribute('label'));
17884                
17885         range.insertNode(this.doc.createTextNode(txt));
17886     } ,
17887     
17888      
17889
17890     /**
17891      * Executes a Midas editor command on the editor document and performs necessary focus and
17892      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17893      * @param {String} cmd The Midas command
17894      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17895      */
17896     relayCmd : function(cmd, value){
17897         this.win.focus();
17898         this.execCmd(cmd, value);
17899         this.owner.fireEvent('editorevent', this);
17900         //this.updateToolbar();
17901         this.owner.deferFocus();
17902     },
17903
17904     /**
17905      * Executes a Midas editor command directly on the editor document.
17906      * For visual commands, you should use {@link #relayCmd} instead.
17907      * <b>This should only be called after the editor is initialized.</b>
17908      * @param {String} cmd The Midas command
17909      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17910      */
17911     execCmd : function(cmd, value){
17912         this.doc.execCommand(cmd, false, value === undefined ? null : value);
17913         this.syncValue();
17914     },
17915  
17916  
17917    
17918     /**
17919      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17920      * to insert tRoo.
17921      * @param {String} text | dom node.. 
17922      */
17923     insertAtCursor : function(text)
17924     {
17925         
17926         
17927         
17928         if(!this.activated){
17929             return;
17930         }
17931         /*
17932         if(Roo.isIE){
17933             this.win.focus();
17934             var r = this.doc.selection.createRange();
17935             if(r){
17936                 r.collapse(true);
17937                 r.pasteHTML(text);
17938                 this.syncValue();
17939                 this.deferFocus();
17940             
17941             }
17942             return;
17943         }
17944         */
17945         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17946             this.win.focus();
17947             
17948             
17949             // from jquery ui (MIT licenced)
17950             var range, node;
17951             var win = this.win;
17952             
17953             if (win.getSelection && win.getSelection().getRangeAt) {
17954                 range = win.getSelection().getRangeAt(0);
17955                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17956                 range.insertNode(node);
17957             } else if (win.document.selection && win.document.selection.createRange) {
17958                 // no firefox support
17959                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17960                 win.document.selection.createRange().pasteHTML(txt);
17961             } else {
17962                 // no firefox support
17963                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17964                 this.execCmd('InsertHTML', txt);
17965             } 
17966             
17967             this.syncValue();
17968             
17969             this.deferFocus();
17970         }
17971     },
17972  // private
17973     mozKeyPress : function(e){
17974         if(e.ctrlKey){
17975             var c = e.getCharCode(), cmd;
17976           
17977             if(c > 0){
17978                 c = String.fromCharCode(c).toLowerCase();
17979                 switch(c){
17980                     case 'b':
17981                         cmd = 'bold';
17982                         break;
17983                     case 'i':
17984                         cmd = 'italic';
17985                         break;
17986                     
17987                     case 'u':
17988                         cmd = 'underline';
17989                         break;
17990                     
17991                     case 'v':
17992                         this.cleanUpPaste.defer(100, this);
17993                         return;
17994                         
17995                 }
17996                 if(cmd){
17997                     this.win.focus();
17998                     this.execCmd(cmd);
17999                     this.deferFocus();
18000                     e.preventDefault();
18001                 }
18002                 
18003             }
18004         }
18005     },
18006
18007     // private
18008     fixKeys : function(){ // load time branching for fastest keydown performance
18009         if(Roo.isIE){
18010             return function(e){
18011                 var k = e.getKey(), r;
18012                 if(k == e.TAB){
18013                     e.stopEvent();
18014                     r = this.doc.selection.createRange();
18015                     if(r){
18016                         r.collapse(true);
18017                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18018                         this.deferFocus();
18019                     }
18020                     return;
18021                 }
18022                 
18023                 if(k == e.ENTER){
18024                     r = this.doc.selection.createRange();
18025                     if(r){
18026                         var target = r.parentElement();
18027                         if(!target || target.tagName.toLowerCase() != 'li'){
18028                             e.stopEvent();
18029                             r.pasteHTML('<br />');
18030                             r.collapse(false);
18031                             r.select();
18032                         }
18033                     }
18034                 }
18035                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18036                     this.cleanUpPaste.defer(100, this);
18037                     return;
18038                 }
18039                 
18040                 
18041             };
18042         }else if(Roo.isOpera){
18043             return function(e){
18044                 var k = e.getKey();
18045                 if(k == e.TAB){
18046                     e.stopEvent();
18047                     this.win.focus();
18048                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18049                     this.deferFocus();
18050                 }
18051                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18052                     this.cleanUpPaste.defer(100, this);
18053                     return;
18054                 }
18055                 
18056             };
18057         }else if(Roo.isSafari){
18058             return function(e){
18059                 var k = e.getKey();
18060                 
18061                 if(k == e.TAB){
18062                     e.stopEvent();
18063                     this.execCmd('InsertText','\t');
18064                     this.deferFocus();
18065                     return;
18066                 }
18067                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18068                     this.cleanUpPaste.defer(100, this);
18069                     return;
18070                 }
18071                 
18072              };
18073         }
18074     }(),
18075     
18076     getAllAncestors: function()
18077     {
18078         var p = this.getSelectedNode();
18079         var a = [];
18080         if (!p) {
18081             a.push(p); // push blank onto stack..
18082             p = this.getParentElement();
18083         }
18084         
18085         
18086         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18087             a.push(p);
18088             p = p.parentNode;
18089         }
18090         a.push(this.doc.body);
18091         return a;
18092     },
18093     lastSel : false,
18094     lastSelNode : false,
18095     
18096     
18097     getSelection : function() 
18098     {
18099         this.assignDocWin();
18100         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18101     },
18102     
18103     getSelectedNode: function() 
18104     {
18105         // this may only work on Gecko!!!
18106         
18107         // should we cache this!!!!
18108         
18109         
18110         
18111          
18112         var range = this.createRange(this.getSelection()).cloneRange();
18113         
18114         if (Roo.isIE) {
18115             var parent = range.parentElement();
18116             while (true) {
18117                 var testRange = range.duplicate();
18118                 testRange.moveToElementText(parent);
18119                 if (testRange.inRange(range)) {
18120                     break;
18121                 }
18122                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18123                     break;
18124                 }
18125                 parent = parent.parentElement;
18126             }
18127             return parent;
18128         }
18129         
18130         // is ancestor a text element.
18131         var ac =  range.commonAncestorContainer;
18132         if (ac.nodeType == 3) {
18133             ac = ac.parentNode;
18134         }
18135         
18136         var ar = ac.childNodes;
18137          
18138         var nodes = [];
18139         var other_nodes = [];
18140         var has_other_nodes = false;
18141         for (var i=0;i<ar.length;i++) {
18142             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18143                 continue;
18144             }
18145             // fullly contained node.
18146             
18147             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18148                 nodes.push(ar[i]);
18149                 continue;
18150             }
18151             
18152             // probably selected..
18153             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18154                 other_nodes.push(ar[i]);
18155                 continue;
18156             }
18157             // outer..
18158             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18159                 continue;
18160             }
18161             
18162             
18163             has_other_nodes = true;
18164         }
18165         if (!nodes.length && other_nodes.length) {
18166             nodes= other_nodes;
18167         }
18168         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18169             return false;
18170         }
18171         
18172         return nodes[0];
18173     },
18174     createRange: function(sel)
18175     {
18176         // this has strange effects when using with 
18177         // top toolbar - not sure if it's a great idea.
18178         //this.editor.contentWindow.focus();
18179         if (typeof sel != "undefined") {
18180             try {
18181                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18182             } catch(e) {
18183                 return this.doc.createRange();
18184             }
18185         } else {
18186             return this.doc.createRange();
18187         }
18188     },
18189     getParentElement: function()
18190     {
18191         
18192         this.assignDocWin();
18193         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18194         
18195         var range = this.createRange(sel);
18196          
18197         try {
18198             var p = range.commonAncestorContainer;
18199             while (p.nodeType == 3) { // text node
18200                 p = p.parentNode;
18201             }
18202             return p;
18203         } catch (e) {
18204             return null;
18205         }
18206     
18207     },
18208     /***
18209      *
18210      * Range intersection.. the hard stuff...
18211      *  '-1' = before
18212      *  '0' = hits..
18213      *  '1' = after.
18214      *         [ -- selected range --- ]
18215      *   [fail]                        [fail]
18216      *
18217      *    basically..
18218      *      if end is before start or  hits it. fail.
18219      *      if start is after end or hits it fail.
18220      *
18221      *   if either hits (but other is outside. - then it's not 
18222      *   
18223      *    
18224      **/
18225     
18226     
18227     // @see http://www.thismuchiknow.co.uk/?p=64.
18228     rangeIntersectsNode : function(range, node)
18229     {
18230         var nodeRange = node.ownerDocument.createRange();
18231         try {
18232             nodeRange.selectNode(node);
18233         } catch (e) {
18234             nodeRange.selectNodeContents(node);
18235         }
18236     
18237         var rangeStartRange = range.cloneRange();
18238         rangeStartRange.collapse(true);
18239     
18240         var rangeEndRange = range.cloneRange();
18241         rangeEndRange.collapse(false);
18242     
18243         var nodeStartRange = nodeRange.cloneRange();
18244         nodeStartRange.collapse(true);
18245     
18246         var nodeEndRange = nodeRange.cloneRange();
18247         nodeEndRange.collapse(false);
18248     
18249         return rangeStartRange.compareBoundaryPoints(
18250                  Range.START_TO_START, nodeEndRange) == -1 &&
18251                rangeEndRange.compareBoundaryPoints(
18252                  Range.START_TO_START, nodeStartRange) == 1;
18253         
18254          
18255     },
18256     rangeCompareNode : function(range, node)
18257     {
18258         var nodeRange = node.ownerDocument.createRange();
18259         try {
18260             nodeRange.selectNode(node);
18261         } catch (e) {
18262             nodeRange.selectNodeContents(node);
18263         }
18264         
18265         
18266         range.collapse(true);
18267     
18268         nodeRange.collapse(true);
18269      
18270         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18271         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18272          
18273         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18274         
18275         var nodeIsBefore   =  ss == 1;
18276         var nodeIsAfter    = ee == -1;
18277         
18278         if (nodeIsBefore && nodeIsAfter)
18279             return 0; // outer
18280         if (!nodeIsBefore && nodeIsAfter)
18281             return 1; //right trailed.
18282         
18283         if (nodeIsBefore && !nodeIsAfter)
18284             return 2;  // left trailed.
18285         // fully contined.
18286         return 3;
18287     },
18288
18289     // private? - in a new class?
18290     cleanUpPaste :  function()
18291     {
18292         // cleans up the whole document..
18293         Roo.log('cleanuppaste');
18294         
18295         this.cleanUpChildren(this.doc.body);
18296         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18297         if (clean != this.doc.body.innerHTML) {
18298             this.doc.body.innerHTML = clean;
18299         }
18300         
18301     },
18302     
18303     cleanWordChars : function(input) {// change the chars to hex code
18304         var he = Roo.HtmlEditorCore;
18305         
18306         var output = input;
18307         Roo.each(he.swapCodes, function(sw) { 
18308             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18309             
18310             output = output.replace(swapper, sw[1]);
18311         });
18312         
18313         return output;
18314     },
18315     
18316     
18317     cleanUpChildren : function (n)
18318     {
18319         if (!n.childNodes.length) {
18320             return;
18321         }
18322         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18323            this.cleanUpChild(n.childNodes[i]);
18324         }
18325     },
18326     
18327     
18328         
18329     
18330     cleanUpChild : function (node)
18331     {
18332         var ed = this;
18333         //console.log(node);
18334         if (node.nodeName == "#text") {
18335             // clean up silly Windows -- stuff?
18336             return; 
18337         }
18338         if (node.nodeName == "#comment") {
18339             node.parentNode.removeChild(node);
18340             // clean up silly Windows -- stuff?
18341             return; 
18342         }
18343         var lcname = node.tagName.toLowerCase();
18344         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18345         // whitelist of tags..
18346         
18347         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18348             // remove node.
18349             node.parentNode.removeChild(node);
18350             return;
18351             
18352         }
18353         
18354         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18355         
18356         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18357         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18358         
18359         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18360         //    remove_keep_children = true;
18361         //}
18362         
18363         if (remove_keep_children) {
18364             this.cleanUpChildren(node);
18365             // inserts everything just before this node...
18366             while (node.childNodes.length) {
18367                 var cn = node.childNodes[0];
18368                 node.removeChild(cn);
18369                 node.parentNode.insertBefore(cn, node);
18370             }
18371             node.parentNode.removeChild(node);
18372             return;
18373         }
18374         
18375         if (!node.attributes || !node.attributes.length) {
18376             this.cleanUpChildren(node);
18377             return;
18378         }
18379         
18380         function cleanAttr(n,v)
18381         {
18382             
18383             if (v.match(/^\./) || v.match(/^\//)) {
18384                 return;
18385             }
18386             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18387                 return;
18388             }
18389             if (v.match(/^#/)) {
18390                 return;
18391             }
18392 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18393             node.removeAttribute(n);
18394             
18395         }
18396         
18397         var cwhite = this.cwhite;
18398         var cblack = this.cblack;
18399             
18400         function cleanStyle(n,v)
18401         {
18402             if (v.match(/expression/)) { //XSS?? should we even bother..
18403                 node.removeAttribute(n);
18404                 return;
18405             }
18406             
18407             var parts = v.split(/;/);
18408             var clean = [];
18409             
18410             Roo.each(parts, function(p) {
18411                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18412                 if (!p.length) {
18413                     return true;
18414                 }
18415                 var l = p.split(':').shift().replace(/\s+/g,'');
18416                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18417                 
18418                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18419 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18420                     //node.removeAttribute(n);
18421                     return true;
18422                 }
18423                 //Roo.log()
18424                 // only allow 'c whitelisted system attributes'
18425                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18426 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18427                     //node.removeAttribute(n);
18428                     return true;
18429                 }
18430                 
18431                 
18432                  
18433                 
18434                 clean.push(p);
18435                 return true;
18436             });
18437             if (clean.length) { 
18438                 node.setAttribute(n, clean.join(';'));
18439             } else {
18440                 node.removeAttribute(n);
18441             }
18442             
18443         }
18444         
18445         
18446         for (var i = node.attributes.length-1; i > -1 ; i--) {
18447             var a = node.attributes[i];
18448             //console.log(a);
18449             
18450             if (a.name.toLowerCase().substr(0,2)=='on')  {
18451                 node.removeAttribute(a.name);
18452                 continue;
18453             }
18454             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18455                 node.removeAttribute(a.name);
18456                 continue;
18457             }
18458             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18459                 cleanAttr(a.name,a.value); // fixme..
18460                 continue;
18461             }
18462             if (a.name == 'style') {
18463                 cleanStyle(a.name,a.value);
18464                 continue;
18465             }
18466             /// clean up MS crap..
18467             // tecnically this should be a list of valid class'es..
18468             
18469             
18470             if (a.name == 'class') {
18471                 if (a.value.match(/^Mso/)) {
18472                     node.className = '';
18473                 }
18474                 
18475                 if (a.value.match(/body/)) {
18476                     node.className = '';
18477                 }
18478                 continue;
18479             }
18480             
18481             // style cleanup!?
18482             // class cleanup?
18483             
18484         }
18485         
18486         
18487         this.cleanUpChildren(node);
18488         
18489         
18490     },
18491     /**
18492      * Clean up MS wordisms...
18493      */
18494     cleanWord : function(node)
18495     {
18496         var _t = this;
18497         var cleanWordChildren = function()
18498         {
18499             if (!node.childNodes.length) {
18500                 return;
18501             }
18502             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18503                _t.cleanWord(node.childNodes[i]);
18504             }
18505         }
18506         
18507         
18508         if (!node) {
18509             this.cleanWord(this.doc.body);
18510             return;
18511         }
18512         if (node.nodeName == "#text") {
18513             // clean up silly Windows -- stuff?
18514             return; 
18515         }
18516         if (node.nodeName == "#comment") {
18517             node.parentNode.removeChild(node);
18518             // clean up silly Windows -- stuff?
18519             return; 
18520         }
18521         
18522         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18523             node.parentNode.removeChild(node);
18524             return;
18525         }
18526         
18527         // remove - but keep children..
18528         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18529             while (node.childNodes.length) {
18530                 var cn = node.childNodes[0];
18531                 node.removeChild(cn);
18532                 node.parentNode.insertBefore(cn, node);
18533             }
18534             node.parentNode.removeChild(node);
18535             cleanWordChildren();
18536             return;
18537         }
18538         // clean styles
18539         if (node.className.length) {
18540             
18541             var cn = node.className.split(/\W+/);
18542             var cna = [];
18543             Roo.each(cn, function(cls) {
18544                 if (cls.match(/Mso[a-zA-Z]+/)) {
18545                     return;
18546                 }
18547                 cna.push(cls);
18548             });
18549             node.className = cna.length ? cna.join(' ') : '';
18550             if (!cna.length) {
18551                 node.removeAttribute("class");
18552             }
18553         }
18554         
18555         if (node.hasAttribute("lang")) {
18556             node.removeAttribute("lang");
18557         }
18558         
18559         if (node.hasAttribute("style")) {
18560             
18561             var styles = node.getAttribute("style").split(";");
18562             var nstyle = [];
18563             Roo.each(styles, function(s) {
18564                 if (!s.match(/:/)) {
18565                     return;
18566                 }
18567                 var kv = s.split(":");
18568                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18569                     return;
18570                 }
18571                 // what ever is left... we allow.
18572                 nstyle.push(s);
18573             });
18574             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18575             if (!nstyle.length) {
18576                 node.removeAttribute('style');
18577             }
18578         }
18579         
18580         cleanWordChildren();
18581         
18582         
18583     },
18584     domToHTML : function(currentElement, depth, nopadtext) {
18585         
18586         depth = depth || 0;
18587         nopadtext = nopadtext || false;
18588     
18589         if (!currentElement) {
18590             return this.domToHTML(this.doc.body);
18591         }
18592         
18593         //Roo.log(currentElement);
18594         var j;
18595         var allText = false;
18596         var nodeName = currentElement.nodeName;
18597         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18598         
18599         if  (nodeName == '#text') {
18600             
18601             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18602         }
18603         
18604         
18605         var ret = '';
18606         if (nodeName != 'BODY') {
18607              
18608             var i = 0;
18609             // Prints the node tagName, such as <A>, <IMG>, etc
18610             if (tagName) {
18611                 var attr = [];
18612                 for(i = 0; i < currentElement.attributes.length;i++) {
18613                     // quoting?
18614                     var aname = currentElement.attributes.item(i).name;
18615                     if (!currentElement.attributes.item(i).value.length) {
18616                         continue;
18617                     }
18618                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18619                 }
18620                 
18621                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18622             } 
18623             else {
18624                 
18625                 // eack
18626             }
18627         } else {
18628             tagName = false;
18629         }
18630         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18631             return ret;
18632         }
18633         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18634             nopadtext = true;
18635         }
18636         
18637         
18638         // Traverse the tree
18639         i = 0;
18640         var currentElementChild = currentElement.childNodes.item(i);
18641         var allText = true;
18642         var innerHTML  = '';
18643         lastnode = '';
18644         while (currentElementChild) {
18645             // Formatting code (indent the tree so it looks nice on the screen)
18646             var nopad = nopadtext;
18647             if (lastnode == 'SPAN') {
18648                 nopad  = true;
18649             }
18650             // text
18651             if  (currentElementChild.nodeName == '#text') {
18652                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18653                 toadd = nopadtext ? toadd : toadd.trim();
18654                 if (!nopad && toadd.length > 80) {
18655                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18656                 }
18657                 innerHTML  += toadd;
18658                 
18659                 i++;
18660                 currentElementChild = currentElement.childNodes.item(i);
18661                 lastNode = '';
18662                 continue;
18663             }
18664             allText = false;
18665             
18666             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18667                 
18668             // Recursively traverse the tree structure of the child node
18669             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18670             lastnode = currentElementChild.nodeName;
18671             i++;
18672             currentElementChild=currentElement.childNodes.item(i);
18673         }
18674         
18675         ret += innerHTML;
18676         
18677         if (!allText) {
18678                 // The remaining code is mostly for formatting the tree
18679             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18680         }
18681         
18682         
18683         if (tagName) {
18684             ret+= "</"+tagName+">";
18685         }
18686         return ret;
18687         
18688     },
18689         
18690     applyBlacklists : function()
18691     {
18692         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18693         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18694         
18695         this.white = [];
18696         this.black = [];
18697         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18698             if (b.indexOf(tag) > -1) {
18699                 return;
18700             }
18701             this.white.push(tag);
18702             
18703         }, this);
18704         
18705         Roo.each(w, function(tag) {
18706             if (b.indexOf(tag) > -1) {
18707                 return;
18708             }
18709             if (this.white.indexOf(tag) > -1) {
18710                 return;
18711             }
18712             this.white.push(tag);
18713             
18714         }, this);
18715         
18716         
18717         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18718             if (w.indexOf(tag) > -1) {
18719                 return;
18720             }
18721             this.black.push(tag);
18722             
18723         }, this);
18724         
18725         Roo.each(b, function(tag) {
18726             if (w.indexOf(tag) > -1) {
18727                 return;
18728             }
18729             if (this.black.indexOf(tag) > -1) {
18730                 return;
18731             }
18732             this.black.push(tag);
18733             
18734         }, this);
18735         
18736         
18737         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18738         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18739         
18740         this.cwhite = [];
18741         this.cblack = [];
18742         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18743             if (b.indexOf(tag) > -1) {
18744                 return;
18745             }
18746             this.cwhite.push(tag);
18747             
18748         }, this);
18749         
18750         Roo.each(w, function(tag) {
18751             if (b.indexOf(tag) > -1) {
18752                 return;
18753             }
18754             if (this.cwhite.indexOf(tag) > -1) {
18755                 return;
18756             }
18757             this.cwhite.push(tag);
18758             
18759         }, this);
18760         
18761         
18762         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18763             if (w.indexOf(tag) > -1) {
18764                 return;
18765             }
18766             this.cblack.push(tag);
18767             
18768         }, this);
18769         
18770         Roo.each(b, function(tag) {
18771             if (w.indexOf(tag) > -1) {
18772                 return;
18773             }
18774             if (this.cblack.indexOf(tag) > -1) {
18775                 return;
18776             }
18777             this.cblack.push(tag);
18778             
18779         }, this);
18780     },
18781     
18782     setStylesheets : function(stylesheets)
18783     {
18784         if(typeof(stylesheets) == 'string'){
18785             Roo.get(this.iframe.contentDocument.head).createChild({
18786                 tag : 'link',
18787                 rel : 'stylesheet',
18788                 type : 'text/css',
18789                 href : stylesheets
18790             });
18791             
18792             return;
18793         }
18794         var _this = this;
18795      
18796         Roo.each(stylesheets, function(s) {
18797             if(!s.length){
18798                 return;
18799             }
18800             
18801             Roo.get(_this.iframe.contentDocument.head).createChild({
18802                 tag : 'link',
18803                 rel : 'stylesheet',
18804                 type : 'text/css',
18805                 href : s
18806             });
18807         });
18808
18809         
18810     },
18811     
18812     removeStylesheets : function()
18813     {
18814         var _this = this;
18815         
18816         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18817             s.remove();
18818         });
18819     }
18820     
18821     // hide stuff that is not compatible
18822     /**
18823      * @event blur
18824      * @hide
18825      */
18826     /**
18827      * @event change
18828      * @hide
18829      */
18830     /**
18831      * @event focus
18832      * @hide
18833      */
18834     /**
18835      * @event specialkey
18836      * @hide
18837      */
18838     /**
18839      * @cfg {String} fieldClass @hide
18840      */
18841     /**
18842      * @cfg {String} focusClass @hide
18843      */
18844     /**
18845      * @cfg {String} autoCreate @hide
18846      */
18847     /**
18848      * @cfg {String} inputType @hide
18849      */
18850     /**
18851      * @cfg {String} invalidClass @hide
18852      */
18853     /**
18854      * @cfg {String} invalidText @hide
18855      */
18856     /**
18857      * @cfg {String} msgFx @hide
18858      */
18859     /**
18860      * @cfg {String} validateOnBlur @hide
18861      */
18862 });
18863
18864 Roo.HtmlEditorCore.white = [
18865         'area', 'br', 'img', 'input', 'hr', 'wbr',
18866         
18867        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
18868        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
18869        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
18870        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
18871        'table',   'ul',         'xmp', 
18872        
18873        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
18874       'thead',   'tr', 
18875      
18876       'dir', 'menu', 'ol', 'ul', 'dl',
18877        
18878       'embed',  'object'
18879 ];
18880
18881
18882 Roo.HtmlEditorCore.black = [
18883     //    'embed',  'object', // enable - backend responsiblity to clean thiese
18884         'applet', // 
18885         'base',   'basefont', 'bgsound', 'blink',  'body', 
18886         'frame',  'frameset', 'head',    'html',   'ilayer', 
18887         'iframe', 'layer',  'link',     'meta',    'object',   
18888         'script', 'style' ,'title',  'xml' // clean later..
18889 ];
18890 Roo.HtmlEditorCore.clean = [
18891     'script', 'style', 'title', 'xml'
18892 ];
18893 Roo.HtmlEditorCore.remove = [
18894     'font'
18895 ];
18896 // attributes..
18897
18898 Roo.HtmlEditorCore.ablack = [
18899     'on'
18900 ];
18901     
18902 Roo.HtmlEditorCore.aclean = [ 
18903     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
18904 ];
18905
18906 // protocols..
18907 Roo.HtmlEditorCore.pwhite= [
18908         'http',  'https',  'mailto'
18909 ];
18910
18911 // white listed style attributes.
18912 Roo.HtmlEditorCore.cwhite= [
18913       //  'text-align', /// default is to allow most things..
18914       
18915          
18916 //        'font-size'//??
18917 ];
18918
18919 // black listed style attributes.
18920 Roo.HtmlEditorCore.cblack= [
18921       //  'font-size' -- this can be set by the project 
18922 ];
18923
18924
18925 Roo.HtmlEditorCore.swapCodes   =[ 
18926     [    8211, "--" ], 
18927     [    8212, "--" ], 
18928     [    8216,  "'" ],  
18929     [    8217, "'" ],  
18930     [    8220, '"' ],  
18931     [    8221, '"' ],  
18932     [    8226, "*" ],  
18933     [    8230, "..." ]
18934 ]; 
18935
18936     /*
18937  * - LGPL
18938  *
18939  * HtmlEditor
18940  * 
18941  */
18942
18943 /**
18944  * @class Roo.bootstrap.HtmlEditor
18945  * @extends Roo.bootstrap.TextArea
18946  * Bootstrap HtmlEditor class
18947
18948  * @constructor
18949  * Create a new HtmlEditor
18950  * @param {Object} config The config object
18951  */
18952
18953 Roo.bootstrap.HtmlEditor = function(config){
18954     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18955     if (!this.toolbars) {
18956         this.toolbars = [];
18957     }
18958     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18959     this.addEvents({
18960             /**
18961              * @event initialize
18962              * Fires when the editor is fully initialized (including the iframe)
18963              * @param {HtmlEditor} this
18964              */
18965             initialize: true,
18966             /**
18967              * @event activate
18968              * Fires when the editor is first receives the focus. Any insertion must wait
18969              * until after this event.
18970              * @param {HtmlEditor} this
18971              */
18972             activate: true,
18973              /**
18974              * @event beforesync
18975              * Fires before the textarea is updated with content from the editor iframe. Return false
18976              * to cancel the sync.
18977              * @param {HtmlEditor} this
18978              * @param {String} html
18979              */
18980             beforesync: true,
18981              /**
18982              * @event beforepush
18983              * Fires before the iframe editor is updated with content from the textarea. Return false
18984              * to cancel the push.
18985              * @param {HtmlEditor} this
18986              * @param {String} html
18987              */
18988             beforepush: true,
18989              /**
18990              * @event sync
18991              * Fires when the textarea is updated with content from the editor iframe.
18992              * @param {HtmlEditor} this
18993              * @param {String} html
18994              */
18995             sync: true,
18996              /**
18997              * @event push
18998              * Fires when the iframe editor is updated with content from the textarea.
18999              * @param {HtmlEditor} this
19000              * @param {String} html
19001              */
19002             push: true,
19003              /**
19004              * @event editmodechange
19005              * Fires when the editor switches edit modes
19006              * @param {HtmlEditor} this
19007              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19008              */
19009             editmodechange: true,
19010             /**
19011              * @event editorevent
19012              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19013              * @param {HtmlEditor} this
19014              */
19015             editorevent: true,
19016             /**
19017              * @event firstfocus
19018              * Fires when on first focus - needed by toolbars..
19019              * @param {HtmlEditor} this
19020              */
19021             firstfocus: true,
19022             /**
19023              * @event autosave
19024              * Auto save the htmlEditor value as a file into Events
19025              * @param {HtmlEditor} this
19026              */
19027             autosave: true,
19028             /**
19029              * @event savedpreview
19030              * preview the saved version of htmlEditor
19031              * @param {HtmlEditor} this
19032              */
19033             savedpreview: true
19034         });
19035 };
19036
19037
19038 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19039     
19040     
19041       /**
19042      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19043      */
19044     toolbars : false,
19045    
19046      /**
19047      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19048      *                        Roo.resizable.
19049      */
19050     resizable : false,
19051      /**
19052      * @cfg {Number} height (in pixels)
19053      */   
19054     height: 300,
19055    /**
19056      * @cfg {Number} width (in pixels)
19057      */   
19058     width: false,
19059     
19060     /**
19061      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19062      * 
19063      */
19064     stylesheets: false,
19065     
19066     // id of frame..
19067     frameId: false,
19068     
19069     // private properties
19070     validationEvent : false,
19071     deferHeight: true,
19072     initialized : false,
19073     activated : false,
19074     
19075     onFocus : Roo.emptyFn,
19076     iframePad:3,
19077     hideMode:'offsets',
19078     
19079     
19080     tbContainer : false,
19081     
19082     toolbarContainer :function() {
19083         return this.wrap.select('.x-html-editor-tb',true).first();
19084     },
19085
19086     /**
19087      * Protected method that will not generally be called directly. It
19088      * is called when the editor creates its toolbar. Override this method if you need to
19089      * add custom toolbar buttons.
19090      * @param {HtmlEditor} editor
19091      */
19092     createToolbar : function(){
19093         
19094         Roo.log("create toolbars");
19095         
19096         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19097         this.toolbars[0].render(this.toolbarContainer());
19098         
19099         return;
19100         
19101 //        if (!editor.toolbars || !editor.toolbars.length) {
19102 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19103 //        }
19104 //        
19105 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19106 //            editor.toolbars[i] = Roo.factory(
19107 //                    typeof(editor.toolbars[i]) == 'string' ?
19108 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19109 //                Roo.bootstrap.HtmlEditor);
19110 //            editor.toolbars[i].init(editor);
19111 //        }
19112     },
19113
19114      
19115     // private
19116     onRender : function(ct, position)
19117     {
19118        // Roo.log("Call onRender: " + this.xtype);
19119         var _t = this;
19120         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19121       
19122         this.wrap = this.inputEl().wrap({
19123             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19124         });
19125         
19126         this.editorcore.onRender(ct, position);
19127          
19128         if (this.resizable) {
19129             this.resizeEl = new Roo.Resizable(this.wrap, {
19130                 pinned : true,
19131                 wrap: true,
19132                 dynamic : true,
19133                 minHeight : this.height,
19134                 height: this.height,
19135                 handles : this.resizable,
19136                 width: this.width,
19137                 listeners : {
19138                     resize : function(r, w, h) {
19139                         _t.onResize(w,h); // -something
19140                     }
19141                 }
19142             });
19143             
19144         }
19145         this.createToolbar(this);
19146        
19147         
19148         if(!this.width && this.resizable){
19149             this.setSize(this.wrap.getSize());
19150         }
19151         if (this.resizeEl) {
19152             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19153             // should trigger onReize..
19154         }
19155         
19156     },
19157
19158     // private
19159     onResize : function(w, h)
19160     {
19161         Roo.log('resize: ' +w + ',' + h );
19162         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19163         var ew = false;
19164         var eh = false;
19165         
19166         if(this.inputEl() ){
19167             if(typeof w == 'number'){
19168                 var aw = w - this.wrap.getFrameWidth('lr');
19169                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19170                 ew = aw;
19171             }
19172             if(typeof h == 'number'){
19173                  var tbh = -11;  // fixme it needs to tool bar size!
19174                 for (var i =0; i < this.toolbars.length;i++) {
19175                     // fixme - ask toolbars for heights?
19176                     tbh += this.toolbars[i].el.getHeight();
19177                     //if (this.toolbars[i].footer) {
19178                     //    tbh += this.toolbars[i].footer.el.getHeight();
19179                     //}
19180                 }
19181               
19182                 
19183                 
19184                 
19185                 
19186                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19187                 ah -= 5; // knock a few pixes off for look..
19188                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19189                 var eh = ah;
19190             }
19191         }
19192         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19193         this.editorcore.onResize(ew,eh);
19194         
19195     },
19196
19197     /**
19198      * Toggles the editor between standard and source edit mode.
19199      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19200      */
19201     toggleSourceEdit : function(sourceEditMode)
19202     {
19203         this.editorcore.toggleSourceEdit(sourceEditMode);
19204         
19205         if(this.editorcore.sourceEditMode){
19206             Roo.log('editor - showing textarea');
19207             
19208 //            Roo.log('in');
19209 //            Roo.log(this.syncValue());
19210             this.syncValue();
19211             this.inputEl().removeClass(['hide', 'x-hidden']);
19212             this.inputEl().dom.removeAttribute('tabIndex');
19213             this.inputEl().focus();
19214         }else{
19215             Roo.log('editor - hiding textarea');
19216 //            Roo.log('out')
19217 //            Roo.log(this.pushValue()); 
19218             this.pushValue();
19219             
19220             this.inputEl().addClass(['hide', 'x-hidden']);
19221             this.inputEl().dom.setAttribute('tabIndex', -1);
19222             //this.deferFocus();
19223         }
19224          
19225         if(this.resizable){
19226             this.setSize(this.wrap.getSize());
19227         }
19228         
19229         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19230     },
19231  
19232     // private (for BoxComponent)
19233     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19234
19235     // private (for BoxComponent)
19236     getResizeEl : function(){
19237         return this.wrap;
19238     },
19239
19240     // private (for BoxComponent)
19241     getPositionEl : function(){
19242         return this.wrap;
19243     },
19244
19245     // private
19246     initEvents : function(){
19247         this.originalValue = this.getValue();
19248     },
19249
19250 //    /**
19251 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19252 //     * @method
19253 //     */
19254 //    markInvalid : Roo.emptyFn,
19255 //    /**
19256 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19257 //     * @method
19258 //     */
19259 //    clearInvalid : Roo.emptyFn,
19260
19261     setValue : function(v){
19262         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19263         this.editorcore.pushValue();
19264     },
19265
19266      
19267     // private
19268     deferFocus : function(){
19269         this.focus.defer(10, this);
19270     },
19271
19272     // doc'ed in Field
19273     focus : function(){
19274         this.editorcore.focus();
19275         
19276     },
19277       
19278
19279     // private
19280     onDestroy : function(){
19281         
19282         
19283         
19284         if(this.rendered){
19285             
19286             for (var i =0; i < this.toolbars.length;i++) {
19287                 // fixme - ask toolbars for heights?
19288                 this.toolbars[i].onDestroy();
19289             }
19290             
19291             this.wrap.dom.innerHTML = '';
19292             this.wrap.remove();
19293         }
19294     },
19295
19296     // private
19297     onFirstFocus : function(){
19298         //Roo.log("onFirstFocus");
19299         this.editorcore.onFirstFocus();
19300          for (var i =0; i < this.toolbars.length;i++) {
19301             this.toolbars[i].onFirstFocus();
19302         }
19303         
19304     },
19305     
19306     // private
19307     syncValue : function()
19308     {   
19309         this.editorcore.syncValue();
19310     },
19311     
19312     pushValue : function()
19313     {   
19314         this.editorcore.pushValue();
19315     }
19316      
19317     
19318     // hide stuff that is not compatible
19319     /**
19320      * @event blur
19321      * @hide
19322      */
19323     /**
19324      * @event change
19325      * @hide
19326      */
19327     /**
19328      * @event focus
19329      * @hide
19330      */
19331     /**
19332      * @event specialkey
19333      * @hide
19334      */
19335     /**
19336      * @cfg {String} fieldClass @hide
19337      */
19338     /**
19339      * @cfg {String} focusClass @hide
19340      */
19341     /**
19342      * @cfg {String} autoCreate @hide
19343      */
19344     /**
19345      * @cfg {String} inputType @hide
19346      */
19347     /**
19348      * @cfg {String} invalidClass @hide
19349      */
19350     /**
19351      * @cfg {String} invalidText @hide
19352      */
19353     /**
19354      * @cfg {String} msgFx @hide
19355      */
19356     /**
19357      * @cfg {String} validateOnBlur @hide
19358      */
19359 });
19360  
19361     
19362    
19363    
19364    
19365       
19366 Roo.namespace('Roo.bootstrap.htmleditor');
19367 /**
19368  * @class Roo.bootstrap.HtmlEditorToolbar1
19369  * Basic Toolbar
19370  * 
19371  * Usage:
19372  *
19373  new Roo.bootstrap.HtmlEditor({
19374     ....
19375     toolbars : [
19376         new Roo.bootstrap.HtmlEditorToolbar1({
19377             disable : { fonts: 1 , format: 1, ..., ... , ...],
19378             btns : [ .... ]
19379         })
19380     }
19381      
19382  * 
19383  * @cfg {Object} disable List of elements to disable..
19384  * @cfg {Array} btns List of additional buttons.
19385  * 
19386  * 
19387  * NEEDS Extra CSS? 
19388  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19389  */
19390  
19391 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19392 {
19393     
19394     Roo.apply(this, config);
19395     
19396     // default disabled, based on 'good practice'..
19397     this.disable = this.disable || {};
19398     Roo.applyIf(this.disable, {
19399         fontSize : true,
19400         colors : true,
19401         specialElements : true
19402     });
19403     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19404     
19405     this.editor = config.editor;
19406     this.editorcore = config.editor.editorcore;
19407     
19408     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19409     
19410     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19411     // dont call parent... till later.
19412 }
19413 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19414      
19415     bar : true,
19416     
19417     editor : false,
19418     editorcore : false,
19419     
19420     
19421     formats : [
19422         "p" ,  
19423         "h1","h2","h3","h4","h5","h6", 
19424         "pre", "code", 
19425         "abbr", "acronym", "address", "cite", "samp", "var",
19426         'div','span'
19427     ],
19428     
19429     onRender : function(ct, position)
19430     {
19431        // Roo.log("Call onRender: " + this.xtype);
19432         
19433        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19434        Roo.log(this.el);
19435        this.el.dom.style.marginBottom = '0';
19436        var _this = this;
19437        var editorcore = this.editorcore;
19438        var editor= this.editor;
19439        
19440        var children = [];
19441        var btn = function(id,cmd , toggle, handler){
19442        
19443             var  event = toggle ? 'toggle' : 'click';
19444        
19445             var a = {
19446                 size : 'sm',
19447                 xtype: 'Button',
19448                 xns: Roo.bootstrap,
19449                 glyphicon : id,
19450                 cmd : id || cmd,
19451                 enableToggle:toggle !== false,
19452                 //html : 'submit'
19453                 pressed : toggle ? false : null,
19454                 listeners : {}
19455             }
19456             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19457                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19458             }
19459             children.push(a);
19460             return a;
19461        }
19462         
19463         var style = {
19464                 xtype: 'Button',
19465                 size : 'sm',
19466                 xns: Roo.bootstrap,
19467                 glyphicon : 'font',
19468                 //html : 'submit'
19469                 menu : {
19470                     xtype: 'Menu',
19471                     xns: Roo.bootstrap,
19472                     items:  []
19473                 }
19474         };
19475         Roo.each(this.formats, function(f) {
19476             style.menu.items.push({
19477                 xtype :'MenuItem',
19478                 xns: Roo.bootstrap,
19479                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19480                 tagname : f,
19481                 listeners : {
19482                     click : function()
19483                     {
19484                         editorcore.insertTag(this.tagname);
19485                         editor.focus();
19486                     }
19487                 }
19488                 
19489             });
19490         });
19491          children.push(style);   
19492             
19493             
19494         btn('bold',false,true);
19495         btn('italic',false,true);
19496         btn('align-left', 'justifyleft',true);
19497         btn('align-center', 'justifycenter',true);
19498         btn('align-right' , 'justifyright',true);
19499         btn('link', false, false, function(btn) {
19500             //Roo.log("create link?");
19501             var url = prompt(this.createLinkText, this.defaultLinkValue);
19502             if(url && url != 'http:/'+'/'){
19503                 this.editorcore.relayCmd('createlink', url);
19504             }
19505         }),
19506         btn('list','insertunorderedlist',true);
19507         btn('pencil', false,true, function(btn){
19508                 Roo.log(this);
19509                 
19510                 this.toggleSourceEdit(btn.pressed);
19511         });
19512         /*
19513         var cog = {
19514                 xtype: 'Button',
19515                 size : 'sm',
19516                 xns: Roo.bootstrap,
19517                 glyphicon : 'cog',
19518                 //html : 'submit'
19519                 menu : {
19520                     xtype: 'Menu',
19521                     xns: Roo.bootstrap,
19522                     items:  []
19523                 }
19524         };
19525         
19526         cog.menu.items.push({
19527             xtype :'MenuItem',
19528             xns: Roo.bootstrap,
19529             html : Clean styles,
19530             tagname : f,
19531             listeners : {
19532                 click : function()
19533                 {
19534                     editorcore.insertTag(this.tagname);
19535                     editor.focus();
19536                 }
19537             }
19538             
19539         });
19540        */
19541         
19542          
19543        this.xtype = 'NavSimplebar';
19544         
19545         for(var i=0;i< children.length;i++) {
19546             
19547             this.buttons.add(this.addxtypeChild(children[i]));
19548             
19549         }
19550         
19551         editor.on('editorevent', this.updateToolbar, this);
19552     },
19553     onBtnClick : function(id)
19554     {
19555        this.editorcore.relayCmd(id);
19556        this.editorcore.focus();
19557     },
19558     
19559     /**
19560      * Protected method that will not generally be called directly. It triggers
19561      * a toolbar update by reading the markup state of the current selection in the editor.
19562      */
19563     updateToolbar: function(){
19564
19565         if(!this.editorcore.activated){
19566             this.editor.onFirstFocus(); // is this neeed?
19567             return;
19568         }
19569
19570         var btns = this.buttons; 
19571         var doc = this.editorcore.doc;
19572         btns.get('bold').setActive(doc.queryCommandState('bold'));
19573         btns.get('italic').setActive(doc.queryCommandState('italic'));
19574         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19575         
19576         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19577         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19578         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19579         
19580         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19581         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19582          /*
19583         
19584         var ans = this.editorcore.getAllAncestors();
19585         if (this.formatCombo) {
19586             
19587             
19588             var store = this.formatCombo.store;
19589             this.formatCombo.setValue("");
19590             for (var i =0; i < ans.length;i++) {
19591                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19592                     // select it..
19593                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19594                     break;
19595                 }
19596             }
19597         }
19598         
19599         
19600         
19601         // hides menus... - so this cant be on a menu...
19602         Roo.bootstrap.MenuMgr.hideAll();
19603         */
19604         Roo.bootstrap.MenuMgr.hideAll();
19605         //this.editorsyncValue();
19606     },
19607     onFirstFocus: function() {
19608         this.buttons.each(function(item){
19609            item.enable();
19610         });
19611     },
19612     toggleSourceEdit : function(sourceEditMode){
19613         
19614           
19615         if(sourceEditMode){
19616             Roo.log("disabling buttons");
19617            this.buttons.each( function(item){
19618                 if(item.cmd != 'pencil'){
19619                     item.disable();
19620                 }
19621             });
19622           
19623         }else{
19624             Roo.log("enabling buttons");
19625             if(this.editorcore.initialized){
19626                 this.buttons.each( function(item){
19627                     item.enable();
19628                 });
19629             }
19630             
19631         }
19632         Roo.log("calling toggole on editor");
19633         // tell the editor that it's been pressed..
19634         this.editor.toggleSourceEdit(sourceEditMode);
19635        
19636     }
19637 });
19638
19639
19640
19641
19642
19643 /**
19644  * @class Roo.bootstrap.Table.AbstractSelectionModel
19645  * @extends Roo.util.Observable
19646  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19647  * implemented by descendant classes.  This class should not be directly instantiated.
19648  * @constructor
19649  */
19650 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19651     this.locked = false;
19652     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19653 };
19654
19655
19656 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19657     /** @ignore Called by the grid automatically. Do not call directly. */
19658     init : function(grid){
19659         this.grid = grid;
19660         this.initEvents();
19661     },
19662
19663     /**
19664      * Locks the selections.
19665      */
19666     lock : function(){
19667         this.locked = true;
19668     },
19669
19670     /**
19671      * Unlocks the selections.
19672      */
19673     unlock : function(){
19674         this.locked = false;
19675     },
19676
19677     /**
19678      * Returns true if the selections are locked.
19679      * @return {Boolean}
19680      */
19681     isLocked : function(){
19682         return this.locked;
19683     }
19684 });
19685 /**
19686  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19687  * @class Roo.bootstrap.Table.RowSelectionModel
19688  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19689  * It supports multiple selections and keyboard selection/navigation. 
19690  * @constructor
19691  * @param {Object} config
19692  */
19693
19694 Roo.bootstrap.Table.RowSelectionModel = function(config){
19695     Roo.apply(this, config);
19696     this.selections = new Roo.util.MixedCollection(false, function(o){
19697         return o.id;
19698     });
19699
19700     this.last = false;
19701     this.lastActive = false;
19702
19703     this.addEvents({
19704         /**
19705              * @event selectionchange
19706              * Fires when the selection changes
19707              * @param {SelectionModel} this
19708              */
19709             "selectionchange" : true,
19710         /**
19711              * @event afterselectionchange
19712              * Fires after the selection changes (eg. by key press or clicking)
19713              * @param {SelectionModel} this
19714              */
19715             "afterselectionchange" : true,
19716         /**
19717              * @event beforerowselect
19718              * Fires when a row is selected being selected, return false to cancel.
19719              * @param {SelectionModel} this
19720              * @param {Number} rowIndex The selected index
19721              * @param {Boolean} keepExisting False if other selections will be cleared
19722              */
19723             "beforerowselect" : true,
19724         /**
19725              * @event rowselect
19726              * Fires when a row is selected.
19727              * @param {SelectionModel} this
19728              * @param {Number} rowIndex The selected index
19729              * @param {Roo.data.Record} r The record
19730              */
19731             "rowselect" : true,
19732         /**
19733              * @event rowdeselect
19734              * Fires when a row is deselected.
19735              * @param {SelectionModel} this
19736              * @param {Number} rowIndex The selected index
19737              */
19738         "rowdeselect" : true
19739     });
19740     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19741     this.locked = false;
19742 };
19743
19744 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19745     /**
19746      * @cfg {Boolean} singleSelect
19747      * True to allow selection of only one row at a time (defaults to false)
19748      */
19749     singleSelect : false,
19750
19751     // private
19752     initEvents : function(){
19753
19754         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19755             this.grid.on("mousedown", this.handleMouseDown, this);
19756         }else{ // allow click to work like normal
19757             this.grid.on("rowclick", this.handleDragableRowClick, this);
19758         }
19759
19760         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19761             "up" : function(e){
19762                 if(!e.shiftKey){
19763                     this.selectPrevious(e.shiftKey);
19764                 }else if(this.last !== false && this.lastActive !== false){
19765                     var last = this.last;
19766                     this.selectRange(this.last,  this.lastActive-1);
19767                     this.grid.getView().focusRow(this.lastActive);
19768                     if(last !== false){
19769                         this.last = last;
19770                     }
19771                 }else{
19772                     this.selectFirstRow();
19773                 }
19774                 this.fireEvent("afterselectionchange", this);
19775             },
19776             "down" : function(e){
19777                 if(!e.shiftKey){
19778                     this.selectNext(e.shiftKey);
19779                 }else if(this.last !== false && this.lastActive !== false){
19780                     var last = this.last;
19781                     this.selectRange(this.last,  this.lastActive+1);
19782                     this.grid.getView().focusRow(this.lastActive);
19783                     if(last !== false){
19784                         this.last = last;
19785                     }
19786                 }else{
19787                     this.selectFirstRow();
19788                 }
19789                 this.fireEvent("afterselectionchange", this);
19790             },
19791             scope: this
19792         });
19793
19794         var view = this.grid.view;
19795         view.on("refresh", this.onRefresh, this);
19796         view.on("rowupdated", this.onRowUpdated, this);
19797         view.on("rowremoved", this.onRemove, this);
19798     },
19799
19800     // private
19801     onRefresh : function(){
19802         var ds = this.grid.dataSource, i, v = this.grid.view;
19803         var s = this.selections;
19804         s.each(function(r){
19805             if((i = ds.indexOfId(r.id)) != -1){
19806                 v.onRowSelect(i);
19807             }else{
19808                 s.remove(r);
19809             }
19810         });
19811     },
19812
19813     // private
19814     onRemove : function(v, index, r){
19815         this.selections.remove(r);
19816     },
19817
19818     // private
19819     onRowUpdated : function(v, index, r){
19820         if(this.isSelected(r)){
19821             v.onRowSelect(index);
19822         }
19823     },
19824
19825     /**
19826      * Select records.
19827      * @param {Array} records The records to select
19828      * @param {Boolean} keepExisting (optional) True to keep existing selections
19829      */
19830     selectRecords : function(records, keepExisting){
19831         if(!keepExisting){
19832             this.clearSelections();
19833         }
19834         var ds = this.grid.dataSource;
19835         for(var i = 0, len = records.length; i < len; i++){
19836             this.selectRow(ds.indexOf(records[i]), true);
19837         }
19838     },
19839
19840     /**
19841      * Gets the number of selected rows.
19842      * @return {Number}
19843      */
19844     getCount : function(){
19845         return this.selections.length;
19846     },
19847
19848     /**
19849      * Selects the first row in the grid.
19850      */
19851     selectFirstRow : function(){
19852         this.selectRow(0);
19853     },
19854
19855     /**
19856      * Select the last row.
19857      * @param {Boolean} keepExisting (optional) True to keep existing selections
19858      */
19859     selectLastRow : function(keepExisting){
19860         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19861     },
19862
19863     /**
19864      * Selects the row immediately following the last selected row.
19865      * @param {Boolean} keepExisting (optional) True to keep existing selections
19866      */
19867     selectNext : function(keepExisting){
19868         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19869             this.selectRow(this.last+1, keepExisting);
19870             this.grid.getView().focusRow(this.last);
19871         }
19872     },
19873
19874     /**
19875      * Selects the row that precedes the last selected row.
19876      * @param {Boolean} keepExisting (optional) True to keep existing selections
19877      */
19878     selectPrevious : function(keepExisting){
19879         if(this.last){
19880             this.selectRow(this.last-1, keepExisting);
19881             this.grid.getView().focusRow(this.last);
19882         }
19883     },
19884
19885     /**
19886      * Returns the selected records
19887      * @return {Array} Array of selected records
19888      */
19889     getSelections : function(){
19890         return [].concat(this.selections.items);
19891     },
19892
19893     /**
19894      * Returns the first selected record.
19895      * @return {Record}
19896      */
19897     getSelected : function(){
19898         return this.selections.itemAt(0);
19899     },
19900
19901
19902     /**
19903      * Clears all selections.
19904      */
19905     clearSelections : function(fast){
19906         if(this.locked) return;
19907         if(fast !== true){
19908             var ds = this.grid.dataSource;
19909             var s = this.selections;
19910             s.each(function(r){
19911                 this.deselectRow(ds.indexOfId(r.id));
19912             }, this);
19913             s.clear();
19914         }else{
19915             this.selections.clear();
19916         }
19917         this.last = false;
19918     },
19919
19920
19921     /**
19922      * Selects all rows.
19923      */
19924     selectAll : function(){
19925         if(this.locked) return;
19926         this.selections.clear();
19927         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19928             this.selectRow(i, true);
19929         }
19930     },
19931
19932     /**
19933      * Returns True if there is a selection.
19934      * @return {Boolean}
19935      */
19936     hasSelection : function(){
19937         return this.selections.length > 0;
19938     },
19939
19940     /**
19941      * Returns True if the specified row is selected.
19942      * @param {Number/Record} record The record or index of the record to check
19943      * @return {Boolean}
19944      */
19945     isSelected : function(index){
19946         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19947         return (r && this.selections.key(r.id) ? true : false);
19948     },
19949
19950     /**
19951      * Returns True if the specified record id is selected.
19952      * @param {String} id The id of record to check
19953      * @return {Boolean}
19954      */
19955     isIdSelected : function(id){
19956         return (this.selections.key(id) ? true : false);
19957     },
19958
19959     // private
19960     handleMouseDown : function(e, t){
19961         var view = this.grid.getView(), rowIndex;
19962         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19963             return;
19964         };
19965         if(e.shiftKey && this.last !== false){
19966             var last = this.last;
19967             this.selectRange(last, rowIndex, e.ctrlKey);
19968             this.last = last; // reset the last
19969             view.focusRow(rowIndex);
19970         }else{
19971             var isSelected = this.isSelected(rowIndex);
19972             if(e.button !== 0 && isSelected){
19973                 view.focusRow(rowIndex);
19974             }else if(e.ctrlKey && isSelected){
19975                 this.deselectRow(rowIndex);
19976             }else if(!isSelected){
19977                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19978                 view.focusRow(rowIndex);
19979             }
19980         }
19981         this.fireEvent("afterselectionchange", this);
19982     },
19983     // private
19984     handleDragableRowClick :  function(grid, rowIndex, e) 
19985     {
19986         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19987             this.selectRow(rowIndex, false);
19988             grid.view.focusRow(rowIndex);
19989              this.fireEvent("afterselectionchange", this);
19990         }
19991     },
19992     
19993     /**
19994      * Selects multiple rows.
19995      * @param {Array} rows Array of the indexes of the row to select
19996      * @param {Boolean} keepExisting (optional) True to keep existing selections
19997      */
19998     selectRows : function(rows, keepExisting){
19999         if(!keepExisting){
20000             this.clearSelections();
20001         }
20002         for(var i = 0, len = rows.length; i < len; i++){
20003             this.selectRow(rows[i], true);
20004         }
20005     },
20006
20007     /**
20008      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20009      * @param {Number} startRow The index of the first row in the range
20010      * @param {Number} endRow The index of the last row in the range
20011      * @param {Boolean} keepExisting (optional) True to retain existing selections
20012      */
20013     selectRange : function(startRow, endRow, keepExisting){
20014         if(this.locked) return;
20015         if(!keepExisting){
20016             this.clearSelections();
20017         }
20018         if(startRow <= endRow){
20019             for(var i = startRow; i <= endRow; i++){
20020                 this.selectRow(i, true);
20021             }
20022         }else{
20023             for(var i = startRow; i >= endRow; i--){
20024                 this.selectRow(i, true);
20025             }
20026         }
20027     },
20028
20029     /**
20030      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20031      * @param {Number} startRow The index of the first row in the range
20032      * @param {Number} endRow The index of the last row in the range
20033      */
20034     deselectRange : function(startRow, endRow, preventViewNotify){
20035         if(this.locked) return;
20036         for(var i = startRow; i <= endRow; i++){
20037             this.deselectRow(i, preventViewNotify);
20038         }
20039     },
20040
20041     /**
20042      * Selects a row.
20043      * @param {Number} row The index of the row to select
20044      * @param {Boolean} keepExisting (optional) True to keep existing selections
20045      */
20046     selectRow : function(index, keepExisting, preventViewNotify){
20047         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20048         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20049             if(!keepExisting || this.singleSelect){
20050                 this.clearSelections();
20051             }
20052             var r = this.grid.dataSource.getAt(index);
20053             this.selections.add(r);
20054             this.last = this.lastActive = index;
20055             if(!preventViewNotify){
20056                 this.grid.getView().onRowSelect(index);
20057             }
20058             this.fireEvent("rowselect", this, index, r);
20059             this.fireEvent("selectionchange", this);
20060         }
20061     },
20062
20063     /**
20064      * Deselects a row.
20065      * @param {Number} row The index of the row to deselect
20066      */
20067     deselectRow : function(index, preventViewNotify){
20068         if(this.locked) return;
20069         if(this.last == index){
20070             this.last = false;
20071         }
20072         if(this.lastActive == index){
20073             this.lastActive = false;
20074         }
20075         var r = this.grid.dataSource.getAt(index);
20076         this.selections.remove(r);
20077         if(!preventViewNotify){
20078             this.grid.getView().onRowDeselect(index);
20079         }
20080         this.fireEvent("rowdeselect", this, index);
20081         this.fireEvent("selectionchange", this);
20082     },
20083
20084     // private
20085     restoreLast : function(){
20086         if(this._last){
20087             this.last = this._last;
20088         }
20089     },
20090
20091     // private
20092     acceptsNav : function(row, col, cm){
20093         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20094     },
20095
20096     // private
20097     onEditorKey : function(field, e){
20098         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20099         if(k == e.TAB){
20100             e.stopEvent();
20101             ed.completeEdit();
20102             if(e.shiftKey){
20103                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20104             }else{
20105                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20106             }
20107         }else if(k == e.ENTER && !e.ctrlKey){
20108             e.stopEvent();
20109             ed.completeEdit();
20110             if(e.shiftKey){
20111                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20112             }else{
20113                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20114             }
20115         }else if(k == e.ESC){
20116             ed.cancelEdit();
20117         }
20118         if(newCell){
20119             g.startEditing(newCell[0], newCell[1]);
20120         }
20121     }
20122 });/*
20123  * Based on:
20124  * Ext JS Library 1.1.1
20125  * Copyright(c) 2006-2007, Ext JS, LLC.
20126  *
20127  * Originally Released Under LGPL - original licence link has changed is not relivant.
20128  *
20129  * Fork - LGPL
20130  * <script type="text/javascript">
20131  */
20132  
20133 /**
20134  * @class Roo.bootstrap.PagingToolbar
20135  * @extends Roo.Row
20136  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20137  * @constructor
20138  * Create a new PagingToolbar
20139  * @param {Object} config The config object
20140  */
20141 Roo.bootstrap.PagingToolbar = function(config)
20142 {
20143     // old args format still supported... - xtype is prefered..
20144         // created from xtype...
20145     var ds = config.dataSource;
20146     this.toolbarItems = [];
20147     if (config.items) {
20148         this.toolbarItems = config.items;
20149 //        config.items = [];
20150     }
20151     
20152     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20153     this.ds = ds;
20154     this.cursor = 0;
20155     if (ds) { 
20156         this.bind(ds);
20157     }
20158     
20159     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20160     
20161 };
20162
20163 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20164     /**
20165      * @cfg {Roo.data.Store} dataSource
20166      * The underlying data store providing the paged data
20167      */
20168     /**
20169      * @cfg {String/HTMLElement/Element} container
20170      * container The id or element that will contain the toolbar
20171      */
20172     /**
20173      * @cfg {Boolean} displayInfo
20174      * True to display the displayMsg (defaults to false)
20175      */
20176     /**
20177      * @cfg {Number} pageSize
20178      * The number of records to display per page (defaults to 20)
20179      */
20180     pageSize: 20,
20181     /**
20182      * @cfg {String} displayMsg
20183      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20184      */
20185     displayMsg : 'Displaying {0} - {1} of {2}',
20186     /**
20187      * @cfg {String} emptyMsg
20188      * The message to display when no records are found (defaults to "No data to display")
20189      */
20190     emptyMsg : 'No data to display',
20191     /**
20192      * Customizable piece of the default paging text (defaults to "Page")
20193      * @type String
20194      */
20195     beforePageText : "Page",
20196     /**
20197      * Customizable piece of the default paging text (defaults to "of %0")
20198      * @type String
20199      */
20200     afterPageText : "of {0}",
20201     /**
20202      * Customizable piece of the default paging text (defaults to "First Page")
20203      * @type String
20204      */
20205     firstText : "First Page",
20206     /**
20207      * Customizable piece of the default paging text (defaults to "Previous Page")
20208      * @type String
20209      */
20210     prevText : "Previous Page",
20211     /**
20212      * Customizable piece of the default paging text (defaults to "Next Page")
20213      * @type String
20214      */
20215     nextText : "Next Page",
20216     /**
20217      * Customizable piece of the default paging text (defaults to "Last Page")
20218      * @type String
20219      */
20220     lastText : "Last Page",
20221     /**
20222      * Customizable piece of the default paging text (defaults to "Refresh")
20223      * @type String
20224      */
20225     refreshText : "Refresh",
20226
20227     buttons : false,
20228     // private
20229     onRender : function(ct, position) 
20230     {
20231         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20232         this.navgroup.parentId = this.id;
20233         this.navgroup.onRender(this.el, null);
20234         // add the buttons to the navgroup
20235         
20236         if(this.displayInfo){
20237             Roo.log(this.el.select('ul.navbar-nav',true).first());
20238             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20239             this.displayEl = this.el.select('.x-paging-info', true).first();
20240 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20241 //            this.displayEl = navel.el.select('span',true).first();
20242         }
20243         
20244         var _this = this;
20245         
20246         if(this.buttons){
20247             Roo.each(_this.buttons, function(e){
20248                Roo.factory(e).onRender(_this.el, null);
20249             });
20250         }
20251             
20252         Roo.each(_this.toolbarItems, function(e) {
20253             _this.navgroup.addItem(e);
20254         });
20255         
20256         
20257         this.first = this.navgroup.addItem({
20258             tooltip: this.firstText,
20259             cls: "prev",
20260             icon : 'fa fa-backward',
20261             disabled: true,
20262             preventDefault: true,
20263             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20264         });
20265         
20266         this.prev =  this.navgroup.addItem({
20267             tooltip: this.prevText,
20268             cls: "prev",
20269             icon : 'fa fa-step-backward',
20270             disabled: true,
20271             preventDefault: true,
20272             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20273         });
20274     //this.addSeparator();
20275         
20276         
20277         var field = this.navgroup.addItem( {
20278             tagtype : 'span',
20279             cls : 'x-paging-position',
20280             
20281             html : this.beforePageText  +
20282                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20283                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20284          } ); //?? escaped?
20285         
20286         this.field = field.el.select('input', true).first();
20287         this.field.on("keydown", this.onPagingKeydown, this);
20288         this.field.on("focus", function(){this.dom.select();});
20289     
20290     
20291         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20292         //this.field.setHeight(18);
20293         //this.addSeparator();
20294         this.next = this.navgroup.addItem({
20295             tooltip: this.nextText,
20296             cls: "next",
20297             html : ' <i class="fa fa-step-forward">',
20298             disabled: true,
20299             preventDefault: true,
20300             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20301         });
20302         this.last = this.navgroup.addItem({
20303             tooltip: this.lastText,
20304             icon : 'fa fa-forward',
20305             cls: "next",
20306             disabled: true,
20307             preventDefault: true,
20308             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20309         });
20310     //this.addSeparator();
20311         this.loading = this.navgroup.addItem({
20312             tooltip: this.refreshText,
20313             icon: 'fa fa-refresh',
20314             preventDefault: true,
20315             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20316         });
20317
20318     },
20319
20320     // private
20321     updateInfo : function(){
20322         if(this.displayEl){
20323             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20324             var msg = count == 0 ?
20325                 this.emptyMsg :
20326                 String.format(
20327                     this.displayMsg,
20328                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20329                 );
20330             this.displayEl.update(msg);
20331         }
20332     },
20333
20334     // private
20335     onLoad : function(ds, r, o){
20336        this.cursor = o.params ? o.params.start : 0;
20337        var d = this.getPageData(),
20338             ap = d.activePage,
20339             ps = d.pages;
20340         
20341        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20342        this.field.dom.value = ap;
20343        this.first.setDisabled(ap == 1);
20344        this.prev.setDisabled(ap == 1);
20345        this.next.setDisabled(ap == ps);
20346        this.last.setDisabled(ap == ps);
20347        this.loading.enable();
20348        this.updateInfo();
20349     },
20350
20351     // private
20352     getPageData : function(){
20353         var total = this.ds.getTotalCount();
20354         return {
20355             total : total,
20356             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20357             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20358         };
20359     },
20360
20361     // private
20362     onLoadError : function(){
20363         this.loading.enable();
20364     },
20365
20366     // private
20367     onPagingKeydown : function(e){
20368         var k = e.getKey();
20369         var d = this.getPageData();
20370         if(k == e.RETURN){
20371             var v = this.field.dom.value, pageNum;
20372             if(!v || isNaN(pageNum = parseInt(v, 10))){
20373                 this.field.dom.value = d.activePage;
20374                 return;
20375             }
20376             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20377             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20378             e.stopEvent();
20379         }
20380         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))
20381         {
20382           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20383           this.field.dom.value = pageNum;
20384           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20385           e.stopEvent();
20386         }
20387         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20388         {
20389           var v = this.field.dom.value, pageNum; 
20390           var increment = (e.shiftKey) ? 10 : 1;
20391           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20392             increment *= -1;
20393           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20394             this.field.dom.value = d.activePage;
20395             return;
20396           }
20397           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20398           {
20399             this.field.dom.value = parseInt(v, 10) + increment;
20400             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20401             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20402           }
20403           e.stopEvent();
20404         }
20405     },
20406
20407     // private
20408     beforeLoad : function(){
20409         if(this.loading){
20410             this.loading.disable();
20411         }
20412     },
20413
20414     // private
20415     onClick : function(which){
20416         
20417         var ds = this.ds;
20418         if (!ds) {
20419             return;
20420         }
20421         
20422         switch(which){
20423             case "first":
20424                 ds.load({params:{start: 0, limit: this.pageSize}});
20425             break;
20426             case "prev":
20427                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20428             break;
20429             case "next":
20430                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20431             break;
20432             case "last":
20433                 var total = ds.getTotalCount();
20434                 var extra = total % this.pageSize;
20435                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20436                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20437             break;
20438             case "refresh":
20439                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20440             break;
20441         }
20442     },
20443
20444     /**
20445      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20446      * @param {Roo.data.Store} store The data store to unbind
20447      */
20448     unbind : function(ds){
20449         ds.un("beforeload", this.beforeLoad, this);
20450         ds.un("load", this.onLoad, this);
20451         ds.un("loadexception", this.onLoadError, this);
20452         ds.un("remove", this.updateInfo, this);
20453         ds.un("add", this.updateInfo, this);
20454         this.ds = undefined;
20455     },
20456
20457     /**
20458      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20459      * @param {Roo.data.Store} store The data store to bind
20460      */
20461     bind : function(ds){
20462         ds.on("beforeload", this.beforeLoad, this);
20463         ds.on("load", this.onLoad, this);
20464         ds.on("loadexception", this.onLoadError, this);
20465         ds.on("remove", this.updateInfo, this);
20466         ds.on("add", this.updateInfo, this);
20467         this.ds = ds;
20468     }
20469 });/*
20470  * - LGPL
20471  *
20472  * element
20473  * 
20474  */
20475
20476 /**
20477  * @class Roo.bootstrap.MessageBar
20478  * @extends Roo.bootstrap.Component
20479  * Bootstrap MessageBar class
20480  * @cfg {String} html contents of the MessageBar
20481  * @cfg {String} weight (info | success | warning | danger) default info
20482  * @cfg {String} beforeClass insert the bar before the given class
20483  * @cfg {Boolean} closable (true | false) default false
20484  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20485  * 
20486  * @constructor
20487  * Create a new Element
20488  * @param {Object} config The config object
20489  */
20490
20491 Roo.bootstrap.MessageBar = function(config){
20492     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20493 };
20494
20495 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20496     
20497     html: '',
20498     weight: 'info',
20499     closable: false,
20500     fixed: false,
20501     beforeClass: 'bootstrap-sticky-wrap',
20502     
20503     getAutoCreate : function(){
20504         
20505         var cfg = {
20506             tag: 'div',
20507             cls: 'alert alert-dismissable alert-' + this.weight,
20508             cn: [
20509                 {
20510                     tag: 'span',
20511                     cls: 'message',
20512                     html: this.html || ''
20513                 }
20514             ]
20515         }
20516         
20517         if(this.fixed){
20518             cfg.cls += ' alert-messages-fixed';
20519         }
20520         
20521         if(this.closable){
20522             cfg.cn.push({
20523                 tag: 'button',
20524                 cls: 'close',
20525                 html: 'x'
20526             });
20527         }
20528         
20529         return cfg;
20530     },
20531     
20532     onRender : function(ct, position)
20533     {
20534         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20535         
20536         if(!this.el){
20537             var cfg = Roo.apply({},  this.getAutoCreate());
20538             cfg.id = Roo.id();
20539             
20540             if (this.cls) {
20541                 cfg.cls += ' ' + this.cls;
20542             }
20543             if (this.style) {
20544                 cfg.style = this.style;
20545             }
20546             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20547             
20548             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20549         }
20550         
20551         this.el.select('>button.close').on('click', this.hide, this);
20552         
20553     },
20554     
20555     show : function()
20556     {
20557         if (!this.rendered) {
20558             this.render();
20559         }
20560         
20561         this.el.show();
20562         
20563         this.fireEvent('show', this);
20564         
20565     },
20566     
20567     hide : function()
20568     {
20569         if (!this.rendered) {
20570             this.render();
20571         }
20572         
20573         this.el.hide();
20574         
20575         this.fireEvent('hide', this);
20576     },
20577     
20578     update : function()
20579     {
20580 //        var e = this.el.dom.firstChild;
20581 //        
20582 //        if(this.closable){
20583 //            e = e.nextSibling;
20584 //        }
20585 //        
20586 //        e.data = this.html || '';
20587
20588         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20589     }
20590    
20591 });
20592
20593  
20594
20595      /*
20596  * - LGPL
20597  *
20598  * Graph
20599  * 
20600  */
20601
20602
20603 /**
20604  * @class Roo.bootstrap.Graph
20605  * @extends Roo.bootstrap.Component
20606  * Bootstrap Graph class
20607 > Prameters
20608  -sm {number} sm 4
20609  -md {number} md 5
20610  @cfg {String} graphtype  bar | vbar | pie
20611  @cfg {number} g_x coodinator | centre x (pie)
20612  @cfg {number} g_y coodinator | centre y (pie)
20613  @cfg {number} g_r radius (pie)
20614  @cfg {number} g_height height of the chart (respected by all elements in the set)
20615  @cfg {number} g_width width of the chart (respected by all elements in the set)
20616  @cfg {Object} title The title of the chart
20617     
20618  -{Array}  values
20619  -opts (object) options for the chart 
20620      o {
20621      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20622      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20623      o vgutter (number)
20624      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.
20625      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20626      o to
20627      o stretch (boolean)
20628      o }
20629  -opts (object) options for the pie
20630      o{
20631      o cut
20632      o startAngle (number)
20633      o endAngle (number)
20634      } 
20635  *
20636  * @constructor
20637  * Create a new Input
20638  * @param {Object} config The config object
20639  */
20640
20641 Roo.bootstrap.Graph = function(config){
20642     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20643     
20644     this.addEvents({
20645         // img events
20646         /**
20647          * @event click
20648          * The img click event for the img.
20649          * @param {Roo.EventObject} e
20650          */
20651         "click" : true
20652     });
20653 };
20654
20655 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20656     
20657     sm: 4,
20658     md: 5,
20659     graphtype: 'bar',
20660     g_height: 250,
20661     g_width: 400,
20662     g_x: 50,
20663     g_y: 50,
20664     g_r: 30,
20665     opts:{
20666         //g_colors: this.colors,
20667         g_type: 'soft',
20668         g_gutter: '20%'
20669
20670     },
20671     title : false,
20672
20673     getAutoCreate : function(){
20674         
20675         var cfg = {
20676             tag: 'div',
20677             html : null
20678         }
20679         
20680         
20681         return  cfg;
20682     },
20683
20684     onRender : function(ct,position){
20685         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20686         this.raphael = Raphael(this.el.dom);
20687         
20688                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20689                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20690                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20691                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20692                 /*
20693                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20694                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20695                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20696                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20697                 
20698                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20699                 r.barchart(330, 10, 300, 220, data1);
20700                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20701                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20702                 */
20703                 
20704                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20705                 // r.barchart(30, 30, 560, 250,  xdata, {
20706                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20707                 //     axis : "0 0 1 1",
20708                 //     axisxlabels :  xdata
20709                 //     //yvalues : cols,
20710                    
20711                 // });
20712 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20713 //        
20714 //        this.load(null,xdata,{
20715 //                axis : "0 0 1 1",
20716 //                axisxlabels :  xdata
20717 //                });
20718
20719     },
20720
20721     load : function(graphtype,xdata,opts){
20722         this.raphael.clear();
20723         if(!graphtype) {
20724             graphtype = this.graphtype;
20725         }
20726         if(!opts){
20727             opts = this.opts;
20728         }
20729         var r = this.raphael,
20730             fin = function () {
20731                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20732             },
20733             fout = function () {
20734                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20735             },
20736             pfin = function() {
20737                 this.sector.stop();
20738                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20739
20740                 if (this.label) {
20741                     this.label[0].stop();
20742                     this.label[0].attr({ r: 7.5 });
20743                     this.label[1].attr({ "font-weight": 800 });
20744                 }
20745             },
20746             pfout = function() {
20747                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20748
20749                 if (this.label) {
20750                     this.label[0].animate({ r: 5 }, 500, "bounce");
20751                     this.label[1].attr({ "font-weight": 400 });
20752                 }
20753             };
20754
20755         switch(graphtype){
20756             case 'bar':
20757                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20758                 break;
20759             case 'hbar':
20760                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20761                 break;
20762             case 'pie':
20763 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20764 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20765 //            
20766                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20767                 
20768                 break;
20769
20770         }
20771         
20772         if(this.title){
20773             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20774         }
20775         
20776     },
20777     
20778     setTitle: function(o)
20779     {
20780         this.title = o;
20781     },
20782     
20783     initEvents: function() {
20784         
20785         if(!this.href){
20786             this.el.on('click', this.onClick, this);
20787         }
20788     },
20789     
20790     onClick : function(e)
20791     {
20792         Roo.log('img onclick');
20793         this.fireEvent('click', this, e);
20794     }
20795    
20796 });
20797
20798  
20799 /*
20800  * - LGPL
20801  *
20802  * numberBox
20803  * 
20804  */
20805 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20806
20807 /**
20808  * @class Roo.bootstrap.dash.NumberBox
20809  * @extends Roo.bootstrap.Component
20810  * Bootstrap NumberBox class
20811  * @cfg {String} headline Box headline
20812  * @cfg {String} content Box content
20813  * @cfg {String} icon Box icon
20814  * @cfg {String} footer Footer text
20815  * @cfg {String} fhref Footer href
20816  * 
20817  * @constructor
20818  * Create a new NumberBox
20819  * @param {Object} config The config object
20820  */
20821
20822
20823 Roo.bootstrap.dash.NumberBox = function(config){
20824     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20825     
20826 };
20827
20828 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
20829     
20830     headline : '',
20831     content : '',
20832     icon : '',
20833     footer : '',
20834     fhref : '',
20835     ficon : '',
20836     
20837     getAutoCreate : function(){
20838         
20839         var cfg = {
20840             tag : 'div',
20841             cls : 'small-box ',
20842             cn : [
20843                 {
20844                     tag : 'div',
20845                     cls : 'inner',
20846                     cn :[
20847                         {
20848                             tag : 'h3',
20849                             cls : 'roo-headline',
20850                             html : this.headline
20851                         },
20852                         {
20853                             tag : 'p',
20854                             cls : 'roo-content',
20855                             html : this.content
20856                         }
20857                     ]
20858                 }
20859             ]
20860         }
20861         
20862         if(this.icon){
20863             cfg.cn.push({
20864                 tag : 'div',
20865                 cls : 'icon',
20866                 cn :[
20867                     {
20868                         tag : 'i',
20869                         cls : 'ion ' + this.icon
20870                     }
20871                 ]
20872             });
20873         }
20874         
20875         if(this.footer){
20876             var footer = {
20877                 tag : 'a',
20878                 cls : 'small-box-footer',
20879                 href : this.fhref || '#',
20880                 html : this.footer
20881             };
20882             
20883             cfg.cn.push(footer);
20884             
20885         }
20886         
20887         return  cfg;
20888     },
20889
20890     onRender : function(ct,position){
20891         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20892
20893
20894        
20895                 
20896     },
20897
20898     setHeadline: function (value)
20899     {
20900         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20901     },
20902     
20903     setFooter: function (value, href)
20904     {
20905         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20906         
20907         if(href){
20908             this.el.select('a.small-box-footer',true).first().attr('href', href);
20909         }
20910         
20911     },
20912
20913     setContent: function (value)
20914     {
20915         this.el.select('.roo-content',true).first().dom.innerHTML = value;
20916     },
20917
20918     initEvents: function() 
20919     {   
20920         
20921     }
20922     
20923 });
20924
20925  
20926 /*
20927  * - LGPL
20928  *
20929  * TabBox
20930  * 
20931  */
20932 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20933
20934 /**
20935  * @class Roo.bootstrap.dash.TabBox
20936  * @extends Roo.bootstrap.Component
20937  * Bootstrap TabBox class
20938  * @cfg {String} title Title of the TabBox
20939  * @cfg {String} icon Icon of the TabBox
20940  * @cfg {Boolean} showtabs (true|false) show the tabs default true
20941  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20942  * 
20943  * @constructor
20944  * Create a new TabBox
20945  * @param {Object} config The config object
20946  */
20947
20948
20949 Roo.bootstrap.dash.TabBox = function(config){
20950     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20951     this.addEvents({
20952         // raw events
20953         /**
20954          * @event addpane
20955          * When a pane is added
20956          * @param {Roo.bootstrap.dash.TabPane} pane
20957          */
20958         "addpane" : true,
20959         /**
20960          * @event activatepane
20961          * When a pane is activated
20962          * @param {Roo.bootstrap.dash.TabPane} pane
20963          */
20964         "activatepane" : true
20965         
20966          
20967     });
20968     
20969     this.panes = [];
20970 };
20971
20972 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
20973
20974     title : '',
20975     icon : false,
20976     showtabs : true,
20977     tabScrollable : false,
20978     
20979     getChildContainer : function()
20980     {
20981         return this.el.select('.tab-content', true).first();
20982     },
20983     
20984     getAutoCreate : function(){
20985         
20986         var header = {
20987             tag: 'li',
20988             cls: 'pull-left header',
20989             html: this.title,
20990             cn : []
20991         };
20992         
20993         if(this.icon){
20994             header.cn.push({
20995                 tag: 'i',
20996                 cls: 'fa ' + this.icon
20997             });
20998         }
20999         
21000         var h = {
21001             tag: 'ul',
21002             cls: 'nav nav-tabs pull-right',
21003             cn: [
21004                 header
21005             ]
21006         };
21007         
21008         if(this.tabScrollable){
21009             h = {
21010                 tag: 'div',
21011                 cls: 'tab-header',
21012                 cn: [
21013                     {
21014                         tag: 'ul',
21015                         cls: 'nav nav-tabs pull-right',
21016                         cn: [
21017                             header
21018                         ]
21019                     }
21020                 ]
21021             }
21022         }
21023         
21024         var cfg = {
21025             tag: 'div',
21026             cls: 'nav-tabs-custom',
21027             cn: [
21028                 h,
21029                 {
21030                     tag: 'div',
21031                     cls: 'tab-content no-padding',
21032                     cn: []
21033                 }
21034             ]
21035         }
21036
21037         return  cfg;
21038     },
21039     initEvents : function()
21040     {
21041         //Roo.log('add add pane handler');
21042         this.on('addpane', this.onAddPane, this);
21043     },
21044      /**
21045      * Updates the box title
21046      * @param {String} html to set the title to.
21047      */
21048     setTitle : function(value)
21049     {
21050         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21051     },
21052     onAddPane : function(pane)
21053     {
21054         this.panes.push(pane);
21055         //Roo.log('addpane');
21056         //Roo.log(pane);
21057         // tabs are rendere left to right..
21058         if(!this.showtabs){
21059             return;
21060         }
21061         
21062         var ctr = this.el.select('.nav-tabs', true).first();
21063          
21064          
21065         var existing = ctr.select('.nav-tab',true);
21066         var qty = existing.getCount();;
21067         
21068         
21069         var tab = ctr.createChild({
21070             tag : 'li',
21071             cls : 'nav-tab' + (qty ? '' : ' active'),
21072             cn : [
21073                 {
21074                     tag : 'a',
21075                     href:'#',
21076                     html : pane.title
21077                 }
21078             ]
21079         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21080         pane.tab = tab;
21081         
21082         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21083         if (!qty) {
21084             pane.el.addClass('active');
21085         }
21086         
21087                 
21088     },
21089     onTabClick : function(ev,un,ob,pane)
21090     {
21091         //Roo.log('tab - prev default');
21092         ev.preventDefault();
21093         
21094         
21095         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21096         pane.tab.addClass('active');
21097         //Roo.log(pane.title);
21098         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21099         // technically we should have a deactivate event.. but maybe add later.
21100         // and it should not de-activate the selected tab...
21101         this.fireEvent('activatepane', pane);
21102         pane.el.addClass('active');
21103         pane.fireEvent('activate');
21104         
21105         
21106     },
21107     
21108     getActivePane : function()
21109     {
21110         var r = false;
21111         Roo.each(this.panes, function(p) {
21112             if(p.el.hasClass('active')){
21113                 r = p;
21114                 return false;
21115             }
21116             
21117             return;
21118         });
21119         
21120         return r;
21121     }
21122     
21123     
21124 });
21125
21126  
21127 /*
21128  * - LGPL
21129  *
21130  * Tab pane
21131  * 
21132  */
21133 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21134 /**
21135  * @class Roo.bootstrap.TabPane
21136  * @extends Roo.bootstrap.Component
21137  * Bootstrap TabPane class
21138  * @cfg {Boolean} active (false | true) Default false
21139  * @cfg {String} title title of panel
21140
21141  * 
21142  * @constructor
21143  * Create a new TabPane
21144  * @param {Object} config The config object
21145  */
21146
21147 Roo.bootstrap.dash.TabPane = function(config){
21148     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21149     
21150     this.addEvents({
21151         // raw events
21152         /**
21153          * @event activate
21154          * When a pane is activated
21155          * @param {Roo.bootstrap.dash.TabPane} pane
21156          */
21157         "activate" : true
21158          
21159     });
21160 };
21161
21162 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21163     
21164     active : false,
21165     title : '',
21166     
21167     // the tabBox that this is attached to.
21168     tab : false,
21169      
21170     getAutoCreate : function() 
21171     {
21172         var cfg = {
21173             tag: 'div',
21174             cls: 'tab-pane'
21175         }
21176         
21177         if(this.active){
21178             cfg.cls += ' active';
21179         }
21180         
21181         return cfg;
21182     },
21183     initEvents  : function()
21184     {
21185         //Roo.log('trigger add pane handler');
21186         this.parent().fireEvent('addpane', this)
21187     },
21188     
21189      /**
21190      * Updates the tab title 
21191      * @param {String} html to set the title to.
21192      */
21193     setTitle: function(str)
21194     {
21195         if (!this.tab) {
21196             return;
21197         }
21198         this.title = str;
21199         this.tab.select('a', true).first().dom.innerHTML = str;
21200         
21201     }
21202     
21203     
21204     
21205 });
21206
21207  
21208
21209
21210  /*
21211  * - LGPL
21212  *
21213  * menu
21214  * 
21215  */
21216 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21217
21218 /**
21219  * @class Roo.bootstrap.menu.Menu
21220  * @extends Roo.bootstrap.Component
21221  * Bootstrap Menu class - container for Menu
21222  * @cfg {String} html Text of the menu
21223  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21224  * @cfg {String} icon Font awesome icon
21225  * @cfg {String} pos Menu align to (top | bottom) default bottom
21226  * 
21227  * 
21228  * @constructor
21229  * Create a new Menu
21230  * @param {Object} config The config object
21231  */
21232
21233
21234 Roo.bootstrap.menu.Menu = function(config){
21235     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21236     
21237     this.addEvents({
21238         /**
21239          * @event beforeshow
21240          * Fires before this menu is displayed
21241          * @param {Roo.bootstrap.menu.Menu} this
21242          */
21243         beforeshow : true,
21244         /**
21245          * @event beforehide
21246          * Fires before this menu is hidden
21247          * @param {Roo.bootstrap.menu.Menu} this
21248          */
21249         beforehide : true,
21250         /**
21251          * @event show
21252          * Fires after this menu is displayed
21253          * @param {Roo.bootstrap.menu.Menu} this
21254          */
21255         show : true,
21256         /**
21257          * @event hide
21258          * Fires after this menu is hidden
21259          * @param {Roo.bootstrap.menu.Menu} this
21260          */
21261         hide : true,
21262         /**
21263          * @event click
21264          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21265          * @param {Roo.bootstrap.menu.Menu} this
21266          * @param {Roo.EventObject} e
21267          */
21268         click : true
21269     });
21270     
21271 };
21272
21273 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21274     
21275     submenu : false,
21276     html : '',
21277     weight : 'default',
21278     icon : false,
21279     pos : 'bottom',
21280     
21281     
21282     getChildContainer : function() {
21283         if(this.isSubMenu){
21284             return this.el;
21285         }
21286         
21287         return this.el.select('ul.dropdown-menu', true).first();  
21288     },
21289     
21290     getAutoCreate : function()
21291     {
21292         var text = [
21293             {
21294                 tag : 'span',
21295                 cls : 'roo-menu-text',
21296                 html : this.html
21297             }
21298         ];
21299         
21300         if(this.icon){
21301             text.unshift({
21302                 tag : 'i',
21303                 cls : 'fa ' + this.icon
21304             })
21305         }
21306         
21307         
21308         var cfg = {
21309             tag : 'div',
21310             cls : 'btn-group',
21311             cn : [
21312                 {
21313                     tag : 'button',
21314                     cls : 'dropdown-button btn btn-' + this.weight,
21315                     cn : text
21316                 },
21317                 {
21318                     tag : 'button',
21319                     cls : 'dropdown-toggle btn btn-' + this.weight,
21320                     cn : [
21321                         {
21322                             tag : 'span',
21323                             cls : 'caret'
21324                         }
21325                     ]
21326                 },
21327                 {
21328                     tag : 'ul',
21329                     cls : 'dropdown-menu'
21330                 }
21331             ]
21332             
21333         };
21334         
21335         if(this.pos == 'top'){
21336             cfg.cls += ' dropup';
21337         }
21338         
21339         if(this.isSubMenu){
21340             cfg = {
21341                 tag : 'ul',
21342                 cls : 'dropdown-menu'
21343             }
21344         }
21345         
21346         return cfg;
21347     },
21348     
21349     onRender : function(ct, position)
21350     {
21351         this.isSubMenu = ct.hasClass('dropdown-submenu');
21352         
21353         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21354     },
21355     
21356     initEvents : function() 
21357     {
21358         if(this.isSubMenu){
21359             return;
21360         }
21361         
21362         this.hidden = true;
21363         
21364         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21365         this.triggerEl.on('click', this.onTriggerPress, this);
21366         
21367         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21368         this.buttonEl.on('click', this.onClick, this);
21369         
21370     },
21371     
21372     list : function()
21373     {
21374         if(this.isSubMenu){
21375             return this.el;
21376         }
21377         
21378         return this.el.select('ul.dropdown-menu', true).first();
21379     },
21380     
21381     onClick : function(e)
21382     {
21383         this.fireEvent("click", this, e);
21384     },
21385     
21386     onTriggerPress  : function(e)
21387     {   
21388         if (this.isVisible()) {
21389             this.hide();
21390         } else {
21391             this.show();
21392         }
21393     },
21394     
21395     isVisible : function(){
21396         return !this.hidden;
21397     },
21398     
21399     show : function()
21400     {
21401         this.fireEvent("beforeshow", this);
21402         
21403         this.hidden = false;
21404         this.el.addClass('open');
21405         
21406         Roo.get(document).on("mouseup", this.onMouseUp, this);
21407         
21408         this.fireEvent("show", this);
21409         
21410         
21411     },
21412     
21413     hide : function()
21414     {
21415         this.fireEvent("beforehide", this);
21416         
21417         this.hidden = true;
21418         this.el.removeClass('open');
21419         
21420         Roo.get(document).un("mouseup", this.onMouseUp);
21421         
21422         this.fireEvent("hide", this);
21423     },
21424     
21425     onMouseUp : function()
21426     {
21427         this.hide();
21428     }
21429     
21430 });
21431
21432  
21433  /*
21434  * - LGPL
21435  *
21436  * menu item
21437  * 
21438  */
21439 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21440
21441 /**
21442  * @class Roo.bootstrap.menu.Item
21443  * @extends Roo.bootstrap.Component
21444  * Bootstrap MenuItem class
21445  * @cfg {Boolean} submenu (true | false) default false
21446  * @cfg {String} html text of the item
21447  * @cfg {String} href the link
21448  * @cfg {Boolean} disable (true | false) default false
21449  * @cfg {Boolean} preventDefault (true | false) default true
21450  * @cfg {String} icon Font awesome icon
21451  * @cfg {String} pos Submenu align to (left | right) default right 
21452  * 
21453  * 
21454  * @constructor
21455  * Create a new Item
21456  * @param {Object} config The config object
21457  */
21458
21459
21460 Roo.bootstrap.menu.Item = function(config){
21461     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21462     this.addEvents({
21463         /**
21464          * @event mouseover
21465          * Fires when the mouse is hovering over this menu
21466          * @param {Roo.bootstrap.menu.Item} this
21467          * @param {Roo.EventObject} e
21468          */
21469         mouseover : true,
21470         /**
21471          * @event mouseout
21472          * Fires when the mouse exits this menu
21473          * @param {Roo.bootstrap.menu.Item} this
21474          * @param {Roo.EventObject} e
21475          */
21476         mouseout : true,
21477         // raw events
21478         /**
21479          * @event click
21480          * The raw click event for the entire grid.
21481          * @param {Roo.EventObject} e
21482          */
21483         click : true
21484     });
21485 };
21486
21487 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21488     
21489     submenu : false,
21490     href : '',
21491     html : '',
21492     preventDefault: true,
21493     disable : false,
21494     icon : false,
21495     pos : 'right',
21496     
21497     getAutoCreate : function()
21498     {
21499         var text = [
21500             {
21501                 tag : 'span',
21502                 cls : 'roo-menu-item-text',
21503                 html : this.html
21504             }
21505         ];
21506         
21507         if(this.icon){
21508             text.unshift({
21509                 tag : 'i',
21510                 cls : 'fa ' + this.icon
21511             })
21512         }
21513         
21514         var cfg = {
21515             tag : 'li',
21516             cn : [
21517                 {
21518                     tag : 'a',
21519                     href : this.href || '#',
21520                     cn : text
21521                 }
21522             ]
21523         };
21524         
21525         if(this.disable){
21526             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21527         }
21528         
21529         if(this.submenu){
21530             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21531             
21532             if(this.pos == 'left'){
21533                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21534             }
21535         }
21536         
21537         return cfg;
21538     },
21539     
21540     initEvents : function() 
21541     {
21542         this.el.on('mouseover', this.onMouseOver, this);
21543         this.el.on('mouseout', this.onMouseOut, this);
21544         
21545         this.el.select('a', true).first().on('click', this.onClick, this);
21546         
21547     },
21548     
21549     onClick : function(e)
21550     {
21551         if(this.preventDefault){
21552             e.preventDefault();
21553         }
21554         
21555         this.fireEvent("click", this, e);
21556     },
21557     
21558     onMouseOver : function(e)
21559     {
21560         if(this.submenu && this.pos == 'left'){
21561             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21562         }
21563         
21564         this.fireEvent("mouseover", this, e);
21565     },
21566     
21567     onMouseOut : function(e)
21568     {
21569         this.fireEvent("mouseout", this, e);
21570     }
21571 });
21572
21573  
21574
21575  /*
21576  * - LGPL
21577  *
21578  * menu separator
21579  * 
21580  */
21581 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21582
21583 /**
21584  * @class Roo.bootstrap.menu.Separator
21585  * @extends Roo.bootstrap.Component
21586  * Bootstrap Separator class
21587  * 
21588  * @constructor
21589  * Create a new Separator
21590  * @param {Object} config The config object
21591  */
21592
21593
21594 Roo.bootstrap.menu.Separator = function(config){
21595     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21596 };
21597
21598 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21599     
21600     getAutoCreate : function(){
21601         var cfg = {
21602             tag : 'li',
21603             cls: 'divider'
21604         };
21605         
21606         return cfg;
21607     }
21608    
21609 });
21610
21611  
21612
21613  /*
21614  * - LGPL
21615  *
21616  * Tooltip
21617  * 
21618  */
21619
21620 /**
21621  * @class Roo.bootstrap.Tooltip
21622  * Bootstrap Tooltip class
21623  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21624  * to determine which dom element triggers the tooltip.
21625  * 
21626  * It needs to add support for additional attributes like tooltip-position
21627  * 
21628  * @constructor
21629  * Create a new Toolti
21630  * @param {Object} config The config object
21631  */
21632
21633 Roo.bootstrap.Tooltip = function(config){
21634     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21635 };
21636
21637 Roo.apply(Roo.bootstrap.Tooltip, {
21638     /**
21639      * @function init initialize tooltip monitoring.
21640      * @static
21641      */
21642     currentEl : false,
21643     currentTip : false,
21644     currentRegion : false,
21645     
21646     //  init : delay?
21647     
21648     init : function()
21649     {
21650         Roo.get(document).on('mouseover', this.enter ,this);
21651         Roo.get(document).on('mouseout', this.leave, this);
21652          
21653         
21654         this.currentTip = new Roo.bootstrap.Tooltip();
21655     },
21656     
21657     enter : function(ev)
21658     {
21659         var dom = ev.getTarget();
21660         //Roo.log(['enter',dom]);
21661         var el = Roo.fly(dom);
21662         if (this.currentEl) {
21663             //Roo.log(dom);
21664             //Roo.log(this.currentEl);
21665             //Roo.log(this.currentEl.contains(dom));
21666             if (this.currentEl == el) {
21667                 return;
21668             }
21669             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21670                 return;
21671             }
21672
21673         }
21674         
21675         
21676         
21677         if (this.currentTip.el) {
21678             this.currentTip.el.hide(); // force hiding...
21679         }    
21680         //Roo.log(el);
21681         if (!el.attr('tooltip')) { // parents who have tip?
21682             return;
21683         }
21684         this.currentEl = el;
21685         this.currentTip.bind(el);
21686         this.currentRegion = Roo.lib.Region.getRegion(dom);
21687         this.currentTip.enter();
21688         
21689     },
21690     leave : function(ev)
21691     {
21692         var dom = ev.getTarget();
21693         //Roo.log(['leave',dom]);
21694         if (!this.currentEl) {
21695             return;
21696         }
21697         
21698         
21699         if (dom != this.currentEl.dom) {
21700             return;
21701         }
21702         var xy = ev.getXY();
21703         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21704             return;
21705         }
21706         // only activate leave if mouse cursor is outside... bounding box..
21707         
21708         
21709         
21710         
21711         if (this.currentTip) {
21712             this.currentTip.leave();
21713         }
21714         //Roo.log('clear currentEl');
21715         this.currentEl = false;
21716         
21717         
21718     },
21719     alignment : {
21720         'left' : ['r-l', [-2,0], 'right'],
21721         'right' : ['l-r', [2,0], 'left'],
21722         'bottom' : ['t-b', [0,2], 'top'],
21723         'top' : [ 'b-t', [0,-2], 'bottom']
21724     }
21725     
21726 });
21727
21728
21729 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21730     
21731     
21732     bindEl : false,
21733     
21734     delay : null, // can be { show : 300 , hide: 500}
21735     
21736     timeout : null,
21737     
21738     hoverState : null, //???
21739     
21740     placement : 'bottom', 
21741     
21742     getAutoCreate : function(){
21743     
21744         var cfg = {
21745            cls : 'tooltip',
21746            role : 'tooltip',
21747            cn : [
21748                 {
21749                     cls : 'tooltip-arrow'
21750                 },
21751                 {
21752                     cls : 'tooltip-inner'
21753                 }
21754            ]
21755         };
21756         
21757         return cfg;
21758     },
21759     bind : function(el)
21760     {
21761         this.bindEl = el;
21762     },
21763       
21764     
21765     enter : function () {
21766        
21767         if (this.timeout != null) {
21768             clearTimeout(this.timeout);
21769         }
21770         
21771         this.hoverState = 'in';
21772          //Roo.log("enter - show");
21773         if (!this.delay || !this.delay.show) {
21774             this.show();
21775             return;
21776         }
21777         var _t = this;
21778         this.timeout = setTimeout(function () {
21779             if (_t.hoverState == 'in') {
21780                 _t.show();
21781             }
21782         }, this.delay.show);
21783     },
21784     leave : function()
21785     {
21786         clearTimeout(this.timeout);
21787     
21788         this.hoverState = 'out';
21789          if (!this.delay || !this.delay.hide) {
21790             this.hide();
21791             return 
21792         }
21793        
21794         var _t = this;
21795         this.timeout = setTimeout(function () {
21796             //Roo.log("leave - timeout");
21797             
21798             if (_t.hoverState == 'out') {
21799                 _t.hide();
21800                 Roo.bootstrap.Tooltip.currentEl = false;
21801             }
21802         }, delay)
21803     },
21804     
21805     show : function ()
21806     {
21807         if (!this.el) {
21808             this.render(document.body);
21809         }
21810         // set content.
21811         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21812         this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21813         
21814         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21815         
21816         var placement = typeof this.placement == 'function' ?
21817             this.placement.call(this, this.el, on_el) :
21818             this.placement;
21819             
21820         var autoToken = /\s?auto?\s?/i;
21821         var autoPlace = autoToken.test(placement);
21822         if (autoPlace) {
21823             placement = placement.replace(autoToken, '') || 'top';
21824         }
21825         
21826         //this.el.detach()
21827         //this.el.setXY([0,0]);
21828         this.el.show();
21829         //this.el.dom.style.display='block';
21830         this.el.addClass(placement);
21831         
21832         //this.el.appendTo(on_el);
21833         
21834         var p = this.getPosition();
21835         var box = this.el.getBox();
21836         
21837         if (autoPlace) {
21838             // fixme..
21839         }
21840         var align = Roo.bootstrap.Tooltip.alignment[placement];
21841         this.el.alignTo(this.bindEl, align[0],align[1]);
21842         //var arrow = this.el.select('.arrow',true).first();
21843         //arrow.set(align[2], 
21844         
21845         this.el.addClass('in fade');
21846         this.hoverState = null;
21847         
21848         if (this.el.hasClass('fade')) {
21849             // fade it?
21850         }
21851         
21852     },
21853     hide : function()
21854     {
21855          
21856         if (!this.el) {
21857             return;
21858         }
21859         //this.el.setXY([0,0]);
21860         this.el.removeClass('in');
21861         //this.el.hide();
21862         
21863     }
21864     
21865 });
21866  
21867
21868  /*
21869  * - LGPL
21870  *
21871  * Location Picker
21872  * 
21873  */
21874
21875 /**
21876  * @class Roo.bootstrap.LocationPicker
21877  * @extends Roo.bootstrap.Component
21878  * Bootstrap LocationPicker class
21879  * @cfg {Number} latitude Position when init default 0
21880  * @cfg {Number} longitude Position when init default 0
21881  * @cfg {Number} zoom default 15
21882  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21883  * @cfg {Boolean} mapTypeControl default false
21884  * @cfg {Boolean} disableDoubleClickZoom default false
21885  * @cfg {Boolean} scrollwheel default true
21886  * @cfg {Boolean} streetViewControl default false
21887  * @cfg {Number} radius default 0
21888  * @cfg {String} locationName
21889  * @cfg {Boolean} draggable default true
21890  * @cfg {Boolean} enableAutocomplete default false
21891  * @cfg {Boolean} enableReverseGeocode default true
21892  * @cfg {String} markerTitle
21893  * 
21894  * @constructor
21895  * Create a new LocationPicker
21896  * @param {Object} config The config object
21897  */
21898
21899
21900 Roo.bootstrap.LocationPicker = function(config){
21901     
21902     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21903     
21904     this.addEvents({
21905         /**
21906          * @event initial
21907          * Fires when the picker initialized.
21908          * @param {Roo.bootstrap.LocationPicker} this
21909          * @param {Google Location} location
21910          */
21911         initial : true,
21912         /**
21913          * @event positionchanged
21914          * Fires when the picker position changed.
21915          * @param {Roo.bootstrap.LocationPicker} this
21916          * @param {Google Location} location
21917          */
21918         positionchanged : true,
21919         /**
21920          * @event resize
21921          * Fires when the map resize.
21922          * @param {Roo.bootstrap.LocationPicker} this
21923          */
21924         resize : true,
21925         /**
21926          * @event show
21927          * Fires when the map show.
21928          * @param {Roo.bootstrap.LocationPicker} this
21929          */
21930         show : true,
21931         /**
21932          * @event hide
21933          * Fires when the map hide.
21934          * @param {Roo.bootstrap.LocationPicker} this
21935          */
21936         hide : true,
21937         /**
21938          * @event mapClick
21939          * Fires when click the map.
21940          * @param {Roo.bootstrap.LocationPicker} this
21941          * @param {Map event} e
21942          */
21943         mapClick : true,
21944         /**
21945          * @event mapRightClick
21946          * Fires when right click the map.
21947          * @param {Roo.bootstrap.LocationPicker} this
21948          * @param {Map event} e
21949          */
21950         mapRightClick : true,
21951         /**
21952          * @event markerClick
21953          * Fires when click the marker.
21954          * @param {Roo.bootstrap.LocationPicker} this
21955          * @param {Map event} e
21956          */
21957         markerClick : true,
21958         /**
21959          * @event markerRightClick
21960          * Fires when right click the marker.
21961          * @param {Roo.bootstrap.LocationPicker} this
21962          * @param {Map event} e
21963          */
21964         markerRightClick : true,
21965         /**
21966          * @event OverlayViewDraw
21967          * Fires when OverlayView Draw
21968          * @param {Roo.bootstrap.LocationPicker} this
21969          */
21970         OverlayViewDraw : true,
21971         /**
21972          * @event OverlayViewOnAdd
21973          * Fires when OverlayView Draw
21974          * @param {Roo.bootstrap.LocationPicker} this
21975          */
21976         OverlayViewOnAdd : true,
21977         /**
21978          * @event OverlayViewOnRemove
21979          * Fires when OverlayView Draw
21980          * @param {Roo.bootstrap.LocationPicker} this
21981          */
21982         OverlayViewOnRemove : true,
21983         /**
21984          * @event OverlayViewShow
21985          * Fires when OverlayView Draw
21986          * @param {Roo.bootstrap.LocationPicker} this
21987          * @param {Pixel} cpx
21988          */
21989         OverlayViewShow : true,
21990         /**
21991          * @event OverlayViewHide
21992          * Fires when OverlayView Draw
21993          * @param {Roo.bootstrap.LocationPicker} this
21994          */
21995         OverlayViewHide : true
21996     });
21997         
21998 };
21999
22000 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22001     
22002     gMapContext: false,
22003     
22004     latitude: 0,
22005     longitude: 0,
22006     zoom: 15,
22007     mapTypeId: false,
22008     mapTypeControl: false,
22009     disableDoubleClickZoom: false,
22010     scrollwheel: true,
22011     streetViewControl: false,
22012     radius: 0,
22013     locationName: '',
22014     draggable: true,
22015     enableAutocomplete: false,
22016     enableReverseGeocode: true,
22017     markerTitle: '',
22018     
22019     getAutoCreate: function()
22020     {
22021
22022         var cfg = {
22023             tag: 'div',
22024             cls: 'roo-location-picker'
22025         };
22026         
22027         return cfg
22028     },
22029     
22030     initEvents: function(ct, position)
22031     {       
22032         if(!this.el.getWidth() || this.isApplied()){
22033             return;
22034         }
22035         
22036         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22037         
22038         this.initial();
22039     },
22040     
22041     initial: function()
22042     {
22043         if(!this.mapTypeId){
22044             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22045         }
22046         
22047         this.gMapContext = this.GMapContext();
22048         
22049         this.initOverlayView();
22050         
22051         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22052         
22053         var _this = this;
22054                 
22055         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22056             _this.setPosition(_this.gMapContext.marker.position);
22057         });
22058         
22059         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22060             _this.fireEvent('mapClick', this, event);
22061             
22062         });
22063
22064         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22065             _this.fireEvent('mapRightClick', this, event);
22066             
22067         });
22068         
22069         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22070             _this.fireEvent('markerClick', this, event);
22071             
22072         });
22073
22074         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22075             _this.fireEvent('markerRightClick', this, event);
22076             
22077         });
22078         
22079         this.setPosition(this.gMapContext.location);
22080         
22081         this.fireEvent('initial', this, this.gMapContext.location);
22082     },
22083     
22084     initOverlayView: function()
22085     {
22086         var _this = this;
22087         
22088         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22089             
22090             draw: function()
22091             {
22092                 _this.fireEvent('OverlayViewDraw', _this);
22093             },
22094             
22095             onAdd: function()
22096             {
22097                 _this.fireEvent('OverlayViewOnAdd', _this);
22098             },
22099             
22100             onRemove: function()
22101             {
22102                 _this.fireEvent('OverlayViewOnRemove', _this);
22103             },
22104             
22105             show: function(cpx)
22106             {
22107                 _this.fireEvent('OverlayViewShow', _this, cpx);
22108             },
22109             
22110             hide: function()
22111             {
22112                 _this.fireEvent('OverlayViewHide', _this);
22113             }
22114             
22115         });
22116     },
22117     
22118     fromLatLngToContainerPixel: function(event)
22119     {
22120         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22121     },
22122     
22123     isApplied: function() 
22124     {
22125         return this.getGmapContext() == false ? false : true;
22126     },
22127     
22128     getGmapContext: function() 
22129     {
22130         return this.gMapContext
22131     },
22132     
22133     GMapContext: function() 
22134     {
22135         var _map = new google.maps.Map(this.el.dom, this);
22136         var _marker = new google.maps.Marker({
22137             position: new google.maps.LatLng(this.latitude, this.longitude),
22138             map: _map,
22139             title: this.markerTitle,
22140             draggable: this.draggable
22141         });
22142         
22143         return {
22144             map: _map,
22145             marker: _marker,
22146             circle: null,
22147             location: _marker.position,
22148             radius: this.radius,
22149             locationName: this.locationName,
22150             addressComponents: {
22151                 formatted_address: null,
22152                 addressLine1: null,
22153                 addressLine2: null,
22154                 streetName: null,
22155                 streetNumber: null,
22156                 city: null,
22157                 district: null,
22158                 state: null,
22159                 stateOrProvince: null
22160             },
22161             settings: this,
22162             domContainer: this.el.dom,
22163             geodecoder: new google.maps.Geocoder()
22164         };
22165     },
22166     
22167     drawCircle: function(center, radius, options) 
22168     {
22169         if (this.gMapContext.circle != null) {
22170             this.gMapContext.circle.setMap(null);
22171         }
22172         if (radius > 0) {
22173             radius *= 1;
22174             options = Roo.apply({}, options, {
22175                 strokeColor: "#0000FF",
22176                 strokeOpacity: .35,
22177                 strokeWeight: 2,
22178                 fillColor: "#0000FF",
22179                 fillOpacity: .2
22180             });
22181             
22182             options.map = this.gMapContext.map;
22183             options.radius = radius;
22184             options.center = center;
22185             this.gMapContext.circle = new google.maps.Circle(options);
22186             return this.gMapContext.circle;
22187         }
22188         
22189         return null;
22190     },
22191     
22192     setPosition: function(location) 
22193     {
22194         this.gMapContext.location = location;
22195         this.gMapContext.marker.setPosition(location);
22196         this.gMapContext.map.panTo(location);
22197         this.drawCircle(location, this.gMapContext.radius, {});
22198         
22199         var _this = this;
22200         
22201         if (this.gMapContext.settings.enableReverseGeocode) {
22202             this.gMapContext.geodecoder.geocode({
22203                 latLng: this.gMapContext.location
22204             }, function(results, status) {
22205                 
22206                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22207                     _this.gMapContext.locationName = results[0].formatted_address;
22208                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22209                     
22210                     _this.fireEvent('positionchanged', this, location);
22211                 }
22212             });
22213             
22214             return;
22215         }
22216         
22217         this.fireEvent('positionchanged', this, location);
22218     },
22219     
22220     resize: function()
22221     {
22222         google.maps.event.trigger(this.gMapContext.map, "resize");
22223         
22224         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22225         
22226         this.fireEvent('resize', this);
22227     },
22228     
22229     setPositionByLatLng: function(latitude, longitude)
22230     {
22231         this.setPosition(new google.maps.LatLng(latitude, longitude));
22232     },
22233     
22234     getCurrentPosition: function() 
22235     {
22236         return {
22237             latitude: this.gMapContext.location.lat(),
22238             longitude: this.gMapContext.location.lng()
22239         };
22240     },
22241     
22242     getAddressName: function() 
22243     {
22244         return this.gMapContext.locationName;
22245     },
22246     
22247     getAddressComponents: function() 
22248     {
22249         return this.gMapContext.addressComponents;
22250     },
22251     
22252     address_component_from_google_geocode: function(address_components) 
22253     {
22254         var result = {};
22255         
22256         for (var i = 0; i < address_components.length; i++) {
22257             var component = address_components[i];
22258             if (component.types.indexOf("postal_code") >= 0) {
22259                 result.postalCode = component.short_name;
22260             } else if (component.types.indexOf("street_number") >= 0) {
22261                 result.streetNumber = component.short_name;
22262             } else if (component.types.indexOf("route") >= 0) {
22263                 result.streetName = component.short_name;
22264             } else if (component.types.indexOf("neighborhood") >= 0) {
22265                 result.city = component.short_name;
22266             } else if (component.types.indexOf("locality") >= 0) {
22267                 result.city = component.short_name;
22268             } else if (component.types.indexOf("sublocality") >= 0) {
22269                 result.district = component.short_name;
22270             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22271                 result.stateOrProvince = component.short_name;
22272             } else if (component.types.indexOf("country") >= 0) {
22273                 result.country = component.short_name;
22274             }
22275         }
22276         
22277         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22278         result.addressLine2 = "";
22279         return result;
22280     },
22281     
22282     setZoomLevel: function(zoom)
22283     {
22284         this.gMapContext.map.setZoom(zoom);
22285     },
22286     
22287     show: function()
22288     {
22289         if(!this.el){
22290             return;
22291         }
22292         
22293         this.el.show();
22294         
22295         this.resize();
22296         
22297         this.fireEvent('show', this);
22298     },
22299     
22300     hide: function()
22301     {
22302         if(!this.el){
22303             return;
22304         }
22305         
22306         this.el.hide();
22307         
22308         this.fireEvent('hide', this);
22309     }
22310     
22311 });
22312
22313 Roo.apply(Roo.bootstrap.LocationPicker, {
22314     
22315     OverlayView : function(map, options)
22316     {
22317         options = options || {};
22318         
22319         this.setMap(map);
22320     }
22321     
22322     
22323 });/*
22324  * - LGPL
22325  *
22326  * Alert
22327  * 
22328  */
22329
22330 /**
22331  * @class Roo.bootstrap.Alert
22332  * @extends Roo.bootstrap.Component
22333  * Bootstrap Alert class
22334  * @cfg {String} title The title of alert
22335  * @cfg {String} html The content of alert
22336  * @cfg {String} weight (  success | info | warning | danger )
22337  * @cfg {String} faicon font-awesomeicon
22338  * 
22339  * @constructor
22340  * Create a new alert
22341  * @param {Object} config The config object
22342  */
22343
22344
22345 Roo.bootstrap.Alert = function(config){
22346     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22347     
22348 };
22349
22350 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22351     
22352     title: '',
22353     html: '',
22354     weight: false,
22355     faicon: false,
22356     
22357     getAutoCreate : function()
22358     {
22359         
22360         var cfg = {
22361             tag : 'div',
22362             cls : 'alert',
22363             cn : [
22364                 {
22365                     tag : 'i',
22366                     cls : 'roo-alert-icon'
22367                     
22368                 },
22369                 {
22370                     tag : 'b',
22371                     cls : 'roo-alert-title',
22372                     html : this.title
22373                 },
22374                 {
22375                     tag : 'span',
22376                     cls : 'roo-alert-text',
22377                     html : this.html
22378                 }
22379             ]
22380         };
22381         
22382         if(this.faicon){
22383             cfg.cn[0].cls += ' fa ' + this.faicon;
22384         }
22385         
22386         if(this.weight){
22387             cfg.cls += ' alert-' + this.weight;
22388         }
22389         
22390         return cfg;
22391     },
22392     
22393     initEvents: function() 
22394     {
22395         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22396     },
22397     
22398     setTitle : function(str)
22399     {
22400         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22401     },
22402     
22403     setText : function(str)
22404     {
22405         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22406     },
22407     
22408     setWeight : function(weight)
22409     {
22410         if(this.weight){
22411             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22412         }
22413         
22414         this.weight = weight;
22415         
22416         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22417     },
22418     
22419     setIcon : function(icon)
22420     {
22421         if(this.faicon){
22422             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22423         }
22424         
22425         this.faicon = icon
22426         
22427         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22428     },
22429     
22430     hide: function() 
22431     {
22432         this.el.hide();   
22433     },
22434     
22435     show: function() 
22436     {  
22437         this.el.show();   
22438     }
22439     
22440 });
22441
22442