buildSDK/dependancy_bootstrap.txt
[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         iter(this);
6921         return r;
6922         
6923         
6924         
6925         
6926     }
6927     
6928 });
6929
6930  
6931 /*
6932  * Based on:
6933  * Ext JS Library 1.1.1
6934  * Copyright(c) 2006-2007, Ext JS, LLC.
6935  *
6936  * Originally Released Under LGPL - original licence link has changed is not relivant.
6937  *
6938  * Fork - LGPL
6939  * <script type="text/javascript">
6940  */
6941 /**
6942  * @class Roo.form.VTypes
6943  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6944  * @singleton
6945  */
6946 Roo.form.VTypes = function(){
6947     // closure these in so they are only created once.
6948     var alpha = /^[a-zA-Z_]+$/;
6949     var alphanum = /^[a-zA-Z0-9_]+$/;
6950     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6951     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6952
6953     // All these messages and functions are configurable
6954     return {
6955         /**
6956          * The function used to validate email addresses
6957          * @param {String} value The email address
6958          */
6959         'email' : function(v){
6960             return email.test(v);
6961         },
6962         /**
6963          * The error text to display when the email validation function returns false
6964          * @type String
6965          */
6966         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6967         /**
6968          * The keystroke filter mask to be applied on email input
6969          * @type RegExp
6970          */
6971         'emailMask' : /[a-z0-9_\.\-@]/i,
6972
6973         /**
6974          * The function used to validate URLs
6975          * @param {String} value The URL
6976          */
6977         'url' : function(v){
6978             return url.test(v);
6979         },
6980         /**
6981          * The error text to display when the url validation function returns false
6982          * @type String
6983          */
6984         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6985         
6986         /**
6987          * The function used to validate alpha values
6988          * @param {String} value The value
6989          */
6990         'alpha' : function(v){
6991             return alpha.test(v);
6992         },
6993         /**
6994          * The error text to display when the alpha validation function returns false
6995          * @type String
6996          */
6997         'alphaText' : 'This field should only contain letters and _',
6998         /**
6999          * The keystroke filter mask to be applied on alpha input
7000          * @type RegExp
7001          */
7002         'alphaMask' : /[a-z_]/i,
7003
7004         /**
7005          * The function used to validate alphanumeric values
7006          * @param {String} value The value
7007          */
7008         'alphanum' : function(v){
7009             return alphanum.test(v);
7010         },
7011         /**
7012          * The error text to display when the alphanumeric validation function returns false
7013          * @type String
7014          */
7015         'alphanumText' : 'This field should only contain letters, numbers and _',
7016         /**
7017          * The keystroke filter mask to be applied on alphanumeric input
7018          * @type RegExp
7019          */
7020         'alphanumMask' : /[a-z0-9_]/i
7021     };
7022 }();/*
7023  * - LGPL
7024  *
7025  * Input
7026  * 
7027  */
7028
7029 /**
7030  * @class Roo.bootstrap.Input
7031  * @extends Roo.bootstrap.Component
7032  * Bootstrap Input class
7033  * @cfg {Boolean} disabled is it disabled
7034  * @cfg {String} fieldLabel - the label associated
7035  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7036  * @cfg {String} name name of the input
7037  * @cfg {string} fieldLabel - the label associated
7038  * @cfg {string}  inputType - input / file submit ...
7039  * @cfg {string} placeholder - placeholder to put in text.
7040  * @cfg {string}  before - input group add on before
7041  * @cfg {string} after - input group add on after
7042  * @cfg {string} size - (lg|sm) or leave empty..
7043  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7044  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7045  * @cfg {Number} md colspan out of 12 for computer-sized screens
7046  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7047  * @cfg {string} value default value of the input
7048  * @cfg {Number} labelWidth set the width of label (0-12)
7049  * @cfg {String} labelAlign (top|left)
7050  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7051  * @cfg {String} align (left|center|right) Default left
7052  * 
7053  * 
7054  * @constructor
7055  * Create a new Input
7056  * @param {Object} config The config object
7057  */
7058
7059 Roo.bootstrap.Input = function(config){
7060     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7061    
7062         this.addEvents({
7063             /**
7064              * @event focus
7065              * Fires when this field receives input focus.
7066              * @param {Roo.form.Field} this
7067              */
7068             focus : true,
7069             /**
7070              * @event blur
7071              * Fires when this field loses input focus.
7072              * @param {Roo.form.Field} this
7073              */
7074             blur : true,
7075             /**
7076              * @event specialkey
7077              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7078              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7079              * @param {Roo.form.Field} this
7080              * @param {Roo.EventObject} e The event object
7081              */
7082             specialkey : true,
7083             /**
7084              * @event change
7085              * Fires just before the field blurs if the field value has changed.
7086              * @param {Roo.form.Field} this
7087              * @param {Mixed} newValue The new value
7088              * @param {Mixed} oldValue The original value
7089              */
7090             change : true,
7091             /**
7092              * @event invalid
7093              * Fires after the field has been marked as invalid.
7094              * @param {Roo.form.Field} this
7095              * @param {String} msg The validation message
7096              */
7097             invalid : true,
7098             /**
7099              * @event valid
7100              * Fires after the field has been validated with no errors.
7101              * @param {Roo.form.Field} this
7102              */
7103             valid : true,
7104              /**
7105              * @event keyup
7106              * Fires after the key up
7107              * @param {Roo.form.Field} this
7108              * @param {Roo.EventObject}  e The event Object
7109              */
7110             keyup : true
7111         });
7112 };
7113
7114 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7115      /**
7116      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7117       automatic validation (defaults to "keyup").
7118      */
7119     validationEvent : "keyup",
7120      /**
7121      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7122      */
7123     validateOnBlur : true,
7124     /**
7125      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7126      */
7127     validationDelay : 250,
7128      /**
7129      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7130      */
7131     focusClass : "x-form-focus",  // not needed???
7132     
7133        
7134     /**
7135      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7136      */
7137     invalidClass : "has-error",
7138     
7139     /**
7140      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7141      */
7142     selectOnFocus : false,
7143     
7144      /**
7145      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7146      */
7147     maskRe : null,
7148        /**
7149      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7150      */
7151     vtype : null,
7152     
7153       /**
7154      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7155      */
7156     disableKeyFilter : false,
7157     
7158        /**
7159      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7160      */
7161     disabled : false,
7162      /**
7163      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7164      */
7165     allowBlank : true,
7166     /**
7167      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7168      */
7169     blankText : "This field is required",
7170     
7171      /**
7172      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7173      */
7174     minLength : 0,
7175     /**
7176      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7177      */
7178     maxLength : Number.MAX_VALUE,
7179     /**
7180      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7181      */
7182     minLengthText : "The minimum length for this field is {0}",
7183     /**
7184      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7185      */
7186     maxLengthText : "The maximum length for this field is {0}",
7187   
7188     
7189     /**
7190      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7191      * If available, this function will be called only after the basic validators all return true, and will be passed the
7192      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7193      */
7194     validator : null,
7195     /**
7196      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7197      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7198      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7199      */
7200     regex : null,
7201     /**
7202      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7203      */
7204     regexText : "",
7205     
7206     
7207     
7208     fieldLabel : '',
7209     inputType : 'text',
7210     
7211     name : false,
7212     placeholder: false,
7213     before : false,
7214     after : false,
7215     size : false,
7216     // private
7217     hasFocus : false,
7218     preventMark: false,
7219     isFormField : true,
7220     value : '',
7221     labelWidth : 2,
7222     labelAlign : false,
7223     readOnly : false,
7224     align : false,
7225     formatedValue : false,
7226     
7227     parentLabelAlign : function()
7228     {
7229         var parent = this;
7230         while (parent.parent()) {
7231             parent = parent.parent();
7232             if (typeof(parent.labelAlign) !='undefined') {
7233                 return parent.labelAlign;
7234             }
7235         }
7236         return 'left';
7237         
7238     },
7239     
7240     getAutoCreate : function(){
7241         
7242         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7243         
7244         var id = Roo.id();
7245         
7246         var cfg = {};
7247         
7248         if(this.inputType != 'hidden'){
7249             cfg.cls = 'form-group' //input-group
7250         }
7251         
7252         var input =  {
7253             tag: 'input',
7254             id : id,
7255             type : this.inputType,
7256             value : this.value,
7257             cls : 'form-control',
7258             placeholder : this.placeholder || ''
7259             
7260         };
7261         
7262         if(this.align){
7263             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7264         }
7265         
7266         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7267             input.maxLength = this.maxLength;
7268         }
7269         
7270         if (this.disabled) {
7271             input.disabled=true;
7272         }
7273         
7274         if (this.readOnly) {
7275             input.readonly=true;
7276         }
7277         
7278         if (this.name) {
7279             input.name = this.name;
7280         }
7281         if (this.size) {
7282             input.cls += ' input-' + this.size;
7283         }
7284         var settings=this;
7285         ['xs','sm','md','lg'].map(function(size){
7286             if (settings[size]) {
7287                 cfg.cls += ' col-' + size + '-' + settings[size];
7288             }
7289         });
7290         
7291         var inputblock = input;
7292         
7293         if (this.before || this.after) {
7294             
7295             inputblock = {
7296                 cls : 'input-group',
7297                 cn :  [] 
7298             };
7299             if (this.before && typeof(this.before) == 'string') {
7300                 
7301                 inputblock.cn.push({
7302                     tag :'span',
7303                     cls : 'roo-input-before input-group-addon',
7304                     html : this.before
7305                 });
7306             }
7307             if (this.before && typeof(this.before) == 'object') {
7308                 this.before = Roo.factory(this.before);
7309                 Roo.log(this.before);
7310                 inputblock.cn.push({
7311                     tag :'span',
7312                     cls : 'roo-input-before input-group-' +
7313                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7314                 });
7315             }
7316             
7317             inputblock.cn.push(input);
7318             
7319             if (this.after && typeof(this.after) == 'string') {
7320                 inputblock.cn.push({
7321                     tag :'span',
7322                     cls : 'roo-input-after input-group-addon',
7323                     html : this.after
7324                 });
7325             }
7326             if (this.after && typeof(this.after) == 'object') {
7327                 this.after = Roo.factory(this.after);
7328                 Roo.log(this.after);
7329                 inputblock.cn.push({
7330                     tag :'span',
7331                     cls : 'roo-input-after input-group-' +
7332                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7333                 });
7334             }
7335         };
7336         
7337         if (align ==='left' && this.fieldLabel.length) {
7338                 Roo.log("left and has label");
7339                 cfg.cn = [
7340                     
7341                     {
7342                         tag: 'label',
7343                         'for' :  id,
7344                         cls : 'control-label col-sm-' + this.labelWidth,
7345                         html : this.fieldLabel
7346                         
7347                     },
7348                     {
7349                         cls : "col-sm-" + (12 - this.labelWidth), 
7350                         cn: [
7351                             inputblock
7352                         ]
7353                     }
7354                     
7355                 ];
7356         } else if ( this.fieldLabel.length) {
7357                 Roo.log(" label");
7358                  cfg.cn = [
7359                    
7360                     {
7361                         tag: 'label',
7362                         //cls : 'input-group-addon',
7363                         html : this.fieldLabel
7364                         
7365                     },
7366                     
7367                     inputblock
7368                     
7369                 ];
7370
7371         } else {
7372             
7373                 Roo.log(" no label && no align");
7374                 cfg.cn = [
7375                     
7376                         inputblock
7377                     
7378                 ];
7379                 
7380                 
7381         };
7382         Roo.log('input-parentType: ' + this.parentType);
7383         
7384         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7385            cfg.cls += ' navbar-form';
7386            Roo.log(cfg);
7387         }
7388         
7389         return cfg;
7390         
7391     },
7392     /**
7393      * return the real input element.
7394      */
7395     inputEl: function ()
7396     {
7397         return this.el.select('input.form-control',true).first();
7398     },
7399     
7400     tooltipEl : function()
7401     {
7402         return this.inputEl();
7403     },
7404     
7405     setDisabled : function(v)
7406     {
7407         var i  = this.inputEl().dom;
7408         if (!v) {
7409             i.removeAttribute('disabled');
7410             return;
7411             
7412         }
7413         i.setAttribute('disabled','true');
7414     },
7415     initEvents : function()
7416     {
7417           
7418         this.inputEl().on("keydown" , this.fireKey,  this);
7419         this.inputEl().on("focus", this.onFocus,  this);
7420         this.inputEl().on("blur", this.onBlur,  this);
7421         
7422         this.inputEl().relayEvent('keyup', this);
7423
7424         // reference to original value for reset
7425         this.originalValue = this.getValue();
7426         //Roo.form.TextField.superclass.initEvents.call(this);
7427         if(this.validationEvent == 'keyup'){
7428             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7429             this.inputEl().on('keyup', this.filterValidation, this);
7430         }
7431         else if(this.validationEvent !== false){
7432             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7433         }
7434         
7435         if(this.selectOnFocus){
7436             this.on("focus", this.preFocus, this);
7437             
7438         }
7439         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7440             this.inputEl().on("keypress", this.filterKeys, this);
7441         }
7442        /* if(this.grow){
7443             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7444             this.el.on("click", this.autoSize,  this);
7445         }
7446         */
7447         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7448             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7449         }
7450         
7451         if (typeof(this.before) == 'object') {
7452             this.before.render(this.el.select('.roo-input-before',true).first());
7453         }
7454         if (typeof(this.after) == 'object') {
7455             this.after.render(this.el.select('.roo-input-after',true).first());
7456         }
7457         
7458         
7459     },
7460     filterValidation : function(e){
7461         if(!e.isNavKeyPress()){
7462             this.validationTask.delay(this.validationDelay);
7463         }
7464     },
7465      /**
7466      * Validates the field value
7467      * @return {Boolean} True if the value is valid, else false
7468      */
7469     validate : function(){
7470         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7471         if(this.disabled || this.validateValue(this.getRawValue())){
7472             this.clearInvalid();
7473             return true;
7474         }
7475         return false;
7476     },
7477     
7478     
7479     /**
7480      * Validates a value according to the field's validation rules and marks the field as invalid
7481      * if the validation fails
7482      * @param {Mixed} value The value to validate
7483      * @return {Boolean} True if the value is valid, else false
7484      */
7485     validateValue : function(value){
7486         if(value.length < 1)  { // if it's blank
7487              if(this.allowBlank){
7488                 this.clearInvalid();
7489                 return true;
7490              }else{
7491                 this.markInvalid(this.blankText);
7492                 return false;
7493              }
7494         }
7495         if(value.length < this.minLength){
7496             this.markInvalid(String.format(this.minLengthText, this.minLength));
7497             return false;
7498         }
7499         if(value.length > this.maxLength){
7500             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7501             return false;
7502         }
7503         if(this.vtype){
7504             var vt = Roo.form.VTypes;
7505             if(!vt[this.vtype](value, this)){
7506                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7507                 return false;
7508             }
7509         }
7510         if(typeof this.validator == "function"){
7511             var msg = this.validator(value);
7512             if(msg !== true){
7513                 this.markInvalid(msg);
7514                 return false;
7515             }
7516         }
7517         if(this.regex && !this.regex.test(value)){
7518             this.markInvalid(this.regexText);
7519             return false;
7520         }
7521         return true;
7522     },
7523
7524     
7525     
7526      // private
7527     fireKey : function(e){
7528         //Roo.log('field ' + e.getKey());
7529         if(e.isNavKeyPress()){
7530             this.fireEvent("specialkey", this, e);
7531         }
7532     },
7533     focus : function (selectText){
7534         if(this.rendered){
7535             this.inputEl().focus();
7536             if(selectText === true){
7537                 this.inputEl().dom.select();
7538             }
7539         }
7540         return this;
7541     } ,
7542     
7543     onFocus : function(){
7544         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7545            // this.el.addClass(this.focusClass);
7546         }
7547         if(!this.hasFocus){
7548             this.hasFocus = true;
7549             this.startValue = this.getValue();
7550             this.fireEvent("focus", this);
7551         }
7552     },
7553     
7554     beforeBlur : Roo.emptyFn,
7555
7556     
7557     // private
7558     onBlur : function(){
7559         this.beforeBlur();
7560         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7561             //this.el.removeClass(this.focusClass);
7562         }
7563         this.hasFocus = false;
7564         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7565             this.validate();
7566         }
7567         var v = this.getValue();
7568         if(String(v) !== String(this.startValue)){
7569             this.fireEvent('change', this, v, this.startValue);
7570         }
7571         this.fireEvent("blur", this);
7572     },
7573     
7574     /**
7575      * Resets the current field value to the originally loaded value and clears any validation messages
7576      */
7577     reset : function(){
7578         this.setValue(this.originalValue);
7579         this.clearInvalid();
7580     },
7581      /**
7582      * Returns the name of the field
7583      * @return {Mixed} name The name field
7584      */
7585     getName: function(){
7586         return this.name;
7587     },
7588      /**
7589      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7590      * @return {Mixed} value The field value
7591      */
7592     getValue : function(){
7593         
7594         var v = this.inputEl().getValue();
7595         
7596         return v;
7597     },
7598     /**
7599      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7600      * @return {Mixed} value The field value
7601      */
7602     getRawValue : function(){
7603         var v = this.inputEl().getValue();
7604         
7605         return v;
7606     },
7607     
7608     /**
7609      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7610      * @param {Mixed} value The value to set
7611      */
7612     setRawValue : function(v){
7613         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7614     },
7615     
7616     selectText : function(start, end){
7617         var v = this.getRawValue();
7618         if(v.length > 0){
7619             start = start === undefined ? 0 : start;
7620             end = end === undefined ? v.length : end;
7621             var d = this.inputEl().dom;
7622             if(d.setSelectionRange){
7623                 d.setSelectionRange(start, end);
7624             }else if(d.createTextRange){
7625                 var range = d.createTextRange();
7626                 range.moveStart("character", start);
7627                 range.moveEnd("character", v.length-end);
7628                 range.select();
7629             }
7630         }
7631     },
7632     
7633     /**
7634      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7635      * @param {Mixed} value The value to set
7636      */
7637     setValue : function(v){
7638         this.value = v;
7639         if(this.rendered){
7640             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7641             this.validate();
7642         }
7643     },
7644     
7645     /*
7646     processValue : function(value){
7647         if(this.stripCharsRe){
7648             var newValue = value.replace(this.stripCharsRe, '');
7649             if(newValue !== value){
7650                 this.setRawValue(newValue);
7651                 return newValue;
7652             }
7653         }
7654         return value;
7655     },
7656   */
7657     preFocus : function(){
7658         
7659         if(this.selectOnFocus){
7660             this.inputEl().dom.select();
7661         }
7662     },
7663     filterKeys : function(e){
7664         var k = e.getKey();
7665         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7666             return;
7667         }
7668         var c = e.getCharCode(), cc = String.fromCharCode(c);
7669         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7670             return;
7671         }
7672         if(!this.maskRe.test(cc)){
7673             e.stopEvent();
7674         }
7675     },
7676      /**
7677      * Clear any invalid styles/messages for this field
7678      */
7679     clearInvalid : function(){
7680         
7681         if(!this.el || this.preventMark){ // not rendered
7682             return;
7683         }
7684         this.el.removeClass(this.invalidClass);
7685         /*
7686         switch(this.msgTarget){
7687             case 'qtip':
7688                 this.el.dom.qtip = '';
7689                 break;
7690             case 'title':
7691                 this.el.dom.title = '';
7692                 break;
7693             case 'under':
7694                 if(this.errorEl){
7695                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7696                 }
7697                 break;
7698             case 'side':
7699                 if(this.errorIcon){
7700                     this.errorIcon.dom.qtip = '';
7701                     this.errorIcon.hide();
7702                     this.un('resize', this.alignErrorIcon, this);
7703                 }
7704                 break;
7705             default:
7706                 var t = Roo.getDom(this.msgTarget);
7707                 t.innerHTML = '';
7708                 t.style.display = 'none';
7709                 break;
7710         }
7711         */
7712         this.fireEvent('valid', this);
7713     },
7714      /**
7715      * Mark this field as invalid
7716      * @param {String} msg The validation message
7717      */
7718     markInvalid : function(msg){
7719         if(!this.el  || this.preventMark){ // not rendered
7720             return;
7721         }
7722         this.el.addClass(this.invalidClass);
7723         /*
7724         msg = msg || this.invalidText;
7725         switch(this.msgTarget){
7726             case 'qtip':
7727                 this.el.dom.qtip = msg;
7728                 this.el.dom.qclass = 'x-form-invalid-tip';
7729                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7730                     Roo.QuickTips.enable();
7731                 }
7732                 break;
7733             case 'title':
7734                 this.el.dom.title = msg;
7735                 break;
7736             case 'under':
7737                 if(!this.errorEl){
7738                     var elp = this.el.findParent('.x-form-element', 5, true);
7739                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7740                     this.errorEl.setWidth(elp.getWidth(true)-20);
7741                 }
7742                 this.errorEl.update(msg);
7743                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7744                 break;
7745             case 'side':
7746                 if(!this.errorIcon){
7747                     var elp = this.el.findParent('.x-form-element', 5, true);
7748                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7749                 }
7750                 this.alignErrorIcon();
7751                 this.errorIcon.dom.qtip = msg;
7752                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7753                 this.errorIcon.show();
7754                 this.on('resize', this.alignErrorIcon, this);
7755                 break;
7756             default:
7757                 var t = Roo.getDom(this.msgTarget);
7758                 t.innerHTML = msg;
7759                 t.style.display = this.msgDisplay;
7760                 break;
7761         }
7762         */
7763         this.fireEvent('invalid', this, msg);
7764     },
7765     // private
7766     SafariOnKeyDown : function(event)
7767     {
7768         // this is a workaround for a password hang bug on chrome/ webkit.
7769         
7770         var isSelectAll = false;
7771         
7772         if(this.inputEl().dom.selectionEnd > 0){
7773             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7774         }
7775         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7776             event.preventDefault();
7777             this.setValue('');
7778             return;
7779         }
7780         
7781         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7782             
7783             event.preventDefault();
7784             // this is very hacky as keydown always get's upper case.
7785             //
7786             var cc = String.fromCharCode(event.getCharCode());
7787             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7788             
7789         }
7790     },
7791     adjustWidth : function(tag, w){
7792         tag = tag.toLowerCase();
7793         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7794             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7795                 if(tag == 'input'){
7796                     return w + 2;
7797                 }
7798                 if(tag == 'textarea'){
7799                     return w-2;
7800                 }
7801             }else if(Roo.isOpera){
7802                 if(tag == 'input'){
7803                     return w + 2;
7804                 }
7805                 if(tag == 'textarea'){
7806                     return w-2;
7807                 }
7808             }
7809         }
7810         return w;
7811     }
7812     
7813 });
7814
7815  
7816 /*
7817  * - LGPL
7818  *
7819  * Input
7820  * 
7821  */
7822
7823 /**
7824  * @class Roo.bootstrap.TextArea
7825  * @extends Roo.bootstrap.Input
7826  * Bootstrap TextArea class
7827  * @cfg {Number} cols Specifies the visible width of a text area
7828  * @cfg {Number} rows Specifies the visible number of lines in a text area
7829  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7830  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7831  * @cfg {string} html text
7832  * 
7833  * @constructor
7834  * Create a new TextArea
7835  * @param {Object} config The config object
7836  */
7837
7838 Roo.bootstrap.TextArea = function(config){
7839     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7840    
7841 };
7842
7843 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7844      
7845     cols : false,
7846     rows : 5,
7847     readOnly : false,
7848     warp : 'soft',
7849     resize : false,
7850     value: false,
7851     html: false,
7852     
7853     getAutoCreate : function(){
7854         
7855         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7856         
7857         var id = Roo.id();
7858         
7859         var cfg = {};
7860         
7861         var input =  {
7862             tag: 'textarea',
7863             id : id,
7864             warp : this.warp,
7865             rows : this.rows,
7866             value : this.value || '',
7867             html: this.html || '',
7868             cls : 'form-control',
7869             placeholder : this.placeholder || '' 
7870             
7871         };
7872         
7873         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7874             input.maxLength = this.maxLength;
7875         }
7876         
7877         if(this.resize){
7878             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7879         }
7880         
7881         if(this.cols){
7882             input.cols = this.cols;
7883         }
7884         
7885         if (this.readOnly) {
7886             input.readonly = true;
7887         }
7888         
7889         if (this.name) {
7890             input.name = this.name;
7891         }
7892         
7893         if (this.size) {
7894             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7895         }
7896         
7897         var settings=this;
7898         ['xs','sm','md','lg'].map(function(size){
7899             if (settings[size]) {
7900                 cfg.cls += ' col-' + size + '-' + settings[size];
7901             }
7902         });
7903         
7904         var inputblock = input;
7905         
7906         if (this.before || this.after) {
7907             
7908             inputblock = {
7909                 cls : 'input-group',
7910                 cn :  [] 
7911             };
7912             if (this.before) {
7913                 inputblock.cn.push({
7914                     tag :'span',
7915                     cls : 'input-group-addon',
7916                     html : this.before
7917                 });
7918             }
7919             inputblock.cn.push(input);
7920             if (this.after) {
7921                 inputblock.cn.push({
7922                     tag :'span',
7923                     cls : 'input-group-addon',
7924                     html : this.after
7925                 });
7926             }
7927             
7928         }
7929         
7930         if (align ==='left' && this.fieldLabel.length) {
7931                 Roo.log("left and has label");
7932                 cfg.cn = [
7933                     
7934                     {
7935                         tag: 'label',
7936                         'for' :  id,
7937                         cls : 'control-label col-sm-' + this.labelWidth,
7938                         html : this.fieldLabel
7939                         
7940                     },
7941                     {
7942                         cls : "col-sm-" + (12 - this.labelWidth), 
7943                         cn: [
7944                             inputblock
7945                         ]
7946                     }
7947                     
7948                 ];
7949         } else if ( this.fieldLabel.length) {
7950                 Roo.log(" label");
7951                  cfg.cn = [
7952                    
7953                     {
7954                         tag: 'label',
7955                         //cls : 'input-group-addon',
7956                         html : this.fieldLabel
7957                         
7958                     },
7959                     
7960                     inputblock
7961                     
7962                 ];
7963
7964         } else {
7965             
7966                    Roo.log(" no label && no align");
7967                 cfg.cn = [
7968                     
7969                         inputblock
7970                     
7971                 ];
7972                 
7973                 
7974         }
7975         
7976         if (this.disabled) {
7977             input.disabled=true;
7978         }
7979         
7980         return cfg;
7981         
7982     },
7983     /**
7984      * return the real textarea element.
7985      */
7986     inputEl: function ()
7987     {
7988         return this.el.select('textarea.form-control',true).first();
7989     }
7990 });
7991
7992  
7993 /*
7994  * - LGPL
7995  *
7996  * trigger field - base class for combo..
7997  * 
7998  */
7999  
8000 /**
8001  * @class Roo.bootstrap.TriggerField
8002  * @extends Roo.bootstrap.Input
8003  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8004  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8005  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8006  * for which you can provide a custom implementation.  For example:
8007  * <pre><code>
8008 var trigger = new Roo.bootstrap.TriggerField();
8009 trigger.onTriggerClick = myTriggerFn;
8010 trigger.applyTo('my-field');
8011 </code></pre>
8012  *
8013  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8014  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8015  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8016  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8017  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8018
8019  * @constructor
8020  * Create a new TriggerField.
8021  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8022  * to the base TextField)
8023  */
8024 Roo.bootstrap.TriggerField = function(config){
8025     this.mimicing = false;
8026     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8027 };
8028
8029 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8030     /**
8031      * @cfg {String} triggerClass A CSS class to apply to the trigger
8032      */
8033      /**
8034      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8035      */
8036     hideTrigger:false,
8037
8038     /** @cfg {Boolean} grow @hide */
8039     /** @cfg {Number} growMin @hide */
8040     /** @cfg {Number} growMax @hide */
8041
8042     /**
8043      * @hide 
8044      * @method
8045      */
8046     autoSize: Roo.emptyFn,
8047     // private
8048     monitorTab : true,
8049     // private
8050     deferHeight : true,
8051
8052     
8053     actionMode : 'wrap',
8054     
8055     caret : false,
8056     
8057     
8058     getAutoCreate : function(){
8059        
8060         var align = this.labelAlign || this.parentLabelAlign();
8061         
8062         var id = Roo.id();
8063         
8064         var cfg = {
8065             cls: 'form-group' //input-group
8066         };
8067         
8068         
8069         var input =  {
8070             tag: 'input',
8071             id : id,
8072             type : this.inputType,
8073             cls : 'form-control',
8074             autocomplete: 'false',
8075             placeholder : this.placeholder || '' 
8076             
8077         };
8078         if (this.name) {
8079             input.name = this.name;
8080         }
8081         if (this.size) {
8082             input.cls += ' input-' + this.size;
8083         }
8084         
8085         if (this.disabled) {
8086             input.disabled=true;
8087         }
8088         
8089         var inputblock = input;
8090         
8091         if (this.before || this.after) {
8092             
8093             inputblock = {
8094                 cls : 'input-group',
8095                 cn :  [] 
8096             };
8097             if (this.before) {
8098                 inputblock.cn.push({
8099                     tag :'span',
8100                     cls : 'input-group-addon',
8101                     html : this.before
8102                 });
8103             }
8104             inputblock.cn.push(input);
8105             if (this.after) {
8106                 inputblock.cn.push({
8107                     tag :'span',
8108                     cls : 'input-group-addon',
8109                     html : this.after
8110                 });
8111             }
8112             
8113         };
8114         
8115         var box = {
8116             tag: 'div',
8117             cn: [
8118                 {
8119                     tag: 'input',
8120                     type : 'hidden',
8121                     cls: 'form-hidden-field'
8122                 },
8123                 inputblock
8124             ]
8125             
8126         };
8127         
8128         if(this.multiple){
8129             Roo.log('multiple');
8130             
8131             box = {
8132                 tag: 'div',
8133                 cn: [
8134                     {
8135                         tag: 'input',
8136                         type : 'hidden',
8137                         cls: 'form-hidden-field'
8138                     },
8139                     {
8140                         tag: 'ul',
8141                         cls: 'select2-choices',
8142                         cn:[
8143                             {
8144                                 tag: 'li',
8145                                 cls: 'select2-search-field',
8146                                 cn: [
8147
8148                                     inputblock
8149                                 ]
8150                             }
8151                         ]
8152                     }
8153                 ]
8154             }
8155         };
8156         
8157         var combobox = {
8158             cls: 'select2-container input-group',
8159             cn: [
8160                 box
8161 //                {
8162 //                    tag: 'ul',
8163 //                    cls: 'typeahead typeahead-long dropdown-menu',
8164 //                    style: 'display:none'
8165 //                }
8166             ]
8167         };
8168         
8169         if(!this.multiple && this.showToggleBtn){
8170             
8171             var caret = {
8172                         tag: 'span',
8173                         cls: 'caret'
8174              };
8175             if (this.caret != false) {
8176                 caret = {
8177                      tag: 'i',
8178                      cls: 'fa fa-' + this.caret
8179                 };
8180                 
8181             }
8182             
8183             combobox.cn.push({
8184                 tag :'span',
8185                 cls : 'input-group-addon btn dropdown-toggle',
8186                 cn : [
8187                     caret,
8188                     {
8189                         tag: 'span',
8190                         cls: 'combobox-clear',
8191                         cn  : [
8192                             {
8193                                 tag : 'i',
8194                                 cls: 'icon-remove'
8195                             }
8196                         ]
8197                     }
8198                 ]
8199
8200             })
8201         }
8202         
8203         if(this.multiple){
8204             combobox.cls += ' select2-container-multi';
8205         }
8206         
8207         if (align ==='left' && this.fieldLabel.length) {
8208             
8209                 Roo.log("left and has label");
8210                 cfg.cn = [
8211                     
8212                     {
8213                         tag: 'label',
8214                         'for' :  id,
8215                         cls : 'control-label col-sm-' + this.labelWidth,
8216                         html : this.fieldLabel
8217                         
8218                     },
8219                     {
8220                         cls : "col-sm-" + (12 - this.labelWidth), 
8221                         cn: [
8222                             combobox
8223                         ]
8224                     }
8225                     
8226                 ];
8227         } else if ( this.fieldLabel.length) {
8228                 Roo.log(" label");
8229                  cfg.cn = [
8230                    
8231                     {
8232                         tag: 'label',
8233                         //cls : 'input-group-addon',
8234                         html : this.fieldLabel
8235                         
8236                     },
8237                     
8238                     combobox
8239                     
8240                 ];
8241
8242         } else {
8243             
8244                 Roo.log(" no label && no align");
8245                 cfg = combobox
8246                      
8247                 
8248         }
8249          
8250         var settings=this;
8251         ['xs','sm','md','lg'].map(function(size){
8252             if (settings[size]) {
8253                 cfg.cls += ' col-' + size + '-' + settings[size];
8254             }
8255         });
8256         
8257         return cfg;
8258         
8259     },
8260     
8261     
8262     
8263     // private
8264     onResize : function(w, h){
8265 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8266 //        if(typeof w == 'number'){
8267 //            var x = w - this.trigger.getWidth();
8268 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8269 //            this.trigger.setStyle('left', x+'px');
8270 //        }
8271     },
8272
8273     // private
8274     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8275
8276     // private
8277     getResizeEl : function(){
8278         return this.inputEl();
8279     },
8280
8281     // private
8282     getPositionEl : function(){
8283         return this.inputEl();
8284     },
8285
8286     // private
8287     alignErrorIcon : function(){
8288         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8289     },
8290
8291     // private
8292     initEvents : function(){
8293         
8294         this.createList();
8295         
8296         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8297         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8298         if(!this.multiple && this.showToggleBtn){
8299             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8300             if(this.hideTrigger){
8301                 this.trigger.setDisplayed(false);
8302             }
8303             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8304         }
8305         
8306         if(this.multiple){
8307             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8308         }
8309         
8310         //this.trigger.addClassOnOver('x-form-trigger-over');
8311         //this.trigger.addClassOnClick('x-form-trigger-click');
8312         
8313         //if(!this.width){
8314         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8315         //}
8316     },
8317     
8318     createList : function()
8319     {
8320         this.list = Roo.get(document.body).createChild({
8321             tag: 'ul',
8322             cls: 'typeahead typeahead-long dropdown-menu',
8323             style: 'display:none'
8324         });
8325         
8326         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8327         
8328     },
8329
8330     // private
8331     initTrigger : function(){
8332        
8333     },
8334
8335     // private
8336     onDestroy : function(){
8337         if(this.trigger){
8338             this.trigger.removeAllListeners();
8339           //  this.trigger.remove();
8340         }
8341         //if(this.wrap){
8342         //    this.wrap.remove();
8343         //}
8344         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8345     },
8346
8347     // private
8348     onFocus : function(){
8349         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8350         /*
8351         if(!this.mimicing){
8352             this.wrap.addClass('x-trigger-wrap-focus');
8353             this.mimicing = true;
8354             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8355             if(this.monitorTab){
8356                 this.el.on("keydown", this.checkTab, this);
8357             }
8358         }
8359         */
8360     },
8361
8362     // private
8363     checkTab : function(e){
8364         if(e.getKey() == e.TAB){
8365             this.triggerBlur();
8366         }
8367     },
8368
8369     // private
8370     onBlur : function(){
8371         // do nothing
8372     },
8373
8374     // private
8375     mimicBlur : function(e, t){
8376         /*
8377         if(!this.wrap.contains(t) && this.validateBlur()){
8378             this.triggerBlur();
8379         }
8380         */
8381     },
8382
8383     // private
8384     triggerBlur : function(){
8385         this.mimicing = false;
8386         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8387         if(this.monitorTab){
8388             this.el.un("keydown", this.checkTab, this);
8389         }
8390         //this.wrap.removeClass('x-trigger-wrap-focus');
8391         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8392     },
8393
8394     // private
8395     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8396     validateBlur : function(e, t){
8397         return true;
8398     },
8399
8400     // private
8401     onDisable : function(){
8402         this.inputEl().dom.disabled = true;
8403         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8404         //if(this.wrap){
8405         //    this.wrap.addClass('x-item-disabled');
8406         //}
8407     },
8408
8409     // private
8410     onEnable : function(){
8411         this.inputEl().dom.disabled = false;
8412         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8413         //if(this.wrap){
8414         //    this.el.removeClass('x-item-disabled');
8415         //}
8416     },
8417
8418     // private
8419     onShow : function(){
8420         var ae = this.getActionEl();
8421         
8422         if(ae){
8423             ae.dom.style.display = '';
8424             ae.dom.style.visibility = 'visible';
8425         }
8426     },
8427
8428     // private
8429     
8430     onHide : function(){
8431         var ae = this.getActionEl();
8432         ae.dom.style.display = 'none';
8433     },
8434
8435     /**
8436      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8437      * by an implementing function.
8438      * @method
8439      * @param {EventObject} e
8440      */
8441     onTriggerClick : Roo.emptyFn
8442 });
8443  /*
8444  * Based on:
8445  * Ext JS Library 1.1.1
8446  * Copyright(c) 2006-2007, Ext JS, LLC.
8447  *
8448  * Originally Released Under LGPL - original licence link has changed is not relivant.
8449  *
8450  * Fork - LGPL
8451  * <script type="text/javascript">
8452  */
8453
8454
8455 /**
8456  * @class Roo.data.SortTypes
8457  * @singleton
8458  * Defines the default sorting (casting?) comparison functions used when sorting data.
8459  */
8460 Roo.data.SortTypes = {
8461     /**
8462      * Default sort that does nothing
8463      * @param {Mixed} s The value being converted
8464      * @return {Mixed} The comparison value
8465      */
8466     none : function(s){
8467         return s;
8468     },
8469     
8470     /**
8471      * The regular expression used to strip tags
8472      * @type {RegExp}
8473      * @property
8474      */
8475     stripTagsRE : /<\/?[^>]+>/gi,
8476     
8477     /**
8478      * Strips all HTML tags to sort on text only
8479      * @param {Mixed} s The value being converted
8480      * @return {String} The comparison value
8481      */
8482     asText : function(s){
8483         return String(s).replace(this.stripTagsRE, "");
8484     },
8485     
8486     /**
8487      * Strips all HTML tags to sort on text only - Case insensitive
8488      * @param {Mixed} s The value being converted
8489      * @return {String} The comparison value
8490      */
8491     asUCText : function(s){
8492         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8493     },
8494     
8495     /**
8496      * Case insensitive string
8497      * @param {Mixed} s The value being converted
8498      * @return {String} The comparison value
8499      */
8500     asUCString : function(s) {
8501         return String(s).toUpperCase();
8502     },
8503     
8504     /**
8505      * Date sorting
8506      * @param {Mixed} s The value being converted
8507      * @return {Number} The comparison value
8508      */
8509     asDate : function(s) {
8510         if(!s){
8511             return 0;
8512         }
8513         if(s instanceof Date){
8514             return s.getTime();
8515         }
8516         return Date.parse(String(s));
8517     },
8518     
8519     /**
8520      * Float sorting
8521      * @param {Mixed} s The value being converted
8522      * @return {Float} The comparison value
8523      */
8524     asFloat : function(s) {
8525         var val = parseFloat(String(s).replace(/,/g, ""));
8526         if(isNaN(val)) val = 0;
8527         return val;
8528     },
8529     
8530     /**
8531      * Integer sorting
8532      * @param {Mixed} s The value being converted
8533      * @return {Number} The comparison value
8534      */
8535     asInt : function(s) {
8536         var val = parseInt(String(s).replace(/,/g, ""));
8537         if(isNaN(val)) val = 0;
8538         return val;
8539     }
8540 };/*
8541  * Based on:
8542  * Ext JS Library 1.1.1
8543  * Copyright(c) 2006-2007, Ext JS, LLC.
8544  *
8545  * Originally Released Under LGPL - original licence link has changed is not relivant.
8546  *
8547  * Fork - LGPL
8548  * <script type="text/javascript">
8549  */
8550
8551 /**
8552 * @class Roo.data.Record
8553  * Instances of this class encapsulate both record <em>definition</em> information, and record
8554  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8555  * to access Records cached in an {@link Roo.data.Store} object.<br>
8556  * <p>
8557  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8558  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8559  * objects.<br>
8560  * <p>
8561  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8562  * @constructor
8563  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8564  * {@link #create}. The parameters are the same.
8565  * @param {Array} data An associative Array of data values keyed by the field name.
8566  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8567  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8568  * not specified an integer id is generated.
8569  */
8570 Roo.data.Record = function(data, id){
8571     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8572     this.data = data;
8573 };
8574
8575 /**
8576  * Generate a constructor for a specific record layout.
8577  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8578  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8579  * Each field definition object may contain the following properties: <ul>
8580  * <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,
8581  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8582  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8583  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8584  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8585  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8586  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8587  * this may be omitted.</p></li>
8588  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8589  * <ul><li>auto (Default, implies no conversion)</li>
8590  * <li>string</li>
8591  * <li>int</li>
8592  * <li>float</li>
8593  * <li>boolean</li>
8594  * <li>date</li></ul></p></li>
8595  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8596  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8597  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8598  * by the Reader into an object that will be stored in the Record. It is passed the
8599  * following parameters:<ul>
8600  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8601  * </ul></p></li>
8602  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8603  * </ul>
8604  * <br>usage:<br><pre><code>
8605 var TopicRecord = Roo.data.Record.create(
8606     {name: 'title', mapping: 'topic_title'},
8607     {name: 'author', mapping: 'username'},
8608     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8609     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8610     {name: 'lastPoster', mapping: 'user2'},
8611     {name: 'excerpt', mapping: 'post_text'}
8612 );
8613
8614 var myNewRecord = new TopicRecord({
8615     title: 'Do my job please',
8616     author: 'noobie',
8617     totalPosts: 1,
8618     lastPost: new Date(),
8619     lastPoster: 'Animal',
8620     excerpt: 'No way dude!'
8621 });
8622 myStore.add(myNewRecord);
8623 </code></pre>
8624  * @method create
8625  * @static
8626  */
8627 Roo.data.Record.create = function(o){
8628     var f = function(){
8629         f.superclass.constructor.apply(this, arguments);
8630     };
8631     Roo.extend(f, Roo.data.Record);
8632     var p = f.prototype;
8633     p.fields = new Roo.util.MixedCollection(false, function(field){
8634         return field.name;
8635     });
8636     for(var i = 0, len = o.length; i < len; i++){
8637         p.fields.add(new Roo.data.Field(o[i]));
8638     }
8639     f.getField = function(name){
8640         return p.fields.get(name);  
8641     };
8642     return f;
8643 };
8644
8645 Roo.data.Record.AUTO_ID = 1000;
8646 Roo.data.Record.EDIT = 'edit';
8647 Roo.data.Record.REJECT = 'reject';
8648 Roo.data.Record.COMMIT = 'commit';
8649
8650 Roo.data.Record.prototype = {
8651     /**
8652      * Readonly flag - true if this record has been modified.
8653      * @type Boolean
8654      */
8655     dirty : false,
8656     editing : false,
8657     error: null,
8658     modified: null,
8659
8660     // private
8661     join : function(store){
8662         this.store = store;
8663     },
8664
8665     /**
8666      * Set the named field to the specified value.
8667      * @param {String} name The name of the field to set.
8668      * @param {Object} value The value to set the field to.
8669      */
8670     set : function(name, value){
8671         if(this.data[name] == value){
8672             return;
8673         }
8674         this.dirty = true;
8675         if(!this.modified){
8676             this.modified = {};
8677         }
8678         if(typeof this.modified[name] == 'undefined'){
8679             this.modified[name] = this.data[name];
8680         }
8681         this.data[name] = value;
8682         if(!this.editing && this.store){
8683             this.store.afterEdit(this);
8684         }       
8685     },
8686
8687     /**
8688      * Get the value of the named field.
8689      * @param {String} name The name of the field to get the value of.
8690      * @return {Object} The value of the field.
8691      */
8692     get : function(name){
8693         return this.data[name]; 
8694     },
8695
8696     // private
8697     beginEdit : function(){
8698         this.editing = true;
8699         this.modified = {}; 
8700     },
8701
8702     // private
8703     cancelEdit : function(){
8704         this.editing = false;
8705         delete this.modified;
8706     },
8707
8708     // private
8709     endEdit : function(){
8710         this.editing = false;
8711         if(this.dirty && this.store){
8712             this.store.afterEdit(this);
8713         }
8714     },
8715
8716     /**
8717      * Usually called by the {@link Roo.data.Store} which owns the Record.
8718      * Rejects all changes made to the Record since either creation, or the last commit operation.
8719      * Modified fields are reverted to their original values.
8720      * <p>
8721      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8722      * of reject operations.
8723      */
8724     reject : function(){
8725         var m = this.modified;
8726         for(var n in m){
8727             if(typeof m[n] != "function"){
8728                 this.data[n] = m[n];
8729             }
8730         }
8731         this.dirty = false;
8732         delete this.modified;
8733         this.editing = false;
8734         if(this.store){
8735             this.store.afterReject(this);
8736         }
8737     },
8738
8739     /**
8740      * Usually called by the {@link Roo.data.Store} which owns the Record.
8741      * Commits all changes made to the Record since either creation, or the last commit operation.
8742      * <p>
8743      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8744      * of commit operations.
8745      */
8746     commit : function(){
8747         this.dirty = false;
8748         delete this.modified;
8749         this.editing = false;
8750         if(this.store){
8751             this.store.afterCommit(this);
8752         }
8753     },
8754
8755     // private
8756     hasError : function(){
8757         return this.error != null;
8758     },
8759
8760     // private
8761     clearError : function(){
8762         this.error = null;
8763     },
8764
8765     /**
8766      * Creates a copy of this record.
8767      * @param {String} id (optional) A new record id if you don't want to use this record's id
8768      * @return {Record}
8769      */
8770     copy : function(newId) {
8771         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8772     }
8773 };/*
8774  * Based on:
8775  * Ext JS Library 1.1.1
8776  * Copyright(c) 2006-2007, Ext JS, LLC.
8777  *
8778  * Originally Released Under LGPL - original licence link has changed is not relivant.
8779  *
8780  * Fork - LGPL
8781  * <script type="text/javascript">
8782  */
8783
8784
8785
8786 /**
8787  * @class Roo.data.Store
8788  * @extends Roo.util.Observable
8789  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8790  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8791  * <p>
8792  * 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
8793  * has no knowledge of the format of the data returned by the Proxy.<br>
8794  * <p>
8795  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8796  * instances from the data object. These records are cached and made available through accessor functions.
8797  * @constructor
8798  * Creates a new Store.
8799  * @param {Object} config A config object containing the objects needed for the Store to access data,
8800  * and read the data into Records.
8801  */
8802 Roo.data.Store = function(config){
8803     this.data = new Roo.util.MixedCollection(false);
8804     this.data.getKey = function(o){
8805         return o.id;
8806     };
8807     this.baseParams = {};
8808     // private
8809     this.paramNames = {
8810         "start" : "start",
8811         "limit" : "limit",
8812         "sort" : "sort",
8813         "dir" : "dir",
8814         "multisort" : "_multisort"
8815     };
8816
8817     if(config && config.data){
8818         this.inlineData = config.data;
8819         delete config.data;
8820     }
8821
8822     Roo.apply(this, config);
8823     
8824     if(this.reader){ // reader passed
8825         this.reader = Roo.factory(this.reader, Roo.data);
8826         this.reader.xmodule = this.xmodule || false;
8827         if(!this.recordType){
8828             this.recordType = this.reader.recordType;
8829         }
8830         if(this.reader.onMetaChange){
8831             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8832         }
8833     }
8834
8835     if(this.recordType){
8836         this.fields = this.recordType.prototype.fields;
8837     }
8838     this.modified = [];
8839
8840     this.addEvents({
8841         /**
8842          * @event datachanged
8843          * Fires when the data cache has changed, and a widget which is using this Store
8844          * as a Record cache should refresh its view.
8845          * @param {Store} this
8846          */
8847         datachanged : true,
8848         /**
8849          * @event metachange
8850          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8851          * @param {Store} this
8852          * @param {Object} meta The JSON metadata
8853          */
8854         metachange : true,
8855         /**
8856          * @event add
8857          * Fires when Records have been added to the Store
8858          * @param {Store} this
8859          * @param {Roo.data.Record[]} records The array of Records added
8860          * @param {Number} index The index at which the record(s) were added
8861          */
8862         add : true,
8863         /**
8864          * @event remove
8865          * Fires when a Record has been removed from the Store
8866          * @param {Store} this
8867          * @param {Roo.data.Record} record The Record that was removed
8868          * @param {Number} index The index at which the record was removed
8869          */
8870         remove : true,
8871         /**
8872          * @event update
8873          * Fires when a Record has been updated
8874          * @param {Store} this
8875          * @param {Roo.data.Record} record The Record that was updated
8876          * @param {String} operation The update operation being performed.  Value may be one of:
8877          * <pre><code>
8878  Roo.data.Record.EDIT
8879  Roo.data.Record.REJECT
8880  Roo.data.Record.COMMIT
8881          * </code></pre>
8882          */
8883         update : true,
8884         /**
8885          * @event clear
8886          * Fires when the data cache has been cleared.
8887          * @param {Store} this
8888          */
8889         clear : true,
8890         /**
8891          * @event beforeload
8892          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8893          * the load action will be canceled.
8894          * @param {Store} this
8895          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8896          */
8897         beforeload : true,
8898         /**
8899          * @event beforeloadadd
8900          * Fires after a new set of Records has been loaded.
8901          * @param {Store} this
8902          * @param {Roo.data.Record[]} records The Records that were loaded
8903          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8904          */
8905         beforeloadadd : true,
8906         /**
8907          * @event load
8908          * Fires after a new set of Records has been loaded, before they are added to the store.
8909          * @param {Store} this
8910          * @param {Roo.data.Record[]} records The Records that were loaded
8911          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8912          * @params {Object} return from reader
8913          */
8914         load : true,
8915         /**
8916          * @event loadexception
8917          * Fires if an exception occurs in the Proxy during loading.
8918          * Called with the signature of the Proxy's "loadexception" event.
8919          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8920          * 
8921          * @param {Proxy} 
8922          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8923          * @param {Object} load options 
8924          * @param {Object} jsonData from your request (normally this contains the Exception)
8925          */
8926         loadexception : true
8927     });
8928     
8929     if(this.proxy){
8930         this.proxy = Roo.factory(this.proxy, Roo.data);
8931         this.proxy.xmodule = this.xmodule || false;
8932         this.relayEvents(this.proxy,  ["loadexception"]);
8933     }
8934     this.sortToggle = {};
8935     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8936
8937     Roo.data.Store.superclass.constructor.call(this);
8938
8939     if(this.inlineData){
8940         this.loadData(this.inlineData);
8941         delete this.inlineData;
8942     }
8943 };
8944
8945 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8946      /**
8947     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8948     * without a remote query - used by combo/forms at present.
8949     */
8950     
8951     /**
8952     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8953     */
8954     /**
8955     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8956     */
8957     /**
8958     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8959     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8960     */
8961     /**
8962     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8963     * on any HTTP request
8964     */
8965     /**
8966     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8967     */
8968     /**
8969     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8970     */
8971     multiSort: false,
8972     /**
8973     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8974     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8975     */
8976     remoteSort : false,
8977
8978     /**
8979     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8980      * loaded or when a record is removed. (defaults to false).
8981     */
8982     pruneModifiedRecords : false,
8983
8984     // private
8985     lastOptions : null,
8986
8987     /**
8988      * Add Records to the Store and fires the add event.
8989      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8990      */
8991     add : function(records){
8992         records = [].concat(records);
8993         for(var i = 0, len = records.length; i < len; i++){
8994             records[i].join(this);
8995         }
8996         var index = this.data.length;
8997         this.data.addAll(records);
8998         this.fireEvent("add", this, records, index);
8999     },
9000
9001     /**
9002      * Remove a Record from the Store and fires the remove event.
9003      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9004      */
9005     remove : function(record){
9006         var index = this.data.indexOf(record);
9007         this.data.removeAt(index);
9008         if(this.pruneModifiedRecords){
9009             this.modified.remove(record);
9010         }
9011         this.fireEvent("remove", this, record, index);
9012     },
9013
9014     /**
9015      * Remove all Records from the Store and fires the clear event.
9016      */
9017     removeAll : function(){
9018         this.data.clear();
9019         if(this.pruneModifiedRecords){
9020             this.modified = [];
9021         }
9022         this.fireEvent("clear", this);
9023     },
9024
9025     /**
9026      * Inserts Records to the Store at the given index and fires the add event.
9027      * @param {Number} index The start index at which to insert the passed Records.
9028      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9029      */
9030     insert : function(index, records){
9031         records = [].concat(records);
9032         for(var i = 0, len = records.length; i < len; i++){
9033             this.data.insert(index, records[i]);
9034             records[i].join(this);
9035         }
9036         this.fireEvent("add", this, records, index);
9037     },
9038
9039     /**
9040      * Get the index within the cache of the passed Record.
9041      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9042      * @return {Number} The index of the passed Record. Returns -1 if not found.
9043      */
9044     indexOf : function(record){
9045         return this.data.indexOf(record);
9046     },
9047
9048     /**
9049      * Get the index within the cache of the Record with the passed id.
9050      * @param {String} id The id of the Record to find.
9051      * @return {Number} The index of the Record. Returns -1 if not found.
9052      */
9053     indexOfId : function(id){
9054         return this.data.indexOfKey(id);
9055     },
9056
9057     /**
9058      * Get the Record with the specified id.
9059      * @param {String} id The id of the Record to find.
9060      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9061      */
9062     getById : function(id){
9063         return this.data.key(id);
9064     },
9065
9066     /**
9067      * Get the Record at the specified index.
9068      * @param {Number} index The index of the Record to find.
9069      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9070      */
9071     getAt : function(index){
9072         return this.data.itemAt(index);
9073     },
9074
9075     /**
9076      * Returns a range of Records between specified indices.
9077      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9078      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9079      * @return {Roo.data.Record[]} An array of Records
9080      */
9081     getRange : function(start, end){
9082         return this.data.getRange(start, end);
9083     },
9084
9085     // private
9086     storeOptions : function(o){
9087         o = Roo.apply({}, o);
9088         delete o.callback;
9089         delete o.scope;
9090         this.lastOptions = o;
9091     },
9092
9093     /**
9094      * Loads the Record cache from the configured Proxy using the configured Reader.
9095      * <p>
9096      * If using remote paging, then the first load call must specify the <em>start</em>
9097      * and <em>limit</em> properties in the options.params property to establish the initial
9098      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9099      * <p>
9100      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9101      * and this call will return before the new data has been loaded. Perform any post-processing
9102      * in a callback function, or in a "load" event handler.</strong>
9103      * <p>
9104      * @param {Object} options An object containing properties which control loading options:<ul>
9105      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9106      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9107      * passed the following arguments:<ul>
9108      * <li>r : Roo.data.Record[]</li>
9109      * <li>options: Options object from the load call</li>
9110      * <li>success: Boolean success indicator</li></ul></li>
9111      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9112      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9113      * </ul>
9114      */
9115     load : function(options){
9116         options = options || {};
9117         if(this.fireEvent("beforeload", this, options) !== false){
9118             this.storeOptions(options);
9119             var p = Roo.apply(options.params || {}, this.baseParams);
9120             // if meta was not loaded from remote source.. try requesting it.
9121             if (!this.reader.metaFromRemote) {
9122                 p._requestMeta = 1;
9123             }
9124             if(this.sortInfo && this.remoteSort){
9125                 var pn = this.paramNames;
9126                 p[pn["sort"]] = this.sortInfo.field;
9127                 p[pn["dir"]] = this.sortInfo.direction;
9128             }
9129             if (this.multiSort) {
9130                 var pn = this.paramNames;
9131                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9132             }
9133             
9134             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9135         }
9136     },
9137
9138     /**
9139      * Reloads the Record cache from the configured Proxy using the configured Reader and
9140      * the options from the last load operation performed.
9141      * @param {Object} options (optional) An object containing properties which may override the options
9142      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9143      * the most recently used options are reused).
9144      */
9145     reload : function(options){
9146         this.load(Roo.applyIf(options||{}, this.lastOptions));
9147     },
9148
9149     // private
9150     // Called as a callback by the Reader during a load operation.
9151     loadRecords : function(o, options, success){
9152         if(!o || success === false){
9153             if(success !== false){
9154                 this.fireEvent("load", this, [], options, o);
9155             }
9156             if(options.callback){
9157                 options.callback.call(options.scope || this, [], options, false);
9158             }
9159             return;
9160         }
9161         // if data returned failure - throw an exception.
9162         if (o.success === false) {
9163             // show a message if no listener is registered.
9164             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9165                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9166             }
9167             // loadmask wil be hooked into this..
9168             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9169             return;
9170         }
9171         var r = o.records, t = o.totalRecords || r.length;
9172         
9173         this.fireEvent("beforeloadadd", this, r, options, o);
9174         
9175         if(!options || options.add !== true){
9176             if(this.pruneModifiedRecords){
9177                 this.modified = [];
9178             }
9179             for(var i = 0, len = r.length; i < len; i++){
9180                 r[i].join(this);
9181             }
9182             if(this.snapshot){
9183                 this.data = this.snapshot;
9184                 delete this.snapshot;
9185             }
9186             this.data.clear();
9187             this.data.addAll(r);
9188             this.totalLength = t;
9189             this.applySort();
9190             this.fireEvent("datachanged", this);
9191         }else{
9192             this.totalLength = Math.max(t, this.data.length+r.length);
9193             this.add(r);
9194         }
9195         this.fireEvent("load", this, r, options, o);
9196         if(options.callback){
9197             options.callback.call(options.scope || this, r, options, true);
9198         }
9199     },
9200
9201
9202     /**
9203      * Loads data from a passed data block. A Reader which understands the format of the data
9204      * must have been configured in the constructor.
9205      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9206      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9207      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9208      */
9209     loadData : function(o, append){
9210         var r = this.reader.readRecords(o);
9211         this.loadRecords(r, {add: append}, true);
9212     },
9213
9214     /**
9215      * Gets the number of cached records.
9216      * <p>
9217      * <em>If using paging, this may not be the total size of the dataset. If the data object
9218      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9219      * the data set size</em>
9220      */
9221     getCount : function(){
9222         return this.data.length || 0;
9223     },
9224
9225     /**
9226      * Gets the total number of records in the dataset as returned by the server.
9227      * <p>
9228      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9229      * the dataset size</em>
9230      */
9231     getTotalCount : function(){
9232         return this.totalLength || 0;
9233     },
9234
9235     /**
9236      * Returns the sort state of the Store as an object with two properties:
9237      * <pre><code>
9238  field {String} The name of the field by which the Records are sorted
9239  direction {String} The sort order, "ASC" or "DESC"
9240      * </code></pre>
9241      */
9242     getSortState : function(){
9243         return this.sortInfo;
9244     },
9245
9246     // private
9247     applySort : function(){
9248         if(this.sortInfo && !this.remoteSort){
9249             var s = this.sortInfo, f = s.field;
9250             var st = this.fields.get(f).sortType;
9251             var fn = function(r1, r2){
9252                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9253                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9254             };
9255             this.data.sort(s.direction, fn);
9256             if(this.snapshot && this.snapshot != this.data){
9257                 this.snapshot.sort(s.direction, fn);
9258             }
9259         }
9260     },
9261
9262     /**
9263      * Sets the default sort column and order to be used by the next load operation.
9264      * @param {String} fieldName The name of the field to sort by.
9265      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9266      */
9267     setDefaultSort : function(field, dir){
9268         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9269     },
9270
9271     /**
9272      * Sort the Records.
9273      * If remote sorting is used, the sort is performed on the server, and the cache is
9274      * reloaded. If local sorting is used, the cache is sorted internally.
9275      * @param {String} fieldName The name of the field to sort by.
9276      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9277      */
9278     sort : function(fieldName, dir){
9279         var f = this.fields.get(fieldName);
9280         if(!dir){
9281             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9282             
9283             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9284                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9285             }else{
9286                 dir = f.sortDir;
9287             }
9288         }
9289         this.sortToggle[f.name] = dir;
9290         this.sortInfo = {field: f.name, direction: dir};
9291         if(!this.remoteSort){
9292             this.applySort();
9293             this.fireEvent("datachanged", this);
9294         }else{
9295             this.load(this.lastOptions);
9296         }
9297     },
9298
9299     /**
9300      * Calls the specified function for each of the Records in the cache.
9301      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9302      * Returning <em>false</em> aborts and exits the iteration.
9303      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9304      */
9305     each : function(fn, scope){
9306         this.data.each(fn, scope);
9307     },
9308
9309     /**
9310      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9311      * (e.g., during paging).
9312      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9313      */
9314     getModifiedRecords : function(){
9315         return this.modified;
9316     },
9317
9318     // private
9319     createFilterFn : function(property, value, anyMatch){
9320         if(!value.exec){ // not a regex
9321             value = String(value);
9322             if(value.length == 0){
9323                 return false;
9324             }
9325             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9326         }
9327         return function(r){
9328             return value.test(r.data[property]);
9329         };
9330     },
9331
9332     /**
9333      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9334      * @param {String} property A field on your records
9335      * @param {Number} start The record index to start at (defaults to 0)
9336      * @param {Number} end The last record index to include (defaults to length - 1)
9337      * @return {Number} The sum
9338      */
9339     sum : function(property, start, end){
9340         var rs = this.data.items, v = 0;
9341         start = start || 0;
9342         end = (end || end === 0) ? end : rs.length-1;
9343
9344         for(var i = start; i <= end; i++){
9345             v += (rs[i].data[property] || 0);
9346         }
9347         return v;
9348     },
9349
9350     /**
9351      * Filter the records by a specified property.
9352      * @param {String} field A field on your records
9353      * @param {String/RegExp} value Either a string that the field
9354      * should start with or a RegExp to test against the field
9355      * @param {Boolean} anyMatch True to match any part not just the beginning
9356      */
9357     filter : function(property, value, anyMatch){
9358         var fn = this.createFilterFn(property, value, anyMatch);
9359         return fn ? this.filterBy(fn) : this.clearFilter();
9360     },
9361
9362     /**
9363      * Filter by a function. The specified function will be called with each
9364      * record in this data source. If the function returns true the record is included,
9365      * otherwise it is filtered.
9366      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9367      * @param {Object} scope (optional) The scope of the function (defaults to this)
9368      */
9369     filterBy : function(fn, scope){
9370         this.snapshot = this.snapshot || this.data;
9371         this.data = this.queryBy(fn, scope||this);
9372         this.fireEvent("datachanged", this);
9373     },
9374
9375     /**
9376      * Query the records by a specified property.
9377      * @param {String} field A field on your records
9378      * @param {String/RegExp} value Either a string that the field
9379      * should start with or a RegExp to test against the field
9380      * @param {Boolean} anyMatch True to match any part not just the beginning
9381      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9382      */
9383     query : function(property, value, anyMatch){
9384         var fn = this.createFilterFn(property, value, anyMatch);
9385         return fn ? this.queryBy(fn) : this.data.clone();
9386     },
9387
9388     /**
9389      * Query by a function. The specified function will be called with each
9390      * record in this data source. If the function returns true the record is included
9391      * in the results.
9392      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9393      * @param {Object} scope (optional) The scope of the function (defaults to this)
9394       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9395      **/
9396     queryBy : function(fn, scope){
9397         var data = this.snapshot || this.data;
9398         return data.filterBy(fn, scope||this);
9399     },
9400
9401     /**
9402      * Collects unique values for a particular dataIndex from this store.
9403      * @param {String} dataIndex The property to collect
9404      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9405      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9406      * @return {Array} An array of the unique values
9407      **/
9408     collect : function(dataIndex, allowNull, bypassFilter){
9409         var d = (bypassFilter === true && this.snapshot) ?
9410                 this.snapshot.items : this.data.items;
9411         var v, sv, r = [], l = {};
9412         for(var i = 0, len = d.length; i < len; i++){
9413             v = d[i].data[dataIndex];
9414             sv = String(v);
9415             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9416                 l[sv] = true;
9417                 r[r.length] = v;
9418             }
9419         }
9420         return r;
9421     },
9422
9423     /**
9424      * Revert to a view of the Record cache with no filtering applied.
9425      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9426      */
9427     clearFilter : function(suppressEvent){
9428         if(this.snapshot && this.snapshot != this.data){
9429             this.data = this.snapshot;
9430             delete this.snapshot;
9431             if(suppressEvent !== true){
9432                 this.fireEvent("datachanged", this);
9433             }
9434         }
9435     },
9436
9437     // private
9438     afterEdit : function(record){
9439         if(this.modified.indexOf(record) == -1){
9440             this.modified.push(record);
9441         }
9442         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9443     },
9444     
9445     // private
9446     afterReject : function(record){
9447         this.modified.remove(record);
9448         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9449     },
9450
9451     // private
9452     afterCommit : function(record){
9453         this.modified.remove(record);
9454         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9455     },
9456
9457     /**
9458      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9459      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9460      */
9461     commitChanges : function(){
9462         var m = this.modified.slice(0);
9463         this.modified = [];
9464         for(var i = 0, len = m.length; i < len; i++){
9465             m[i].commit();
9466         }
9467     },
9468
9469     /**
9470      * Cancel outstanding changes on all changed records.
9471      */
9472     rejectChanges : function(){
9473         var m = this.modified.slice(0);
9474         this.modified = [];
9475         for(var i = 0, len = m.length; i < len; i++){
9476             m[i].reject();
9477         }
9478     },
9479
9480     onMetaChange : function(meta, rtype, o){
9481         this.recordType = rtype;
9482         this.fields = rtype.prototype.fields;
9483         delete this.snapshot;
9484         this.sortInfo = meta.sortInfo || this.sortInfo;
9485         this.modified = [];
9486         this.fireEvent('metachange', this, this.reader.meta);
9487     },
9488     
9489     moveIndex : function(data, type)
9490     {
9491         var index = this.indexOf(data);
9492         
9493         var newIndex = index + type;
9494         
9495         this.remove(data);
9496         
9497         this.insert(newIndex, data);
9498         
9499     }
9500 });/*
9501  * Based on:
9502  * Ext JS Library 1.1.1
9503  * Copyright(c) 2006-2007, Ext JS, LLC.
9504  *
9505  * Originally Released Under LGPL - original licence link has changed is not relivant.
9506  *
9507  * Fork - LGPL
9508  * <script type="text/javascript">
9509  */
9510
9511 /**
9512  * @class Roo.data.SimpleStore
9513  * @extends Roo.data.Store
9514  * Small helper class to make creating Stores from Array data easier.
9515  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9516  * @cfg {Array} fields An array of field definition objects, or field name strings.
9517  * @cfg {Array} data The multi-dimensional array of data
9518  * @constructor
9519  * @param {Object} config
9520  */
9521 Roo.data.SimpleStore = function(config){
9522     Roo.data.SimpleStore.superclass.constructor.call(this, {
9523         isLocal : true,
9524         reader: new Roo.data.ArrayReader({
9525                 id: config.id
9526             },
9527             Roo.data.Record.create(config.fields)
9528         ),
9529         proxy : new Roo.data.MemoryProxy(config.data)
9530     });
9531     this.load();
9532 };
9533 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9534  * Based on:
9535  * Ext JS Library 1.1.1
9536  * Copyright(c) 2006-2007, Ext JS, LLC.
9537  *
9538  * Originally Released Under LGPL - original licence link has changed is not relivant.
9539  *
9540  * Fork - LGPL
9541  * <script type="text/javascript">
9542  */
9543
9544 /**
9545 /**
9546  * @extends Roo.data.Store
9547  * @class Roo.data.JsonStore
9548  * Small helper class to make creating Stores for JSON data easier. <br/>
9549 <pre><code>
9550 var store = new Roo.data.JsonStore({
9551     url: 'get-images.php',
9552     root: 'images',
9553     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9554 });
9555 </code></pre>
9556  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9557  * JsonReader and HttpProxy (unless inline data is provided).</b>
9558  * @cfg {Array} fields An array of field definition objects, or field name strings.
9559  * @constructor
9560  * @param {Object} config
9561  */
9562 Roo.data.JsonStore = function(c){
9563     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9564         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9565         reader: new Roo.data.JsonReader(c, c.fields)
9566     }));
9567 };
9568 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
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 Roo.data.Field = function(config){
9581     if(typeof config == "string"){
9582         config = {name: config};
9583     }
9584     Roo.apply(this, config);
9585     
9586     if(!this.type){
9587         this.type = "auto";
9588     }
9589     
9590     var st = Roo.data.SortTypes;
9591     // named sortTypes are supported, here we look them up
9592     if(typeof this.sortType == "string"){
9593         this.sortType = st[this.sortType];
9594     }
9595     
9596     // set default sortType for strings and dates
9597     if(!this.sortType){
9598         switch(this.type){
9599             case "string":
9600                 this.sortType = st.asUCString;
9601                 break;
9602             case "date":
9603                 this.sortType = st.asDate;
9604                 break;
9605             default:
9606                 this.sortType = st.none;
9607         }
9608     }
9609
9610     // define once
9611     var stripRe = /[\$,%]/g;
9612
9613     // prebuilt conversion function for this field, instead of
9614     // switching every time we're reading a value
9615     if(!this.convert){
9616         var cv, dateFormat = this.dateFormat;
9617         switch(this.type){
9618             case "":
9619             case "auto":
9620             case undefined:
9621                 cv = function(v){ return v; };
9622                 break;
9623             case "string":
9624                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9625                 break;
9626             case "int":
9627                 cv = function(v){
9628                     return v !== undefined && v !== null && v !== '' ?
9629                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9630                     };
9631                 break;
9632             case "float":
9633                 cv = function(v){
9634                     return v !== undefined && v !== null && v !== '' ?
9635                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9636                     };
9637                 break;
9638             case "bool":
9639             case "boolean":
9640                 cv = function(v){ return v === true || v === "true" || v == 1; };
9641                 break;
9642             case "date":
9643                 cv = function(v){
9644                     if(!v){
9645                         return '';
9646                     }
9647                     if(v instanceof Date){
9648                         return v;
9649                     }
9650                     if(dateFormat){
9651                         if(dateFormat == "timestamp"){
9652                             return new Date(v*1000);
9653                         }
9654                         return Date.parseDate(v, dateFormat);
9655                     }
9656                     var parsed = Date.parse(v);
9657                     return parsed ? new Date(parsed) : null;
9658                 };
9659              break;
9660             
9661         }
9662         this.convert = cv;
9663     }
9664 };
9665
9666 Roo.data.Field.prototype = {
9667     dateFormat: null,
9668     defaultValue: "",
9669     mapping: null,
9670     sortType : null,
9671     sortDir : "ASC"
9672 };/*
9673  * Based on:
9674  * Ext JS Library 1.1.1
9675  * Copyright(c) 2006-2007, Ext JS, LLC.
9676  *
9677  * Originally Released Under LGPL - original licence link has changed is not relivant.
9678  *
9679  * Fork - LGPL
9680  * <script type="text/javascript">
9681  */
9682  
9683 // Base class for reading structured data from a data source.  This class is intended to be
9684 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9685
9686 /**
9687  * @class Roo.data.DataReader
9688  * Base class for reading structured data from a data source.  This class is intended to be
9689  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9690  */
9691
9692 Roo.data.DataReader = function(meta, recordType){
9693     
9694     this.meta = meta;
9695     
9696     this.recordType = recordType instanceof Array ? 
9697         Roo.data.Record.create(recordType) : recordType;
9698 };
9699
9700 Roo.data.DataReader.prototype = {
9701      /**
9702      * Create an empty record
9703      * @param {Object} data (optional) - overlay some values
9704      * @return {Roo.data.Record} record created.
9705      */
9706     newRow :  function(d) {
9707         var da =  {};
9708         this.recordType.prototype.fields.each(function(c) {
9709             switch( c.type) {
9710                 case 'int' : da[c.name] = 0; break;
9711                 case 'date' : da[c.name] = new Date(); break;
9712                 case 'float' : da[c.name] = 0.0; break;
9713                 case 'boolean' : da[c.name] = false; break;
9714                 default : da[c.name] = ""; break;
9715             }
9716             
9717         });
9718         return new this.recordType(Roo.apply(da, d));
9719     }
9720     
9721 };/*
9722  * Based on:
9723  * Ext JS Library 1.1.1
9724  * Copyright(c) 2006-2007, Ext JS, LLC.
9725  *
9726  * Originally Released Under LGPL - original licence link has changed is not relivant.
9727  *
9728  * Fork - LGPL
9729  * <script type="text/javascript">
9730  */
9731
9732 /**
9733  * @class Roo.data.DataProxy
9734  * @extends Roo.data.Observable
9735  * This class is an abstract base class for implementations which provide retrieval of
9736  * unformatted data objects.<br>
9737  * <p>
9738  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9739  * (of the appropriate type which knows how to parse the data object) to provide a block of
9740  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9741  * <p>
9742  * Custom implementations must implement the load method as described in
9743  * {@link Roo.data.HttpProxy#load}.
9744  */
9745 Roo.data.DataProxy = function(){
9746     this.addEvents({
9747         /**
9748          * @event beforeload
9749          * Fires before a network request is made to retrieve a data object.
9750          * @param {Object} This DataProxy object.
9751          * @param {Object} params The params parameter to the load function.
9752          */
9753         beforeload : true,
9754         /**
9755          * @event load
9756          * Fires before the load method's callback is called.
9757          * @param {Object} This DataProxy object.
9758          * @param {Object} o The data object.
9759          * @param {Object} arg The callback argument object passed to the load function.
9760          */
9761         load : true,
9762         /**
9763          * @event loadexception
9764          * Fires if an Exception occurs during data retrieval.
9765          * @param {Object} This DataProxy object.
9766          * @param {Object} o The data object.
9767          * @param {Object} arg The callback argument object passed to the load function.
9768          * @param {Object} e The Exception.
9769          */
9770         loadexception : true
9771     });
9772     Roo.data.DataProxy.superclass.constructor.call(this);
9773 };
9774
9775 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9776
9777     /**
9778      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9779      */
9780 /*
9781  * Based on:
9782  * Ext JS Library 1.1.1
9783  * Copyright(c) 2006-2007, Ext JS, LLC.
9784  *
9785  * Originally Released Under LGPL - original licence link has changed is not relivant.
9786  *
9787  * Fork - LGPL
9788  * <script type="text/javascript">
9789  */
9790 /**
9791  * @class Roo.data.MemoryProxy
9792  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9793  * to the Reader when its load method is called.
9794  * @constructor
9795  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9796  */
9797 Roo.data.MemoryProxy = function(data){
9798     if (data.data) {
9799         data = data.data;
9800     }
9801     Roo.data.MemoryProxy.superclass.constructor.call(this);
9802     this.data = data;
9803 };
9804
9805 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9806     /**
9807      * Load data from the requested source (in this case an in-memory
9808      * data object passed to the constructor), read the data object into
9809      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9810      * process that block using the passed callback.
9811      * @param {Object} params This parameter is not used by the MemoryProxy class.
9812      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9813      * object into a block of Roo.data.Records.
9814      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9815      * The function must be passed <ul>
9816      * <li>The Record block object</li>
9817      * <li>The "arg" argument from the load function</li>
9818      * <li>A boolean success indicator</li>
9819      * </ul>
9820      * @param {Object} scope The scope in which to call the callback
9821      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9822      */
9823     load : function(params, reader, callback, scope, arg){
9824         params = params || {};
9825         var result;
9826         try {
9827             result = reader.readRecords(this.data);
9828         }catch(e){
9829             this.fireEvent("loadexception", this, arg, null, e);
9830             callback.call(scope, null, arg, false);
9831             return;
9832         }
9833         callback.call(scope, result, arg, true);
9834     },
9835     
9836     // private
9837     update : function(params, records){
9838         
9839     }
9840 });/*
9841  * Based on:
9842  * Ext JS Library 1.1.1
9843  * Copyright(c) 2006-2007, Ext JS, LLC.
9844  *
9845  * Originally Released Under LGPL - original licence link has changed is not relivant.
9846  *
9847  * Fork - LGPL
9848  * <script type="text/javascript">
9849  */
9850 /**
9851  * @class Roo.data.HttpProxy
9852  * @extends Roo.data.DataProxy
9853  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9854  * configured to reference a certain URL.<br><br>
9855  * <p>
9856  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9857  * from which the running page was served.<br><br>
9858  * <p>
9859  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9860  * <p>
9861  * Be aware that to enable the browser to parse an XML document, the server must set
9862  * the Content-Type header in the HTTP response to "text/xml".
9863  * @constructor
9864  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9865  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9866  * will be used to make the request.
9867  */
9868 Roo.data.HttpProxy = function(conn){
9869     Roo.data.HttpProxy.superclass.constructor.call(this);
9870     // is conn a conn config or a real conn?
9871     this.conn = conn;
9872     this.useAjax = !conn || !conn.events;
9873   
9874 };
9875
9876 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9877     // thse are take from connection...
9878     
9879     /**
9880      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9881      */
9882     /**
9883      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9884      * extra parameters to each request made by this object. (defaults to undefined)
9885      */
9886     /**
9887      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9888      *  to each request made by this object. (defaults to undefined)
9889      */
9890     /**
9891      * @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)
9892      */
9893     /**
9894      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9895      */
9896      /**
9897      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9898      * @type Boolean
9899      */
9900   
9901
9902     /**
9903      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9904      * @type Boolean
9905      */
9906     /**
9907      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9908      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9909      * a finer-grained basis than the DataProxy events.
9910      */
9911     getConnection : function(){
9912         return this.useAjax ? Roo.Ajax : this.conn;
9913     },
9914
9915     /**
9916      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9917      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9918      * process that block using the passed callback.
9919      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9920      * for the request to the remote server.
9921      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9922      * object into a block of Roo.data.Records.
9923      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9924      * The function must be passed <ul>
9925      * <li>The Record block object</li>
9926      * <li>The "arg" argument from the load function</li>
9927      * <li>A boolean success indicator</li>
9928      * </ul>
9929      * @param {Object} scope The scope in which to call the callback
9930      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9931      */
9932     load : function(params, reader, callback, scope, arg){
9933         if(this.fireEvent("beforeload", this, params) !== false){
9934             var  o = {
9935                 params : params || {},
9936                 request: {
9937                     callback : callback,
9938                     scope : scope,
9939                     arg : arg
9940                 },
9941                 reader: reader,
9942                 callback : this.loadResponse,
9943                 scope: this
9944             };
9945             if(this.useAjax){
9946                 Roo.applyIf(o, this.conn);
9947                 if(this.activeRequest){
9948                     Roo.Ajax.abort(this.activeRequest);
9949                 }
9950                 this.activeRequest = Roo.Ajax.request(o);
9951             }else{
9952                 this.conn.request(o);
9953             }
9954         }else{
9955             callback.call(scope||this, null, arg, false);
9956         }
9957     },
9958
9959     // private
9960     loadResponse : function(o, success, response){
9961         delete this.activeRequest;
9962         if(!success){
9963             this.fireEvent("loadexception", this, o, response);
9964             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9965             return;
9966         }
9967         var result;
9968         try {
9969             result = o.reader.read(response);
9970         }catch(e){
9971             this.fireEvent("loadexception", this, o, response, e);
9972             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9973             return;
9974         }
9975         
9976         this.fireEvent("load", this, o, o.request.arg);
9977         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9978     },
9979
9980     // private
9981     update : function(dataSet){
9982
9983     },
9984
9985     // private
9986     updateResponse : function(dataSet){
9987
9988     }
9989 });/*
9990  * Based on:
9991  * Ext JS Library 1.1.1
9992  * Copyright(c) 2006-2007, Ext JS, LLC.
9993  *
9994  * Originally Released Under LGPL - original licence link has changed is not relivant.
9995  *
9996  * Fork - LGPL
9997  * <script type="text/javascript">
9998  */
9999
10000 /**
10001  * @class Roo.data.ScriptTagProxy
10002  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10003  * other than the originating domain of the running page.<br><br>
10004  * <p>
10005  * <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
10006  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10007  * <p>
10008  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10009  * source code that is used as the source inside a &lt;script> tag.<br><br>
10010  * <p>
10011  * In order for the browser to process the returned data, the server must wrap the data object
10012  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10013  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10014  * depending on whether the callback name was passed:
10015  * <p>
10016  * <pre><code>
10017 boolean scriptTag = false;
10018 String cb = request.getParameter("callback");
10019 if (cb != null) {
10020     scriptTag = true;
10021     response.setContentType("text/javascript");
10022 } else {
10023     response.setContentType("application/x-json");
10024 }
10025 Writer out = response.getWriter();
10026 if (scriptTag) {
10027     out.write(cb + "(");
10028 }
10029 out.print(dataBlock.toJsonString());
10030 if (scriptTag) {
10031     out.write(");");
10032 }
10033 </pre></code>
10034  *
10035  * @constructor
10036  * @param {Object} config A configuration object.
10037  */
10038 Roo.data.ScriptTagProxy = function(config){
10039     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10040     Roo.apply(this, config);
10041     this.head = document.getElementsByTagName("head")[0];
10042 };
10043
10044 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10045
10046 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10047     /**
10048      * @cfg {String} url The URL from which to request the data object.
10049      */
10050     /**
10051      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10052      */
10053     timeout : 30000,
10054     /**
10055      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10056      * the server the name of the callback function set up by the load call to process the returned data object.
10057      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10058      * javascript output which calls this named function passing the data object as its only parameter.
10059      */
10060     callbackParam : "callback",
10061     /**
10062      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10063      * name to the request.
10064      */
10065     nocache : true,
10066
10067     /**
10068      * Load data from the configured URL, read the data object into
10069      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10070      * process that block using the passed callback.
10071      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10072      * for the request to the remote server.
10073      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10074      * object into a block of Roo.data.Records.
10075      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10076      * The function must be passed <ul>
10077      * <li>The Record block object</li>
10078      * <li>The "arg" argument from the load function</li>
10079      * <li>A boolean success indicator</li>
10080      * </ul>
10081      * @param {Object} scope The scope in which to call the callback
10082      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10083      */
10084     load : function(params, reader, callback, scope, arg){
10085         if(this.fireEvent("beforeload", this, params) !== false){
10086
10087             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10088
10089             var url = this.url;
10090             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10091             if(this.nocache){
10092                 url += "&_dc=" + (new Date().getTime());
10093             }
10094             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10095             var trans = {
10096                 id : transId,
10097                 cb : "stcCallback"+transId,
10098                 scriptId : "stcScript"+transId,
10099                 params : params,
10100                 arg : arg,
10101                 url : url,
10102                 callback : callback,
10103                 scope : scope,
10104                 reader : reader
10105             };
10106             var conn = this;
10107
10108             window[trans.cb] = function(o){
10109                 conn.handleResponse(o, trans);
10110             };
10111
10112             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10113
10114             if(this.autoAbort !== false){
10115                 this.abort();
10116             }
10117
10118             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10119
10120             var script = document.createElement("script");
10121             script.setAttribute("src", url);
10122             script.setAttribute("type", "text/javascript");
10123             script.setAttribute("id", trans.scriptId);
10124             this.head.appendChild(script);
10125
10126             this.trans = trans;
10127         }else{
10128             callback.call(scope||this, null, arg, false);
10129         }
10130     },
10131
10132     // private
10133     isLoading : function(){
10134         return this.trans ? true : false;
10135     },
10136
10137     /**
10138      * Abort the current server request.
10139      */
10140     abort : function(){
10141         if(this.isLoading()){
10142             this.destroyTrans(this.trans);
10143         }
10144     },
10145
10146     // private
10147     destroyTrans : function(trans, isLoaded){
10148         this.head.removeChild(document.getElementById(trans.scriptId));
10149         clearTimeout(trans.timeoutId);
10150         if(isLoaded){
10151             window[trans.cb] = undefined;
10152             try{
10153                 delete window[trans.cb];
10154             }catch(e){}
10155         }else{
10156             // if hasn't been loaded, wait for load to remove it to prevent script error
10157             window[trans.cb] = function(){
10158                 window[trans.cb] = undefined;
10159                 try{
10160                     delete window[trans.cb];
10161                 }catch(e){}
10162             };
10163         }
10164     },
10165
10166     // private
10167     handleResponse : function(o, trans){
10168         this.trans = false;
10169         this.destroyTrans(trans, true);
10170         var result;
10171         try {
10172             result = trans.reader.readRecords(o);
10173         }catch(e){
10174             this.fireEvent("loadexception", this, o, trans.arg, e);
10175             trans.callback.call(trans.scope||window, null, trans.arg, false);
10176             return;
10177         }
10178         this.fireEvent("load", this, o, trans.arg);
10179         trans.callback.call(trans.scope||window, result, trans.arg, true);
10180     },
10181
10182     // private
10183     handleFailure : function(trans){
10184         this.trans = false;
10185         this.destroyTrans(trans, false);
10186         this.fireEvent("loadexception", this, null, trans.arg);
10187         trans.callback.call(trans.scope||window, null, trans.arg, false);
10188     }
10189 });/*
10190  * Based on:
10191  * Ext JS Library 1.1.1
10192  * Copyright(c) 2006-2007, Ext JS, LLC.
10193  *
10194  * Originally Released Under LGPL - original licence link has changed is not relivant.
10195  *
10196  * Fork - LGPL
10197  * <script type="text/javascript">
10198  */
10199
10200 /**
10201  * @class Roo.data.JsonReader
10202  * @extends Roo.data.DataReader
10203  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10204  * based on mappings in a provided Roo.data.Record constructor.
10205  * 
10206  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10207  * in the reply previously. 
10208  * 
10209  * <p>
10210  * Example code:
10211  * <pre><code>
10212 var RecordDef = Roo.data.Record.create([
10213     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10214     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10215 ]);
10216 var myReader = new Roo.data.JsonReader({
10217     totalProperty: "results",    // The property which contains the total dataset size (optional)
10218     root: "rows",                // The property which contains an Array of row objects
10219     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10220 }, RecordDef);
10221 </code></pre>
10222  * <p>
10223  * This would consume a JSON file like this:
10224  * <pre><code>
10225 { 'results': 2, 'rows': [
10226     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10227     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10228 }
10229 </code></pre>
10230  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10231  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10232  * paged from the remote server.
10233  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10234  * @cfg {String} root name of the property which contains the Array of row objects.
10235  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10236  * @constructor
10237  * Create a new JsonReader
10238  * @param {Object} meta Metadata configuration options
10239  * @param {Object} recordType Either an Array of field definition objects,
10240  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10241  */
10242 Roo.data.JsonReader = function(meta, recordType){
10243     
10244     meta = meta || {};
10245     // set some defaults:
10246     Roo.applyIf(meta, {
10247         totalProperty: 'total',
10248         successProperty : 'success',
10249         root : 'data',
10250         id : 'id'
10251     });
10252     
10253     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10254 };
10255 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10256     
10257     /**
10258      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10259      * Used by Store query builder to append _requestMeta to params.
10260      * 
10261      */
10262     metaFromRemote : false,
10263     /**
10264      * This method is only used by a DataProxy which has retrieved data from a remote server.
10265      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10266      * @return {Object} data A data block which is used by an Roo.data.Store object as
10267      * a cache of Roo.data.Records.
10268      */
10269     read : function(response){
10270         var json = response.responseText;
10271        
10272         var o = /* eval:var:o */ eval("("+json+")");
10273         if(!o) {
10274             throw {message: "JsonReader.read: Json object not found"};
10275         }
10276         
10277         if(o.metaData){
10278             
10279             delete this.ef;
10280             this.metaFromRemote = true;
10281             this.meta = o.metaData;
10282             this.recordType = Roo.data.Record.create(o.metaData.fields);
10283             this.onMetaChange(this.meta, this.recordType, o);
10284         }
10285         return this.readRecords(o);
10286     },
10287
10288     // private function a store will implement
10289     onMetaChange : function(meta, recordType, o){
10290
10291     },
10292
10293     /**
10294          * @ignore
10295          */
10296     simpleAccess: function(obj, subsc) {
10297         return obj[subsc];
10298     },
10299
10300         /**
10301          * @ignore
10302          */
10303     getJsonAccessor: function(){
10304         var re = /[\[\.]/;
10305         return function(expr) {
10306             try {
10307                 return(re.test(expr))
10308                     ? new Function("obj", "return obj." + expr)
10309                     : function(obj){
10310                         return obj[expr];
10311                     };
10312             } catch(e){}
10313             return Roo.emptyFn;
10314         };
10315     }(),
10316
10317     /**
10318      * Create a data block containing Roo.data.Records from an XML document.
10319      * @param {Object} o An object which contains an Array of row objects in the property specified
10320      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10321      * which contains the total size of the dataset.
10322      * @return {Object} data A data block which is used by an Roo.data.Store object as
10323      * a cache of Roo.data.Records.
10324      */
10325     readRecords : function(o){
10326         /**
10327          * After any data loads, the raw JSON data is available for further custom processing.
10328          * @type Object
10329          */
10330         this.o = o;
10331         var s = this.meta, Record = this.recordType,
10332             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10333
10334 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10335         if (!this.ef) {
10336             if(s.totalProperty) {
10337                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10338                 }
10339                 if(s.successProperty) {
10340                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10341                 }
10342                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10343                 if (s.id) {
10344                         var g = this.getJsonAccessor(s.id);
10345                         this.getId = function(rec) {
10346                                 var r = g(rec);  
10347                                 return (r === undefined || r === "") ? null : r;
10348                         };
10349                 } else {
10350                         this.getId = function(){return null;};
10351                 }
10352             this.ef = [];
10353             for(var jj = 0; jj < fl; jj++){
10354                 f = fi[jj];
10355                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10356                 this.ef[jj] = this.getJsonAccessor(map);
10357             }
10358         }
10359
10360         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10361         if(s.totalProperty){
10362             var vt = parseInt(this.getTotal(o), 10);
10363             if(!isNaN(vt)){
10364                 totalRecords = vt;
10365             }
10366         }
10367         if(s.successProperty){
10368             var vs = this.getSuccess(o);
10369             if(vs === false || vs === 'false'){
10370                 success = false;
10371             }
10372         }
10373         var records = [];
10374         for(var i = 0; i < c; i++){
10375                 var n = root[i];
10376             var values = {};
10377             var id = this.getId(n);
10378             for(var j = 0; j < fl; j++){
10379                 f = fi[j];
10380             var v = this.ef[j](n);
10381             if (!f.convert) {
10382                 Roo.log('missing convert for ' + f.name);
10383                 Roo.log(f);
10384                 continue;
10385             }
10386             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10387             }
10388             var record = new Record(values, id);
10389             record.json = n;
10390             records[i] = record;
10391         }
10392         return {
10393             raw : o,
10394             success : success,
10395             records : records,
10396             totalRecords : totalRecords
10397         };
10398     }
10399 });/*
10400  * Based on:
10401  * Ext JS Library 1.1.1
10402  * Copyright(c) 2006-2007, Ext JS, LLC.
10403  *
10404  * Originally Released Under LGPL - original licence link has changed is not relivant.
10405  *
10406  * Fork - LGPL
10407  * <script type="text/javascript">
10408  */
10409
10410 /**
10411  * @class Roo.data.ArrayReader
10412  * @extends Roo.data.DataReader
10413  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10414  * Each element of that Array represents a row of data fields. The
10415  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10416  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10417  * <p>
10418  * Example code:.
10419  * <pre><code>
10420 var RecordDef = Roo.data.Record.create([
10421     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10422     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10423 ]);
10424 var myReader = new Roo.data.ArrayReader({
10425     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10426 }, RecordDef);
10427 </code></pre>
10428  * <p>
10429  * This would consume an Array like this:
10430  * <pre><code>
10431 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10432   </code></pre>
10433  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10434  * @constructor
10435  * Create a new JsonReader
10436  * @param {Object} meta Metadata configuration options.
10437  * @param {Object} recordType Either an Array of field definition objects
10438  * as specified to {@link Roo.data.Record#create},
10439  * or an {@link Roo.data.Record} object
10440  * created using {@link Roo.data.Record#create}.
10441  */
10442 Roo.data.ArrayReader = function(meta, recordType){
10443     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10444 };
10445
10446 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10447     /**
10448      * Create a data block containing Roo.data.Records from an XML document.
10449      * @param {Object} o An Array of row objects which represents the dataset.
10450      * @return {Object} data A data block which is used by an Roo.data.Store object as
10451      * a cache of Roo.data.Records.
10452      */
10453     readRecords : function(o){
10454         var sid = this.meta ? this.meta.id : null;
10455         var recordType = this.recordType, fields = recordType.prototype.fields;
10456         var records = [];
10457         var root = o;
10458             for(var i = 0; i < root.length; i++){
10459                     var n = root[i];
10460                 var values = {};
10461                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10462                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10463                 var f = fields.items[j];
10464                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10465                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10466                 v = f.convert(v);
10467                 values[f.name] = v;
10468             }
10469                 var record = new recordType(values, id);
10470                 record.json = n;
10471                 records[records.length] = record;
10472             }
10473             return {
10474                 records : records,
10475                 totalRecords : records.length
10476             };
10477     }
10478 });/*
10479  * - LGPL
10480  * * 
10481  */
10482
10483 /**
10484  * @class Roo.bootstrap.ComboBox
10485  * @extends Roo.bootstrap.TriggerField
10486  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10487  * @cfg {Boolean} append (true|false) default false
10488  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10489  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10490  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10491  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10492  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10493  * @constructor
10494  * Create a new ComboBox.
10495  * @param {Object} config Configuration options
10496  */
10497 Roo.bootstrap.ComboBox = function(config){
10498     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10499     this.addEvents({
10500         /**
10501          * @event expand
10502          * Fires when the dropdown list is expanded
10503              * @param {Roo.bootstrap.ComboBox} combo This combo box
10504              */
10505         'expand' : true,
10506         /**
10507          * @event collapse
10508          * Fires when the dropdown list is collapsed
10509              * @param {Roo.bootstrap.ComboBox} combo This combo box
10510              */
10511         'collapse' : true,
10512         /**
10513          * @event beforeselect
10514          * Fires before a list item is selected. Return false to cancel the selection.
10515              * @param {Roo.bootstrap.ComboBox} combo This combo box
10516              * @param {Roo.data.Record} record The data record returned from the underlying store
10517              * @param {Number} index The index of the selected item in the dropdown list
10518              */
10519         'beforeselect' : true,
10520         /**
10521          * @event select
10522          * Fires when a list item is selected
10523              * @param {Roo.bootstrap.ComboBox} combo This combo box
10524              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10525              * @param {Number} index The index of the selected item in the dropdown list
10526              */
10527         'select' : true,
10528         /**
10529          * @event beforequery
10530          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10531          * The event object passed has these properties:
10532              * @param {Roo.bootstrap.ComboBox} combo This combo box
10533              * @param {String} query The query
10534              * @param {Boolean} forceAll true to force "all" query
10535              * @param {Boolean} cancel true to cancel the query
10536              * @param {Object} e The query event object
10537              */
10538         'beforequery': true,
10539          /**
10540          * @event add
10541          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10542              * @param {Roo.bootstrap.ComboBox} combo This combo box
10543              */
10544         'add' : true,
10545         /**
10546          * @event edit
10547          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10548              * @param {Roo.bootstrap.ComboBox} combo This combo box
10549              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10550              */
10551         'edit' : true,
10552         /**
10553          * @event remove
10554          * Fires when the remove value from the combobox array
10555              * @param {Roo.bootstrap.ComboBox} combo This combo box
10556              */
10557         'remove' : true
10558         
10559     });
10560     
10561     this.item = [];
10562     this.tickItems = [];
10563     
10564     this.selectedIndex = -1;
10565     if(this.mode == 'local'){
10566         if(config.queryDelay === undefined){
10567             this.queryDelay = 10;
10568         }
10569         if(config.minChars === undefined){
10570             this.minChars = 0;
10571         }
10572     }
10573 };
10574
10575 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10576      
10577     /**
10578      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10579      * rendering into an Roo.Editor, defaults to false)
10580      */
10581     /**
10582      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10583      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10584      */
10585     /**
10586      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10587      */
10588     /**
10589      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10590      * the dropdown list (defaults to undefined, with no header element)
10591      */
10592
10593      /**
10594      * @cfg {String/Roo.Template} tpl The template to use to render the output
10595      */
10596      
10597      /**
10598      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10599      */
10600     listWidth: undefined,
10601     /**
10602      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10603      * mode = 'remote' or 'text' if mode = 'local')
10604      */
10605     displayField: undefined,
10606     /**
10607      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10608      * mode = 'remote' or 'value' if mode = 'local'). 
10609      * Note: use of a valueField requires the user make a selection
10610      * in order for a value to be mapped.
10611      */
10612     valueField: undefined,
10613     
10614     
10615     /**
10616      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10617      * field's data value (defaults to the underlying DOM element's name)
10618      */
10619     hiddenName: undefined,
10620     /**
10621      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10622      */
10623     listClass: '',
10624     /**
10625      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10626      */
10627     selectedClass: 'active',
10628     
10629     /**
10630      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10631      */
10632     shadow:'sides',
10633     /**
10634      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10635      * anchor positions (defaults to 'tl-bl')
10636      */
10637     listAlign: 'tl-bl?',
10638     /**
10639      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10640      */
10641     maxHeight: 300,
10642     /**
10643      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10644      * query specified by the allQuery config option (defaults to 'query')
10645      */
10646     triggerAction: 'query',
10647     /**
10648      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10649      * (defaults to 4, does not apply if editable = false)
10650      */
10651     minChars : 4,
10652     /**
10653      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10654      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10655      */
10656     typeAhead: false,
10657     /**
10658      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10659      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10660      */
10661     queryDelay: 500,
10662     /**
10663      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10664      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10665      */
10666     pageSize: 0,
10667     /**
10668      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10669      * when editable = true (defaults to false)
10670      */
10671     selectOnFocus:false,
10672     /**
10673      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10674      */
10675     queryParam: 'query',
10676     /**
10677      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10678      * when mode = 'remote' (defaults to 'Loading...')
10679      */
10680     loadingText: 'Loading...',
10681     /**
10682      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10683      */
10684     resizable: false,
10685     /**
10686      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10687      */
10688     handleHeight : 8,
10689     /**
10690      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10691      * traditional select (defaults to true)
10692      */
10693     editable: true,
10694     /**
10695      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10696      */
10697     allQuery: '',
10698     /**
10699      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10700      */
10701     mode: 'remote',
10702     /**
10703      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10704      * listWidth has a higher value)
10705      */
10706     minListWidth : 70,
10707     /**
10708      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10709      * allow the user to set arbitrary text into the field (defaults to false)
10710      */
10711     forceSelection:false,
10712     /**
10713      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10714      * if typeAhead = true (defaults to 250)
10715      */
10716     typeAheadDelay : 250,
10717     /**
10718      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10719      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10720      */
10721     valueNotFoundText : undefined,
10722     /**
10723      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10724      */
10725     blockFocus : false,
10726     
10727     /**
10728      * @cfg {Boolean} disableClear Disable showing of clear button.
10729      */
10730     disableClear : false,
10731     /**
10732      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10733      */
10734     alwaysQuery : false,
10735     
10736     /**
10737      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10738      */
10739     multiple : false,
10740     
10741     //private
10742     addicon : false,
10743     editicon: false,
10744     
10745     page: 0,
10746     hasQuery: false,
10747     append: false,
10748     loadNext: false,
10749     autoFocus : true,
10750     tickable : false,
10751     btnPosition : 'right',
10752     triggerList : true,
10753     showToggleBtn : true,
10754     // element that contains real text value.. (when hidden is used..)
10755     
10756     getAutoCreate : function()
10757     {
10758         var cfg = false;
10759         
10760         /*
10761          *  Normal ComboBox
10762          */
10763         if(!this.tickable){
10764             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10765             return cfg;
10766         }
10767         
10768         /*
10769          *  ComboBox with tickable selections
10770          */
10771              
10772         var align = this.labelAlign || this.parentLabelAlign();
10773         
10774         cfg = {
10775             cls : 'form-group roo-combobox-tickable' //input-group
10776         };
10777         
10778         
10779         var buttons = {
10780             tag : 'div',
10781             cls : 'tickable-buttons',
10782             cn : [
10783                 {
10784                     tag : 'button',
10785                     type : 'button',
10786                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10787                     html : 'Edit'
10788                 },
10789                 {
10790                     tag : 'button',
10791                     type : 'button',
10792                     name : 'ok',
10793                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10794                     html : 'Done'
10795                 },
10796                 {
10797                     tag : 'button',
10798                     type : 'button',
10799                     name : 'cancel',
10800                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10801                     html : 'Cancel'
10802                 }
10803             ]
10804         };
10805         
10806         var _this = this;
10807         Roo.each(buttons.cn, function(c){
10808             if (_this.size) {
10809                 c.cls += ' btn-' + _this.size;
10810             }
10811
10812             if (_this.disabled) {
10813                 c.disabled = true;
10814             }
10815         });
10816         
10817         var box = {
10818             tag: 'div',
10819             cn: [
10820                 {
10821                     tag: 'input',
10822                     type : 'hidden',
10823                     cls: 'form-hidden-field'
10824                 },
10825                 {
10826                     tag: 'ul',
10827                     cls: 'select2-choices',
10828                     cn:[
10829                         {
10830                             tag: 'li',
10831                             cls: 'select2-search-field',
10832                             cn: [
10833
10834                                 buttons
10835                             ]
10836                         }
10837                     ]
10838                 }
10839             ]
10840         }
10841         
10842         var combobox = {
10843             cls: 'select2-container input-group select2-container-multi',
10844             cn: [
10845                 box
10846 //                {
10847 //                    tag: 'ul',
10848 //                    cls: 'typeahead typeahead-long dropdown-menu',
10849 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
10850 //                }
10851             ]
10852         };
10853         
10854         if (align ==='left' && this.fieldLabel.length) {
10855             
10856                 Roo.log("left and has label");
10857                 cfg.cn = [
10858                     
10859                     {
10860                         tag: 'label',
10861                         'for' :  id,
10862                         cls : 'control-label col-sm-' + this.labelWidth,
10863                         html : this.fieldLabel
10864                         
10865                     },
10866                     {
10867                         cls : "col-sm-" + (12 - this.labelWidth), 
10868                         cn: [
10869                             combobox
10870                         ]
10871                     }
10872                     
10873                 ];
10874         } else if ( this.fieldLabel.length) {
10875                 Roo.log(" label");
10876                  cfg.cn = [
10877                    
10878                     {
10879                         tag: 'label',
10880                         //cls : 'input-group-addon',
10881                         html : this.fieldLabel
10882                         
10883                     },
10884                     
10885                     combobox
10886                     
10887                 ];
10888
10889         } else {
10890             
10891                 Roo.log(" no label && no align");
10892                 cfg = combobox
10893                      
10894                 
10895         }
10896          
10897         var settings=this;
10898         ['xs','sm','md','lg'].map(function(size){
10899             if (settings[size]) {
10900                 cfg.cls += ' col-' + size + '-' + settings[size];
10901             }
10902         });
10903         
10904         return cfg;
10905         
10906     },
10907     
10908     // private
10909     initEvents: function()
10910     {
10911         
10912         if (!this.store) {
10913             throw "can not find store for combo";
10914         }
10915         this.store = Roo.factory(this.store, Roo.data);
10916         
10917         if(this.tickable){
10918             this.initTickableEvents();
10919             return;
10920         }
10921         
10922         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10923         
10924         if(this.hiddenName){
10925             
10926             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10927             
10928             this.hiddenField.dom.value =
10929                 this.hiddenValue !== undefined ? this.hiddenValue :
10930                 this.value !== undefined ? this.value : '';
10931
10932             // prevent input submission
10933             this.el.dom.removeAttribute('name');
10934             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10935              
10936              
10937         }
10938         //if(Roo.isGecko){
10939         //    this.el.dom.setAttribute('autocomplete', 'off');
10940         //}
10941         
10942         var cls = 'x-combo-list';
10943         
10944         //this.list = new Roo.Layer({
10945         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10946         //});
10947         
10948         var _this = this;
10949         
10950         (function(){
10951             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10952             _this.list.setWidth(lw);
10953         }).defer(100);
10954         
10955         this.list.on('mouseover', this.onViewOver, this);
10956         this.list.on('mousemove', this.onViewMove, this);
10957         
10958         this.list.on('scroll', this.onViewScroll, this);
10959         
10960         /*
10961         this.list.swallowEvent('mousewheel');
10962         this.assetHeight = 0;
10963
10964         if(this.title){
10965             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10966             this.assetHeight += this.header.getHeight();
10967         }
10968
10969         this.innerList = this.list.createChild({cls:cls+'-inner'});
10970         this.innerList.on('mouseover', this.onViewOver, this);
10971         this.innerList.on('mousemove', this.onViewMove, this);
10972         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10973         
10974         if(this.allowBlank && !this.pageSize && !this.disableClear){
10975             this.footer = this.list.createChild({cls:cls+'-ft'});
10976             this.pageTb = new Roo.Toolbar(this.footer);
10977            
10978         }
10979         if(this.pageSize){
10980             this.footer = this.list.createChild({cls:cls+'-ft'});
10981             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10982                     {pageSize: this.pageSize});
10983             
10984         }
10985         
10986         if (this.pageTb && this.allowBlank && !this.disableClear) {
10987             var _this = this;
10988             this.pageTb.add(new Roo.Toolbar.Fill(), {
10989                 cls: 'x-btn-icon x-btn-clear',
10990                 text: '&#160;',
10991                 handler: function()
10992                 {
10993                     _this.collapse();
10994                     _this.clearValue();
10995                     _this.onSelect(false, -1);
10996                 }
10997             });
10998         }
10999         if (this.footer) {
11000             this.assetHeight += this.footer.getHeight();
11001         }
11002         */
11003             
11004         if(!this.tpl){
11005             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11006         }
11007
11008         this.view = new Roo.View(this.list, this.tpl, {
11009             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11010         });
11011         //this.view.wrapEl.setDisplayed(false);
11012         this.view.on('click', this.onViewClick, this);
11013         
11014         
11015         
11016         this.store.on('beforeload', this.onBeforeLoad, this);
11017         this.store.on('load', this.onLoad, this);
11018         this.store.on('loadexception', this.onLoadException, this);
11019         /*
11020         if(this.resizable){
11021             this.resizer = new Roo.Resizable(this.list,  {
11022                pinned:true, handles:'se'
11023             });
11024             this.resizer.on('resize', function(r, w, h){
11025                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11026                 this.listWidth = w;
11027                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11028                 this.restrictHeight();
11029             }, this);
11030             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11031         }
11032         */
11033         if(!this.editable){
11034             this.editable = true;
11035             this.setEditable(false);
11036         }
11037         
11038         /*
11039         
11040         if (typeof(this.events.add.listeners) != 'undefined') {
11041             
11042             this.addicon = this.wrap.createChild(
11043                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11044        
11045             this.addicon.on('click', function(e) {
11046                 this.fireEvent('add', this);
11047             }, this);
11048         }
11049         if (typeof(this.events.edit.listeners) != 'undefined') {
11050             
11051             this.editicon = this.wrap.createChild(
11052                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11053             if (this.addicon) {
11054                 this.editicon.setStyle('margin-left', '40px');
11055             }
11056             this.editicon.on('click', function(e) {
11057                 
11058                 // we fire even  if inothing is selected..
11059                 this.fireEvent('edit', this, this.lastData );
11060                 
11061             }, this);
11062         }
11063         */
11064         
11065         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11066             "up" : function(e){
11067                 this.inKeyMode = true;
11068                 this.selectPrev();
11069             },
11070
11071             "down" : function(e){
11072                 if(!this.isExpanded()){
11073                     this.onTriggerClick();
11074                 }else{
11075                     this.inKeyMode = true;
11076                     this.selectNext();
11077                 }
11078             },
11079
11080             "enter" : function(e){
11081 //                this.onViewClick();
11082                 //return true;
11083                 this.collapse();
11084                 
11085                 if(this.fireEvent("specialkey", this, e)){
11086                     this.onViewClick(false);
11087                 }
11088                 
11089                 return true;
11090             },
11091
11092             "esc" : function(e){
11093                 this.collapse();
11094             },
11095
11096             "tab" : function(e){
11097                 this.collapse();
11098                 
11099                 if(this.fireEvent("specialkey", this, e)){
11100                     this.onViewClick(false);
11101                 }
11102                 
11103                 return true;
11104             },
11105
11106             scope : this,
11107
11108             doRelay : function(foo, bar, hname){
11109                 if(hname == 'down' || this.scope.isExpanded()){
11110                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11111                 }
11112                 return true;
11113             },
11114
11115             forceKeyDown: true
11116         });
11117         
11118         
11119         this.queryDelay = Math.max(this.queryDelay || 10,
11120                 this.mode == 'local' ? 10 : 250);
11121         
11122         
11123         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11124         
11125         if(this.typeAhead){
11126             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11127         }
11128         if(this.editable !== false){
11129             this.inputEl().on("keyup", this.onKeyUp, this);
11130         }
11131         if(this.forceSelection){
11132             this.inputEl().on('blur', this.doForce, this);
11133         }
11134         
11135         if(this.multiple){
11136             this.choices = this.el.select('ul.select2-choices', true).first();
11137             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11138         }
11139     },
11140     
11141     initTickableEvents: function()
11142     {   
11143         this.createList();
11144         
11145         if(this.hiddenName){
11146             
11147             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11148             
11149             this.hiddenField.dom.value =
11150                 this.hiddenValue !== undefined ? this.hiddenValue :
11151                 this.value !== undefined ? this.value : '';
11152
11153             // prevent input submission
11154             this.el.dom.removeAttribute('name');
11155             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11156              
11157              
11158         }
11159         
11160 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11161         
11162         this.choices = this.el.select('ul.select2-choices', true).first();
11163         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11164         if(this.triggerList){
11165             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11166         }
11167          
11168         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11169         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11170         
11171         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11172         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11173         
11174         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11175         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11176         
11177         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11178         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11179         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11180         
11181         this.okBtn.hide();
11182         this.cancelBtn.hide();
11183         
11184         var _this = this;
11185         
11186         (function(){
11187             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11188             _this.list.setWidth(lw);
11189         }).defer(100);
11190         
11191         this.list.on('mouseover', this.onViewOver, this);
11192         this.list.on('mousemove', this.onViewMove, this);
11193         
11194         this.list.on('scroll', this.onViewScroll, this);
11195         
11196         if(!this.tpl){
11197             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>';
11198         }
11199
11200         this.view = new Roo.View(this.list, this.tpl, {
11201             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11202         });
11203         
11204         //this.view.wrapEl.setDisplayed(false);
11205         this.view.on('click', this.onViewClick, this);
11206         
11207         
11208         
11209         this.store.on('beforeload', this.onBeforeLoad, this);
11210         this.store.on('load', this.onLoad, this);
11211         this.store.on('loadexception', this.onLoadException, this);
11212         
11213 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11214 //            "up" : function(e){
11215 //                this.inKeyMode = true;
11216 //                this.selectPrev();
11217 //            },
11218 //
11219 //            "down" : function(e){
11220 //                if(!this.isExpanded()){
11221 //                    this.onTriggerClick();
11222 //                }else{
11223 //                    this.inKeyMode = true;
11224 //                    this.selectNext();
11225 //                }
11226 //            },
11227 //
11228 //            "enter" : function(e){
11229 ////                this.onViewClick();
11230 //                //return true;
11231 //                this.collapse();
11232 //                
11233 //                if(this.fireEvent("specialkey", this, e)){
11234 //                    this.onViewClick(false);
11235 //                }
11236 //                
11237 //                return true;
11238 //            },
11239 //
11240 //            "esc" : function(e){
11241 //                this.collapse();
11242 //            },
11243 //
11244 //            "tab" : function(e){
11245 //                this.collapse();
11246 //                
11247 //                if(this.fireEvent("specialkey", this, e)){
11248 //                    this.onViewClick(false);
11249 //                }
11250 //                
11251 //                return true;
11252 //            },
11253 //
11254 //            scope : this,
11255 //
11256 //            doRelay : function(foo, bar, hname){
11257 //                if(hname == 'down' || this.scope.isExpanded()){
11258 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11259 //                }
11260 //                return true;
11261 //            },
11262 //
11263 //            forceKeyDown: true
11264 //        });
11265         
11266         
11267         this.queryDelay = Math.max(this.queryDelay || 10,
11268                 this.mode == 'local' ? 10 : 250);
11269         
11270         
11271         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11272         
11273         if(this.typeAhead){
11274             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11275         }
11276         
11277     },
11278
11279     onDestroy : function(){
11280         if(this.view){
11281             this.view.setStore(null);
11282             this.view.el.removeAllListeners();
11283             this.view.el.remove();
11284             this.view.purgeListeners();
11285         }
11286         if(this.list){
11287             this.list.dom.innerHTML  = '';
11288         }
11289         
11290         if(this.store){
11291             this.store.un('beforeload', this.onBeforeLoad, this);
11292             this.store.un('load', this.onLoad, this);
11293             this.store.un('loadexception', this.onLoadException, this);
11294         }
11295         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11296     },
11297
11298     // private
11299     fireKey : function(e){
11300         if(e.isNavKeyPress() && !this.list.isVisible()){
11301             this.fireEvent("specialkey", this, e);
11302         }
11303     },
11304
11305     // private
11306     onResize: function(w, h){
11307 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11308 //        
11309 //        if(typeof w != 'number'){
11310 //            // we do not handle it!?!?
11311 //            return;
11312 //        }
11313 //        var tw = this.trigger.getWidth();
11314 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11315 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11316 //        var x = w - tw;
11317 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11318 //            
11319 //        //this.trigger.setStyle('left', x+'px');
11320 //        
11321 //        if(this.list && this.listWidth === undefined){
11322 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11323 //            this.list.setWidth(lw);
11324 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11325 //        }
11326         
11327     
11328         
11329     },
11330
11331     /**
11332      * Allow or prevent the user from directly editing the field text.  If false is passed,
11333      * the user will only be able to select from the items defined in the dropdown list.  This method
11334      * is the runtime equivalent of setting the 'editable' config option at config time.
11335      * @param {Boolean} value True to allow the user to directly edit the field text
11336      */
11337     setEditable : function(value){
11338         if(value == this.editable){
11339             return;
11340         }
11341         this.editable = value;
11342         if(!value){
11343             this.inputEl().dom.setAttribute('readOnly', true);
11344             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11345             this.inputEl().addClass('x-combo-noedit');
11346         }else{
11347             this.inputEl().dom.setAttribute('readOnly', false);
11348             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11349             this.inputEl().removeClass('x-combo-noedit');
11350         }
11351     },
11352
11353     // private
11354     
11355     onBeforeLoad : function(combo,opts){
11356         if(!this.hasFocus){
11357             return;
11358         }
11359          if (!opts.add) {
11360             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11361          }
11362         this.restrictHeight();
11363         this.selectedIndex = -1;
11364     },
11365
11366     // private
11367     onLoad : function(){
11368         
11369         this.hasQuery = false;
11370         
11371         if(!this.hasFocus){
11372             return;
11373         }
11374         
11375         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11376             this.loading.hide();
11377         }
11378         
11379         if(this.store.getCount() > 0){
11380             this.expand();
11381 //            this.restrictHeight();
11382             if(this.lastQuery == this.allQuery){
11383                 if(this.editable && !this.tickable){
11384                     this.inputEl().dom.select();
11385                 }
11386                 
11387                 if(
11388                     !this.selectByValue(this.value, true) &&
11389                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11390                     this.store.lastOptions.add != true)
11391                 ){
11392                     this.select(0, true);
11393                 }
11394             }else{
11395                 if(this.autoFocus){
11396                     this.selectNext();
11397                 }
11398                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11399                     this.taTask.delay(this.typeAheadDelay);
11400                 }
11401             }
11402         }else{
11403             this.onEmptyResults();
11404         }
11405         
11406         //this.el.focus();
11407     },
11408     // private
11409     onLoadException : function()
11410     {
11411         this.hasQuery = false;
11412         
11413         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11414             this.loading.hide();
11415         }
11416         
11417         this.collapse();
11418         Roo.log(this.store.reader.jsonData);
11419         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11420             // fixme
11421             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11422         }
11423         
11424         
11425     },
11426     // private
11427     onTypeAhead : function(){
11428         if(this.store.getCount() > 0){
11429             var r = this.store.getAt(0);
11430             var newValue = r.data[this.displayField];
11431             var len = newValue.length;
11432             var selStart = this.getRawValue().length;
11433             
11434             if(selStart != len){
11435                 this.setRawValue(newValue);
11436                 this.selectText(selStart, newValue.length);
11437             }
11438         }
11439     },
11440
11441     // private
11442     onSelect : function(record, index){
11443         
11444         if(this.fireEvent('beforeselect', this, record, index) !== false){
11445         
11446             this.setFromData(index > -1 ? record.data : false);
11447             
11448             this.collapse();
11449             this.fireEvent('select', this, record, index);
11450         }
11451     },
11452
11453     /**
11454      * Returns the currently selected field value or empty string if no value is set.
11455      * @return {String} value The selected value
11456      */
11457     getValue : function(){
11458         
11459         if(this.multiple){
11460             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11461         }
11462         
11463         if(this.valueField){
11464             return typeof this.value != 'undefined' ? this.value : '';
11465         }else{
11466             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11467         }
11468     },
11469
11470     /**
11471      * Clears any text/value currently set in the field
11472      */
11473     clearValue : function(){
11474         if(this.hiddenField){
11475             this.hiddenField.dom.value = '';
11476         }
11477         this.value = '';
11478         this.setRawValue('');
11479         this.lastSelectionText = '';
11480         
11481     },
11482
11483     /**
11484      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11485      * will be displayed in the field.  If the value does not match the data value of an existing item,
11486      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11487      * Otherwise the field will be blank (although the value will still be set).
11488      * @param {String} value The value to match
11489      */
11490     setValue : function(v){
11491         if(this.multiple){
11492             this.syncValue();
11493             return;
11494         }
11495         
11496         var text = v;
11497         if(this.valueField){
11498             var r = this.findRecord(this.valueField, v);
11499             if(r){
11500                 text = r.data[this.displayField];
11501             }else if(this.valueNotFoundText !== undefined){
11502                 text = this.valueNotFoundText;
11503             }
11504         }
11505         this.lastSelectionText = text;
11506         if(this.hiddenField){
11507             this.hiddenField.dom.value = v;
11508         }
11509         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11510         this.value = v;
11511     },
11512     /**
11513      * @property {Object} the last set data for the element
11514      */
11515     
11516     lastData : false,
11517     /**
11518      * Sets the value of the field based on a object which is related to the record format for the store.
11519      * @param {Object} value the value to set as. or false on reset?
11520      */
11521     setFromData : function(o){
11522         
11523         if(this.multiple){
11524             this.addItem(o);
11525             return;
11526         }
11527             
11528         var dv = ''; // display value
11529         var vv = ''; // value value..
11530         this.lastData = o;
11531         if (this.displayField) {
11532             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11533         } else {
11534             // this is an error condition!!!
11535             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11536         }
11537         
11538         if(this.valueField){
11539             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11540         }
11541         
11542         if(this.hiddenField){
11543             this.hiddenField.dom.value = vv;
11544             
11545             this.lastSelectionText = dv;
11546             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11547             this.value = vv;
11548             return;
11549         }
11550         // no hidden field.. - we store the value in 'value', but still display
11551         // display field!!!!
11552         this.lastSelectionText = dv;
11553         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11554         this.value = vv;
11555         
11556         
11557     },
11558     // private
11559     reset : function(){
11560         // overridden so that last data is reset..
11561         this.setValue(this.originalValue);
11562         this.clearInvalid();
11563         this.lastData = false;
11564         if (this.view) {
11565             this.view.clearSelections();
11566         }
11567     },
11568     // private
11569     findRecord : function(prop, value){
11570         var record;
11571         if(this.store.getCount() > 0){
11572             this.store.each(function(r){
11573                 if(r.data[prop] == value){
11574                     record = r;
11575                     return false;
11576                 }
11577                 return true;
11578             });
11579         }
11580         return record;
11581     },
11582     
11583     getName: function()
11584     {
11585         // returns hidden if it's set..
11586         if (!this.rendered) {return ''};
11587         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11588         
11589     },
11590     // private
11591     onViewMove : function(e, t){
11592         this.inKeyMode = false;
11593     },
11594
11595     // private
11596     onViewOver : function(e, t){
11597         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11598             return;
11599         }
11600         var item = this.view.findItemFromChild(t);
11601         
11602         if(item){
11603             var index = this.view.indexOf(item);
11604             this.select(index, false);
11605         }
11606     },
11607
11608     // private
11609     onViewClick : function(view, doFocus, el, e)
11610     {
11611         var index = this.view.getSelectedIndexes()[0];
11612         
11613         var r = this.store.getAt(index);
11614         
11615         if(this.tickable){
11616             
11617             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11618                 return;
11619             }
11620             
11621             var rm = false;
11622             var _this = this;
11623             
11624             Roo.each(this.tickItems, function(v,k){
11625                 
11626                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11627                     _this.tickItems.splice(k, 1);
11628                     rm = true;
11629                     return;
11630                 }
11631             });
11632             
11633             if(rm){
11634                 return;
11635             }
11636             
11637             this.tickItems.push(r.data);
11638             return;
11639         }
11640         
11641         if(r){
11642             this.onSelect(r, index);
11643         }
11644         if(doFocus !== false && !this.blockFocus){
11645             this.inputEl().focus();
11646         }
11647     },
11648
11649     // private
11650     restrictHeight : function(){
11651         //this.innerList.dom.style.height = '';
11652         //var inner = this.innerList.dom;
11653         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11654         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11655         //this.list.beginUpdate();
11656         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11657         this.list.alignTo(this.inputEl(), this.listAlign);
11658         this.list.alignTo(this.inputEl(), this.listAlign);
11659         //this.list.endUpdate();
11660     },
11661
11662     // private
11663     onEmptyResults : function(){
11664         this.collapse();
11665     },
11666
11667     /**
11668      * Returns true if the dropdown list is expanded, else false.
11669      */
11670     isExpanded : function(){
11671         return this.list.isVisible();
11672     },
11673
11674     /**
11675      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11676      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11677      * @param {String} value The data value of the item to select
11678      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11679      * selected item if it is not currently in view (defaults to true)
11680      * @return {Boolean} True if the value matched an item in the list, else false
11681      */
11682     selectByValue : function(v, scrollIntoView){
11683         if(v !== undefined && v !== null){
11684             var r = this.findRecord(this.valueField || this.displayField, v);
11685             if(r){
11686                 this.select(this.store.indexOf(r), scrollIntoView);
11687                 return true;
11688             }
11689         }
11690         return false;
11691     },
11692
11693     /**
11694      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11695      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11696      * @param {Number} index The zero-based index of the list item to select
11697      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11698      * selected item if it is not currently in view (defaults to true)
11699      */
11700     select : function(index, scrollIntoView){
11701         this.selectedIndex = index;
11702         this.view.select(index);
11703         if(scrollIntoView !== false){
11704             var el = this.view.getNode(index);
11705             if(el && !this.multiple && !this.tickable){
11706                 this.list.scrollChildIntoView(el, false);
11707             }
11708         }
11709     },
11710
11711     // private
11712     selectNext : function(){
11713         var ct = this.store.getCount();
11714         if(ct > 0){
11715             if(this.selectedIndex == -1){
11716                 this.select(0);
11717             }else if(this.selectedIndex < ct-1){
11718                 this.select(this.selectedIndex+1);
11719             }
11720         }
11721     },
11722
11723     // private
11724     selectPrev : function(){
11725         var ct = this.store.getCount();
11726         if(ct > 0){
11727             if(this.selectedIndex == -1){
11728                 this.select(0);
11729             }else if(this.selectedIndex != 0){
11730                 this.select(this.selectedIndex-1);
11731             }
11732         }
11733     },
11734
11735     // private
11736     onKeyUp : function(e){
11737         if(this.editable !== false && !e.isSpecialKey()){
11738             this.lastKey = e.getKey();
11739             this.dqTask.delay(this.queryDelay);
11740         }
11741     },
11742
11743     // private
11744     validateBlur : function(){
11745         return !this.list || !this.list.isVisible();   
11746     },
11747
11748     // private
11749     initQuery : function(){
11750         this.doQuery(this.getRawValue());
11751     },
11752
11753     // private
11754     doForce : function(){
11755         if(this.inputEl().dom.value.length > 0){
11756             this.inputEl().dom.value =
11757                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11758              
11759         }
11760     },
11761
11762     /**
11763      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11764      * query allowing the query action to be canceled if needed.
11765      * @param {String} query The SQL query to execute
11766      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11767      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11768      * saved in the current store (defaults to false)
11769      */
11770     doQuery : function(q, forceAll){
11771         
11772         if(q === undefined || q === null){
11773             q = '';
11774         }
11775         var qe = {
11776             query: q,
11777             forceAll: forceAll,
11778             combo: this,
11779             cancel:false
11780         };
11781         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11782             return false;
11783         }
11784         q = qe.query;
11785         
11786         forceAll = qe.forceAll;
11787         if(forceAll === true || (q.length >= this.minChars)){
11788             
11789             this.hasQuery = true;
11790             
11791             if(this.lastQuery != q || this.alwaysQuery){
11792                 this.lastQuery = q;
11793                 if(this.mode == 'local'){
11794                     this.selectedIndex = -1;
11795                     if(forceAll){
11796                         this.store.clearFilter();
11797                     }else{
11798                         this.store.filter(this.displayField, q);
11799                     }
11800                     this.onLoad();
11801                 }else{
11802                     this.store.baseParams[this.queryParam] = q;
11803                     
11804                     var options = {params : this.getParams(q)};
11805                     
11806                     if(this.loadNext){
11807                         options.add = true;
11808                         options.params.start = this.page * this.pageSize;
11809                     }
11810                     
11811                     this.store.load(options);
11812                     /*
11813                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11814                      *  we should expand the list on onLoad
11815                      *  so command out it
11816                      */
11817 //                    this.expand();
11818                 }
11819             }else{
11820                 this.selectedIndex = -1;
11821                 this.onLoad();   
11822             }
11823         }
11824         
11825         this.loadNext = false;
11826     },
11827
11828     // private
11829     getParams : function(q){
11830         var p = {};
11831         //p[this.queryParam] = q;
11832         
11833         if(this.pageSize){
11834             p.start = 0;
11835             p.limit = this.pageSize;
11836         }
11837         return p;
11838     },
11839
11840     /**
11841      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11842      */
11843     collapse : function(){
11844         if(!this.isExpanded()){
11845             return;
11846         }
11847         
11848         this.list.hide();
11849         
11850         if(this.tickable){
11851             this.hasFocus = false;
11852             this.okBtn.hide();
11853             this.cancelBtn.hide();
11854             this.trigger.show();
11855         }
11856         
11857         Roo.get(document).un('mousedown', this.collapseIf, this);
11858         Roo.get(document).un('mousewheel', this.collapseIf, this);
11859         if (!this.editable) {
11860             Roo.get(document).un('keydown', this.listKeyPress, this);
11861         }
11862         this.fireEvent('collapse', this);
11863     },
11864
11865     // private
11866     collapseIf : function(e){
11867         var in_combo  = e.within(this.el);
11868         var in_list =  e.within(this.list);
11869         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11870         
11871         if (in_combo || in_list || is_list) {
11872             //e.stopPropagation();
11873             return;
11874         }
11875         
11876         if(this.tickable){
11877             this.onTickableFooterButtonClick(e, false, false);
11878         }
11879
11880         this.collapse();
11881         
11882     },
11883
11884     /**
11885      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11886      */
11887     expand : function(){
11888        
11889         if(this.isExpanded() || !this.hasFocus){
11890             return;
11891         }
11892         
11893         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11894         this.list.setWidth(lw);
11895         
11896         
11897          Roo.log('expand');
11898         
11899         this.list.show();
11900         
11901         this.restrictHeight();
11902         
11903         if(this.tickable){
11904             
11905             this.tickItems = Roo.apply([], this.item);
11906             
11907             this.okBtn.show();
11908             this.cancelBtn.show();
11909             this.trigger.hide();
11910             
11911         }
11912         
11913         Roo.get(document).on('mousedown', this.collapseIf, this);
11914         Roo.get(document).on('mousewheel', this.collapseIf, this);
11915         if (!this.editable) {
11916             Roo.get(document).on('keydown', this.listKeyPress, this);
11917         }
11918         
11919         this.fireEvent('expand', this);
11920     },
11921
11922     // private
11923     // Implements the default empty TriggerField.onTriggerClick function
11924     onTriggerClick : function(e)
11925     {
11926         Roo.log('trigger click');
11927         
11928         if(this.disabled || !this.triggerList){
11929             return;
11930         }
11931         
11932         this.page = 0;
11933         this.loadNext = false;
11934         
11935         if(this.isExpanded()){
11936             this.collapse();
11937             if (!this.blockFocus) {
11938                 this.inputEl().focus();
11939             }
11940             
11941         }else {
11942             this.hasFocus = true;
11943             if(this.triggerAction == 'all') {
11944                 this.doQuery(this.allQuery, true);
11945             } else {
11946                 this.doQuery(this.getRawValue());
11947             }
11948             if (!this.blockFocus) {
11949                 this.inputEl().focus();
11950             }
11951         }
11952     },
11953     
11954     onTickableTriggerClick : function(e)
11955     {
11956         if(this.disabled){
11957             return;
11958         }
11959         
11960         this.page = 0;
11961         this.loadNext = false;
11962         this.hasFocus = true;
11963         
11964         if(this.triggerAction == 'all') {
11965             this.doQuery(this.allQuery, true);
11966         } else {
11967             this.doQuery(this.getRawValue());
11968         }
11969     },
11970     
11971     onSearchFieldClick : function(e)
11972     {
11973         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
11974             this.onTickableFooterButtonClick(e, false, false);
11975             return;
11976         }
11977         
11978         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11979             return;
11980         }
11981         
11982         this.page = 0;
11983         this.loadNext = false;
11984         this.hasFocus = true;
11985         
11986         if(this.triggerAction == 'all') {
11987             this.doQuery(this.allQuery, true);
11988         } else {
11989             this.doQuery(this.getRawValue());
11990         }
11991     },
11992     
11993     listKeyPress : function(e)
11994     {
11995         //Roo.log('listkeypress');
11996         // scroll to first matching element based on key pres..
11997         if (e.isSpecialKey()) {
11998             return false;
11999         }
12000         var k = String.fromCharCode(e.getKey()).toUpperCase();
12001         //Roo.log(k);
12002         var match  = false;
12003         var csel = this.view.getSelectedNodes();
12004         var cselitem = false;
12005         if (csel.length) {
12006             var ix = this.view.indexOf(csel[0]);
12007             cselitem  = this.store.getAt(ix);
12008             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12009                 cselitem = false;
12010             }
12011             
12012         }
12013         
12014         this.store.each(function(v) { 
12015             if (cselitem) {
12016                 // start at existing selection.
12017                 if (cselitem.id == v.id) {
12018                     cselitem = false;
12019                 }
12020                 return true;
12021             }
12022                 
12023             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12024                 match = this.store.indexOf(v);
12025                 return false;
12026             }
12027             return true;
12028         }, this);
12029         
12030         if (match === false) {
12031             return true; // no more action?
12032         }
12033         // scroll to?
12034         this.view.select(match);
12035         var sn = Roo.get(this.view.getSelectedNodes()[0])
12036         sn.scrollIntoView(sn.dom.parentNode, false);
12037     },
12038     
12039     onViewScroll : function(e, t){
12040         
12041         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){
12042             return;
12043         }
12044         
12045         this.hasQuery = true;
12046         
12047         this.loading = this.list.select('.loading', true).first();
12048         
12049         if(this.loading === null){
12050             this.list.createChild({
12051                 tag: 'div',
12052                 cls: 'loading select2-more-results select2-active',
12053                 html: 'Loading more results...'
12054             })
12055             
12056             this.loading = this.list.select('.loading', true).first();
12057             
12058             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12059             
12060             this.loading.hide();
12061         }
12062         
12063         this.loading.show();
12064         
12065         var _combo = this;
12066         
12067         this.page++;
12068         this.loadNext = true;
12069         
12070         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12071         
12072         return;
12073     },
12074     
12075     addItem : function(o)
12076     {   
12077         var dv = ''; // display value
12078         
12079         if (this.displayField) {
12080             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12081         } else {
12082             // this is an error condition!!!
12083             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12084         }
12085         
12086         if(!dv.length){
12087             return;
12088         }
12089         
12090         var choice = this.choices.createChild({
12091             tag: 'li',
12092             cls: 'select2-search-choice',
12093             cn: [
12094                 {
12095                     tag: 'div',
12096                     html: dv
12097                 },
12098                 {
12099                     tag: 'a',
12100                     href: '#',
12101                     cls: 'select2-search-choice-close',
12102                     tabindex: '-1'
12103                 }
12104             ]
12105             
12106         }, this.searchField);
12107         
12108         var close = choice.select('a.select2-search-choice-close', true).first()
12109         
12110         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12111         
12112         this.item.push(o);
12113         
12114         this.lastData = o;
12115         
12116         this.syncValue();
12117         
12118         this.inputEl().dom.value = '';
12119         
12120     },
12121     
12122     onRemoveItem : function(e, _self, o)
12123     {
12124         e.preventDefault();
12125         var index = this.item.indexOf(o.data) * 1;
12126         
12127         if( index < 0){
12128             Roo.log('not this item?!');
12129             return;
12130         }
12131         
12132         this.item.splice(index, 1);
12133         o.item.remove();
12134         
12135         this.syncValue();
12136         
12137         this.fireEvent('remove', this, e);
12138         
12139     },
12140     
12141     syncValue : function()
12142     {
12143         if(!this.item.length){
12144             this.clearValue();
12145             return;
12146         }
12147             
12148         var value = [];
12149         var _this = this;
12150         Roo.each(this.item, function(i){
12151             if(_this.valueField){
12152                 value.push(i[_this.valueField]);
12153                 return;
12154             }
12155
12156             value.push(i);
12157         });
12158
12159         this.value = value.join(',');
12160
12161         if(this.hiddenField){
12162             this.hiddenField.dom.value = this.value;
12163         }
12164     },
12165     
12166     clearItem : function()
12167     {
12168         if(!this.multiple){
12169             return;
12170         }
12171         
12172         this.item = [];
12173         
12174         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12175            c.remove();
12176         });
12177         
12178         this.syncValue();
12179     },
12180     
12181     inputEl: function ()
12182     {
12183         if(this.tickable){
12184             return this.searchField;
12185         }
12186         return this.el.select('input.form-control',true).first();
12187     },
12188     
12189     
12190     onTickableFooterButtonClick : function(e, btn, el)
12191     {
12192         e.preventDefault();
12193         
12194         if(btn && btn.name == 'cancel'){
12195             this.tickItems = Roo.apply([], this.item);
12196             this.collapse();
12197             return;
12198         }
12199         
12200         this.clearItem();
12201         
12202         var _this = this;
12203         
12204         Roo.each(this.tickItems, function(o){
12205             _this.addItem(o);
12206         });
12207         
12208         this.collapse();
12209         
12210     },
12211     
12212     validate : function()
12213     {
12214         var v = this.getRawValue();
12215         
12216         if(this.multiple){
12217             v = this.getValue();
12218         }
12219         
12220         if(this.disabled || this.validateValue(v)){
12221             this.clearInvalid();
12222             return true;
12223         }
12224         return false;
12225     }
12226     
12227     
12228
12229     /** 
12230     * @cfg {Boolean} grow 
12231     * @hide 
12232     */
12233     /** 
12234     * @cfg {Number} growMin 
12235     * @hide 
12236     */
12237     /** 
12238     * @cfg {Number} growMax 
12239     * @hide 
12240     */
12241     /**
12242      * @hide
12243      * @method autoSize
12244      */
12245 });
12246 /*
12247  * Based on:
12248  * Ext JS Library 1.1.1
12249  * Copyright(c) 2006-2007, Ext JS, LLC.
12250  *
12251  * Originally Released Under LGPL - original licence link has changed is not relivant.
12252  *
12253  * Fork - LGPL
12254  * <script type="text/javascript">
12255  */
12256
12257 /**
12258  * @class Roo.View
12259  * @extends Roo.util.Observable
12260  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12261  * This class also supports single and multi selection modes. <br>
12262  * Create a data model bound view:
12263  <pre><code>
12264  var store = new Roo.data.Store(...);
12265
12266  var view = new Roo.View({
12267     el : "my-element",
12268     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12269  
12270     singleSelect: true,
12271     selectedClass: "ydataview-selected",
12272     store: store
12273  });
12274
12275  // listen for node click?
12276  view.on("click", function(vw, index, node, e){
12277  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12278  });
12279
12280  // load XML data
12281  dataModel.load("foobar.xml");
12282  </code></pre>
12283  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12284  * <br><br>
12285  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12286  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12287  * 
12288  * Note: old style constructor is still suported (container, template, config)
12289  * 
12290  * @constructor
12291  * Create a new View
12292  * @param {Object} config The config object
12293  * 
12294  */
12295 Roo.View = function(config, depreciated_tpl, depreciated_config){
12296     
12297     this.parent = false;
12298     
12299     if (typeof(depreciated_tpl) == 'undefined') {
12300         // new way.. - universal constructor.
12301         Roo.apply(this, config);
12302         this.el  = Roo.get(this.el);
12303     } else {
12304         // old format..
12305         this.el  = Roo.get(config);
12306         this.tpl = depreciated_tpl;
12307         Roo.apply(this, depreciated_config);
12308     }
12309     this.wrapEl  = this.el.wrap().wrap();
12310     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12311     
12312     
12313     if(typeof(this.tpl) == "string"){
12314         this.tpl = new Roo.Template(this.tpl);
12315     } else {
12316         // support xtype ctors..
12317         this.tpl = new Roo.factory(this.tpl, Roo);
12318     }
12319     
12320     
12321     this.tpl.compile();
12322     
12323     /** @private */
12324     this.addEvents({
12325         /**
12326          * @event beforeclick
12327          * Fires before a click is processed. Returns false to cancel the default action.
12328          * @param {Roo.View} this
12329          * @param {Number} index The index of the target node
12330          * @param {HTMLElement} node The target node
12331          * @param {Roo.EventObject} e The raw event object
12332          */
12333             "beforeclick" : true,
12334         /**
12335          * @event click
12336          * Fires when a template node is clicked.
12337          * @param {Roo.View} this
12338          * @param {Number} index The index of the target node
12339          * @param {HTMLElement} node The target node
12340          * @param {Roo.EventObject} e The raw event object
12341          */
12342             "click" : true,
12343         /**
12344          * @event dblclick
12345          * Fires when a template node is double clicked.
12346          * @param {Roo.View} this
12347          * @param {Number} index The index of the target node
12348          * @param {HTMLElement} node The target node
12349          * @param {Roo.EventObject} e The raw event object
12350          */
12351             "dblclick" : true,
12352         /**
12353          * @event contextmenu
12354          * Fires when a template node is right clicked.
12355          * @param {Roo.View} this
12356          * @param {Number} index The index of the target node
12357          * @param {HTMLElement} node The target node
12358          * @param {Roo.EventObject} e The raw event object
12359          */
12360             "contextmenu" : true,
12361         /**
12362          * @event selectionchange
12363          * Fires when the selected nodes change.
12364          * @param {Roo.View} this
12365          * @param {Array} selections Array of the selected nodes
12366          */
12367             "selectionchange" : true,
12368     
12369         /**
12370          * @event beforeselect
12371          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12372          * @param {Roo.View} this
12373          * @param {HTMLElement} node The node to be selected
12374          * @param {Array} selections Array of currently selected nodes
12375          */
12376             "beforeselect" : true,
12377         /**
12378          * @event preparedata
12379          * Fires on every row to render, to allow you to change the data.
12380          * @param {Roo.View} this
12381          * @param {Object} data to be rendered (change this)
12382          */
12383           "preparedata" : true
12384           
12385           
12386         });
12387
12388
12389
12390     this.el.on({
12391         "click": this.onClick,
12392         "dblclick": this.onDblClick,
12393         "contextmenu": this.onContextMenu,
12394         scope:this
12395     });
12396
12397     this.selections = [];
12398     this.nodes = [];
12399     this.cmp = new Roo.CompositeElementLite([]);
12400     if(this.store){
12401         this.store = Roo.factory(this.store, Roo.data);
12402         this.setStore(this.store, true);
12403     }
12404     
12405     if ( this.footer && this.footer.xtype) {
12406            
12407          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12408         
12409         this.footer.dataSource = this.store
12410         this.footer.container = fctr;
12411         this.footer = Roo.factory(this.footer, Roo);
12412         fctr.insertFirst(this.el);
12413         
12414         // this is a bit insane - as the paging toolbar seems to detach the el..
12415 //        dom.parentNode.parentNode.parentNode
12416          // they get detached?
12417     }
12418     
12419     
12420     Roo.View.superclass.constructor.call(this);
12421     
12422     
12423 };
12424
12425 Roo.extend(Roo.View, Roo.util.Observable, {
12426     
12427      /**
12428      * @cfg {Roo.data.Store} store Data store to load data from.
12429      */
12430     store : false,
12431     
12432     /**
12433      * @cfg {String|Roo.Element} el The container element.
12434      */
12435     el : '',
12436     
12437     /**
12438      * @cfg {String|Roo.Template} tpl The template used by this View 
12439      */
12440     tpl : false,
12441     /**
12442      * @cfg {String} dataName the named area of the template to use as the data area
12443      *                          Works with domtemplates roo-name="name"
12444      */
12445     dataName: false,
12446     /**
12447      * @cfg {String} selectedClass The css class to add to selected nodes
12448      */
12449     selectedClass : "x-view-selected",
12450      /**
12451      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12452      */
12453     emptyText : "",
12454     
12455     /**
12456      * @cfg {String} text to display on mask (default Loading)
12457      */
12458     mask : false,
12459     /**
12460      * @cfg {Boolean} multiSelect Allow multiple selection
12461      */
12462     multiSelect : false,
12463     /**
12464      * @cfg {Boolean} singleSelect Allow single selection
12465      */
12466     singleSelect:  false,
12467     
12468     /**
12469      * @cfg {Boolean} toggleSelect - selecting 
12470      */
12471     toggleSelect : false,
12472     
12473     /**
12474      * @cfg {Boolean} tickable - selecting 
12475      */
12476     tickable : false,
12477     
12478     /**
12479      * Returns the element this view is bound to.
12480      * @return {Roo.Element}
12481      */
12482     getEl : function(){
12483         return this.wrapEl;
12484     },
12485     
12486     
12487
12488     /**
12489      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12490      */
12491     refresh : function(){
12492         //Roo.log('refresh');
12493         var t = this.tpl;
12494         
12495         // if we are using something like 'domtemplate', then
12496         // the what gets used is:
12497         // t.applySubtemplate(NAME, data, wrapping data..)
12498         // the outer template then get' applied with
12499         //     the store 'extra data'
12500         // and the body get's added to the
12501         //      roo-name="data" node?
12502         //      <span class='roo-tpl-{name}'></span> ?????
12503         
12504         
12505         
12506         this.clearSelections();
12507         this.el.update("");
12508         var html = [];
12509         var records = this.store.getRange();
12510         if(records.length < 1) {
12511             
12512             // is this valid??  = should it render a template??
12513             
12514             this.el.update(this.emptyText);
12515             return;
12516         }
12517         var el = this.el;
12518         if (this.dataName) {
12519             this.el.update(t.apply(this.store.meta)); //????
12520             el = this.el.child('.roo-tpl-' + this.dataName);
12521         }
12522         
12523         for(var i = 0, len = records.length; i < len; i++){
12524             var data = this.prepareData(records[i].data, i, records[i]);
12525             this.fireEvent("preparedata", this, data, i, records[i]);
12526             
12527             var d = Roo.apply({}, data);
12528             
12529             if(this.tickable){
12530                 Roo.apply(d, {'roo-id' : Roo.id()});
12531                 
12532                 var _this = this;
12533             
12534                 Roo.each(this.parent.item, function(item){
12535                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12536                         return;
12537                     }
12538                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12539                 });
12540             }
12541             
12542             html[html.length] = Roo.util.Format.trim(
12543                 this.dataName ?
12544                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12545                     t.apply(d)
12546             );
12547         }
12548         
12549         
12550         
12551         el.update(html.join(""));
12552         this.nodes = el.dom.childNodes;
12553         this.updateIndexes(0);
12554     },
12555     
12556
12557     /**
12558      * Function to override to reformat the data that is sent to
12559      * the template for each node.
12560      * DEPRICATED - use the preparedata event handler.
12561      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12562      * a JSON object for an UpdateManager bound view).
12563      */
12564     prepareData : function(data, index, record)
12565     {
12566         this.fireEvent("preparedata", this, data, index, record);
12567         return data;
12568     },
12569
12570     onUpdate : function(ds, record){
12571         // Roo.log('on update');   
12572         this.clearSelections();
12573         var index = this.store.indexOf(record);
12574         var n = this.nodes[index];
12575         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12576         n.parentNode.removeChild(n);
12577         this.updateIndexes(index, index);
12578     },
12579
12580     
12581     
12582 // --------- FIXME     
12583     onAdd : function(ds, records, index)
12584     {
12585         //Roo.log(['on Add', ds, records, index] );        
12586         this.clearSelections();
12587         if(this.nodes.length == 0){
12588             this.refresh();
12589             return;
12590         }
12591         var n = this.nodes[index];
12592         for(var i = 0, len = records.length; i < len; i++){
12593             var d = this.prepareData(records[i].data, i, records[i]);
12594             if(n){
12595                 this.tpl.insertBefore(n, d);
12596             }else{
12597                 
12598                 this.tpl.append(this.el, d);
12599             }
12600         }
12601         this.updateIndexes(index);
12602     },
12603
12604     onRemove : function(ds, record, index){
12605        // Roo.log('onRemove');
12606         this.clearSelections();
12607         var el = this.dataName  ?
12608             this.el.child('.roo-tpl-' + this.dataName) :
12609             this.el; 
12610         
12611         el.dom.removeChild(this.nodes[index]);
12612         this.updateIndexes(index);
12613     },
12614
12615     /**
12616      * Refresh an individual node.
12617      * @param {Number} index
12618      */
12619     refreshNode : function(index){
12620         this.onUpdate(this.store, this.store.getAt(index));
12621     },
12622
12623     updateIndexes : function(startIndex, endIndex){
12624         var ns = this.nodes;
12625         startIndex = startIndex || 0;
12626         endIndex = endIndex || ns.length - 1;
12627         for(var i = startIndex; i <= endIndex; i++){
12628             ns[i].nodeIndex = i;
12629         }
12630     },
12631
12632     /**
12633      * Changes the data store this view uses and refresh the view.
12634      * @param {Store} store
12635      */
12636     setStore : function(store, initial){
12637         if(!initial && this.store){
12638             this.store.un("datachanged", this.refresh);
12639             this.store.un("add", this.onAdd);
12640             this.store.un("remove", this.onRemove);
12641             this.store.un("update", this.onUpdate);
12642             this.store.un("clear", this.refresh);
12643             this.store.un("beforeload", this.onBeforeLoad);
12644             this.store.un("load", this.onLoad);
12645             this.store.un("loadexception", this.onLoad);
12646         }
12647         if(store){
12648           
12649             store.on("datachanged", this.refresh, this);
12650             store.on("add", this.onAdd, this);
12651             store.on("remove", this.onRemove, this);
12652             store.on("update", this.onUpdate, this);
12653             store.on("clear", this.refresh, this);
12654             store.on("beforeload", this.onBeforeLoad, this);
12655             store.on("load", this.onLoad, this);
12656             store.on("loadexception", this.onLoad, this);
12657         }
12658         
12659         if(store){
12660             this.refresh();
12661         }
12662     },
12663     /**
12664      * onbeforeLoad - masks the loading area.
12665      *
12666      */
12667     onBeforeLoad : function(store,opts)
12668     {
12669          //Roo.log('onBeforeLoad');   
12670         if (!opts.add) {
12671             this.el.update("");
12672         }
12673         this.el.mask(this.mask ? this.mask : "Loading" ); 
12674     },
12675     onLoad : function ()
12676     {
12677         this.el.unmask();
12678     },
12679     
12680
12681     /**
12682      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12683      * @param {HTMLElement} node
12684      * @return {HTMLElement} The template node
12685      */
12686     findItemFromChild : function(node){
12687         var el = this.dataName  ?
12688             this.el.child('.roo-tpl-' + this.dataName,true) :
12689             this.el.dom; 
12690         
12691         if(!node || node.parentNode == el){
12692                     return node;
12693             }
12694             var p = node.parentNode;
12695             while(p && p != el){
12696             if(p.parentNode == el){
12697                 return p;
12698             }
12699             p = p.parentNode;
12700         }
12701             return null;
12702     },
12703
12704     /** @ignore */
12705     onClick : function(e){
12706         var item = this.findItemFromChild(e.getTarget());
12707         if(item){
12708             var index = this.indexOf(item);
12709             if(this.onItemClick(item, index, e) !== false){
12710                 this.fireEvent("click", this, index, item, e);
12711             }
12712         }else{
12713             this.clearSelections();
12714         }
12715     },
12716
12717     /** @ignore */
12718     onContextMenu : function(e){
12719         var item = this.findItemFromChild(e.getTarget());
12720         if(item){
12721             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12722         }
12723     },
12724
12725     /** @ignore */
12726     onDblClick : function(e){
12727         var item = this.findItemFromChild(e.getTarget());
12728         if(item){
12729             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12730         }
12731     },
12732
12733     onItemClick : function(item, index, e)
12734     {
12735         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12736             return false;
12737         }
12738         if (this.toggleSelect) {
12739             var m = this.isSelected(item) ? 'unselect' : 'select';
12740             //Roo.log(m);
12741             var _t = this;
12742             _t[m](item, true, false);
12743             return true;
12744         }
12745         if(this.multiSelect || this.singleSelect){
12746             if(this.multiSelect && e.shiftKey && this.lastSelection){
12747                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12748             }else{
12749                 this.select(item, this.multiSelect && e.ctrlKey);
12750                 this.lastSelection = item;
12751             }
12752             
12753             if(!this.tickable){
12754                 e.preventDefault();
12755             }
12756             
12757         }
12758         return true;
12759     },
12760
12761     /**
12762      * Get the number of selected nodes.
12763      * @return {Number}
12764      */
12765     getSelectionCount : function(){
12766         return this.selections.length;
12767     },
12768
12769     /**
12770      * Get the currently selected nodes.
12771      * @return {Array} An array of HTMLElements
12772      */
12773     getSelectedNodes : function(){
12774         return this.selections;
12775     },
12776
12777     /**
12778      * Get the indexes of the selected nodes.
12779      * @return {Array}
12780      */
12781     getSelectedIndexes : function(){
12782         var indexes = [], s = this.selections;
12783         for(var i = 0, len = s.length; i < len; i++){
12784             indexes.push(s[i].nodeIndex);
12785         }
12786         return indexes;
12787     },
12788
12789     /**
12790      * Clear all selections
12791      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12792      */
12793     clearSelections : function(suppressEvent){
12794         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12795             this.cmp.elements = this.selections;
12796             this.cmp.removeClass(this.selectedClass);
12797             this.selections = [];
12798             if(!suppressEvent){
12799                 this.fireEvent("selectionchange", this, this.selections);
12800             }
12801         }
12802     },
12803
12804     /**
12805      * Returns true if the passed node is selected
12806      * @param {HTMLElement/Number} node The node or node index
12807      * @return {Boolean}
12808      */
12809     isSelected : function(node){
12810         var s = this.selections;
12811         if(s.length < 1){
12812             return false;
12813         }
12814         node = this.getNode(node);
12815         return s.indexOf(node) !== -1;
12816     },
12817
12818     /**
12819      * Selects nodes.
12820      * @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
12821      * @param {Boolean} keepExisting (optional) true to keep existing selections
12822      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12823      */
12824     select : function(nodeInfo, keepExisting, suppressEvent){
12825         if(nodeInfo instanceof Array){
12826             if(!keepExisting){
12827                 this.clearSelections(true);
12828             }
12829             for(var i = 0, len = nodeInfo.length; i < len; i++){
12830                 this.select(nodeInfo[i], true, true);
12831             }
12832             return;
12833         } 
12834         var node = this.getNode(nodeInfo);
12835         if(!node || this.isSelected(node)){
12836             return; // already selected.
12837         }
12838         if(!keepExisting){
12839             this.clearSelections(true);
12840         }
12841         
12842         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12843             Roo.fly(node).addClass(this.selectedClass);
12844             this.selections.push(node);
12845             if(!suppressEvent){
12846                 this.fireEvent("selectionchange", this, this.selections);
12847             }
12848         }
12849         
12850         
12851     },
12852       /**
12853      * Unselects nodes.
12854      * @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
12855      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12856      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12857      */
12858     unselect : function(nodeInfo, keepExisting, suppressEvent)
12859     {
12860         if(nodeInfo instanceof Array){
12861             Roo.each(this.selections, function(s) {
12862                 this.unselect(s, nodeInfo);
12863             }, this);
12864             return;
12865         }
12866         var node = this.getNode(nodeInfo);
12867         if(!node || !this.isSelected(node)){
12868             //Roo.log("not selected");
12869             return; // not selected.
12870         }
12871         // fireevent???
12872         var ns = [];
12873         Roo.each(this.selections, function(s) {
12874             if (s == node ) {
12875                 Roo.fly(node).removeClass(this.selectedClass);
12876
12877                 return;
12878             }
12879             ns.push(s);
12880         },this);
12881         
12882         this.selections= ns;
12883         this.fireEvent("selectionchange", this, this.selections);
12884     },
12885
12886     /**
12887      * Gets a template node.
12888      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12889      * @return {HTMLElement} The node or null if it wasn't found
12890      */
12891     getNode : function(nodeInfo){
12892         if(typeof nodeInfo == "string"){
12893             return document.getElementById(nodeInfo);
12894         }else if(typeof nodeInfo == "number"){
12895             return this.nodes[nodeInfo];
12896         }
12897         return nodeInfo;
12898     },
12899
12900     /**
12901      * Gets a range template nodes.
12902      * @param {Number} startIndex
12903      * @param {Number} endIndex
12904      * @return {Array} An array of nodes
12905      */
12906     getNodes : function(start, end){
12907         var ns = this.nodes;
12908         start = start || 0;
12909         end = typeof end == "undefined" ? ns.length - 1 : end;
12910         var nodes = [];
12911         if(start <= end){
12912             for(var i = start; i <= end; i++){
12913                 nodes.push(ns[i]);
12914             }
12915         } else{
12916             for(var i = start; i >= end; i--){
12917                 nodes.push(ns[i]);
12918             }
12919         }
12920         return nodes;
12921     },
12922
12923     /**
12924      * Finds the index of the passed node
12925      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12926      * @return {Number} The index of the node or -1
12927      */
12928     indexOf : function(node){
12929         node = this.getNode(node);
12930         if(typeof node.nodeIndex == "number"){
12931             return node.nodeIndex;
12932         }
12933         var ns = this.nodes;
12934         for(var i = 0, len = ns.length; i < len; i++){
12935             if(ns[i] == node){
12936                 return i;
12937             }
12938         }
12939         return -1;
12940     }
12941 });
12942 /*
12943  * - LGPL
12944  *
12945  * based on jquery fullcalendar
12946  * 
12947  */
12948
12949 Roo.bootstrap = Roo.bootstrap || {};
12950 /**
12951  * @class Roo.bootstrap.Calendar
12952  * @extends Roo.bootstrap.Component
12953  * Bootstrap Calendar class
12954  * @cfg {Boolean} loadMask (true|false) default false
12955  * @cfg {Object} header generate the user specific header of the calendar, default false
12956
12957  * @constructor
12958  * Create a new Container
12959  * @param {Object} config The config object
12960  */
12961
12962
12963
12964 Roo.bootstrap.Calendar = function(config){
12965     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12966      this.addEvents({
12967         /**
12968              * @event select
12969              * Fires when a date is selected
12970              * @param {DatePicker} this
12971              * @param {Date} date The selected date
12972              */
12973         'select': true,
12974         /**
12975              * @event monthchange
12976              * Fires when the displayed month changes 
12977              * @param {DatePicker} this
12978              * @param {Date} date The selected month
12979              */
12980         'monthchange': true,
12981         /**
12982              * @event evententer
12983              * Fires when mouse over an event
12984              * @param {Calendar} this
12985              * @param {event} Event
12986              */
12987         'evententer': true,
12988         /**
12989              * @event eventleave
12990              * Fires when the mouse leaves an
12991              * @param {Calendar} this
12992              * @param {event}
12993              */
12994         'eventleave': true,
12995         /**
12996              * @event eventclick
12997              * Fires when the mouse click an
12998              * @param {Calendar} this
12999              * @param {event}
13000              */
13001         'eventclick': true
13002         
13003     });
13004
13005 };
13006
13007 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13008     
13009      /**
13010      * @cfg {Number} startDay
13011      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13012      */
13013     startDay : 0,
13014     
13015     loadMask : false,
13016     
13017     header : false,
13018       
13019     getAutoCreate : function(){
13020         
13021         
13022         var fc_button = function(name, corner, style, content ) {
13023             return Roo.apply({},{
13024                 tag : 'span',
13025                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13026                          (corner.length ?
13027                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13028                             ''
13029                         ),
13030                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13031                 unselectable: 'on'
13032             });
13033         };
13034         
13035         var header = {};
13036         
13037         if(!this.header){
13038             header = {
13039                 tag : 'table',
13040                 cls : 'fc-header',
13041                 style : 'width:100%',
13042                 cn : [
13043                     {
13044                         tag: 'tr',
13045                         cn : [
13046                             {
13047                                 tag : 'td',
13048                                 cls : 'fc-header-left',
13049                                 cn : [
13050                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13051                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13052                                     { tag: 'span', cls: 'fc-header-space' },
13053                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13054
13055
13056                                 ]
13057                             },
13058
13059                             {
13060                                 tag : 'td',
13061                                 cls : 'fc-header-center',
13062                                 cn : [
13063                                     {
13064                                         tag: 'span',
13065                                         cls: 'fc-header-title',
13066                                         cn : {
13067                                             tag: 'H2',
13068                                             html : 'month / year'
13069                                         }
13070                                     }
13071
13072                                 ]
13073                             },
13074                             {
13075                                 tag : 'td',
13076                                 cls : 'fc-header-right',
13077                                 cn : [
13078                               /*      fc_button('month', 'left', '', 'month' ),
13079                                     fc_button('week', '', '', 'week' ),
13080                                     fc_button('day', 'right', '', 'day' )
13081                                 */    
13082
13083                                 ]
13084                             }
13085
13086                         ]
13087                     }
13088                 ]
13089             };
13090         }
13091         
13092         header = this.header;
13093         
13094        
13095         var cal_heads = function() {
13096             var ret = [];
13097             // fixme - handle this.
13098             
13099             for (var i =0; i < Date.dayNames.length; i++) {
13100                 var d = Date.dayNames[i];
13101                 ret.push({
13102                     tag: 'th',
13103                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13104                     html : d.substring(0,3)
13105                 });
13106                 
13107             }
13108             ret[0].cls += ' fc-first';
13109             ret[6].cls += ' fc-last';
13110             return ret;
13111         };
13112         var cal_cell = function(n) {
13113             return  {
13114                 tag: 'td',
13115                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13116                 cn : [
13117                     {
13118                         cn : [
13119                             {
13120                                 cls: 'fc-day-number',
13121                                 html: 'D'
13122                             },
13123                             {
13124                                 cls: 'fc-day-content',
13125                              
13126                                 cn : [
13127                                      {
13128                                         style: 'position: relative;' // height: 17px;
13129                                     }
13130                                 ]
13131                             }
13132                             
13133                             
13134                         ]
13135                     }
13136                 ]
13137                 
13138             }
13139         };
13140         var cal_rows = function() {
13141             
13142             var ret = [];
13143             for (var r = 0; r < 6; r++) {
13144                 var row= {
13145                     tag : 'tr',
13146                     cls : 'fc-week',
13147                     cn : []
13148                 };
13149                 
13150                 for (var i =0; i < Date.dayNames.length; i++) {
13151                     var d = Date.dayNames[i];
13152                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13153
13154                 }
13155                 row.cn[0].cls+=' fc-first';
13156                 row.cn[0].cn[0].style = 'min-height:90px';
13157                 row.cn[6].cls+=' fc-last';
13158                 ret.push(row);
13159                 
13160             }
13161             ret[0].cls += ' fc-first';
13162             ret[4].cls += ' fc-prev-last';
13163             ret[5].cls += ' fc-last';
13164             return ret;
13165             
13166         };
13167         
13168         var cal_table = {
13169             tag: 'table',
13170             cls: 'fc-border-separate',
13171             style : 'width:100%',
13172             cellspacing  : 0,
13173             cn : [
13174                 { 
13175                     tag: 'thead',
13176                     cn : [
13177                         { 
13178                             tag: 'tr',
13179                             cls : 'fc-first fc-last',
13180                             cn : cal_heads()
13181                         }
13182                     ]
13183                 },
13184                 { 
13185                     tag: 'tbody',
13186                     cn : cal_rows()
13187                 }
13188                   
13189             ]
13190         };
13191          
13192          var cfg = {
13193             cls : 'fc fc-ltr',
13194             cn : [
13195                 header,
13196                 {
13197                     cls : 'fc-content',
13198                     style : "position: relative;",
13199                     cn : [
13200                         {
13201                             cls : 'fc-view fc-view-month fc-grid',
13202                             style : 'position: relative',
13203                             unselectable : 'on',
13204                             cn : [
13205                                 {
13206                                     cls : 'fc-event-container',
13207                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13208                                 },
13209                                 cal_table
13210                             ]
13211                         }
13212                     ]
13213     
13214                 }
13215            ] 
13216             
13217         };
13218         
13219          
13220         
13221         return cfg;
13222     },
13223     
13224     
13225     initEvents : function()
13226     {
13227         if(!this.store){
13228             throw "can not find store for calendar";
13229         }
13230         
13231         var mark = {
13232             tag: "div",
13233             cls:"x-dlg-mask",
13234             style: "text-align:center",
13235             cn: [
13236                 {
13237                     tag: "div",
13238                     style: "background-color:white;width:50%;margin:250 auto",
13239                     cn: [
13240                         {
13241                             tag: "img",
13242                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13243                         },
13244                         {
13245                             tag: "span",
13246                             html: "Loading"
13247                         }
13248                         
13249                     ]
13250                 }
13251             ]
13252         }
13253         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13254         
13255         var size = this.el.select('.fc-content', true).first().getSize();
13256         this.maskEl.setSize(size.width, size.height);
13257         this.maskEl.enableDisplayMode("block");
13258         if(!this.loadMask){
13259             this.maskEl.hide();
13260         }
13261         
13262         this.store = Roo.factory(this.store, Roo.data);
13263         this.store.on('load', this.onLoad, this);
13264         this.store.on('beforeload', this.onBeforeLoad, this);
13265         
13266         this.resize();
13267         
13268         this.cells = this.el.select('.fc-day',true);
13269         //Roo.log(this.cells);
13270         this.textNodes = this.el.query('.fc-day-number');
13271         this.cells.addClassOnOver('fc-state-hover');
13272         
13273         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13274         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13275         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13276         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13277         
13278         this.on('monthchange', this.onMonthChange, this);
13279         
13280         this.update(new Date().clearTime());
13281     },
13282     
13283     resize : function() {
13284         var sz  = this.el.getSize();
13285         
13286         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13287         this.el.select('.fc-day-content div',true).setHeight(34);
13288     },
13289     
13290     
13291     // private
13292     showPrevMonth : function(e){
13293         this.update(this.activeDate.add("mo", -1));
13294     },
13295     showToday : function(e){
13296         this.update(new Date().clearTime());
13297     },
13298     // private
13299     showNextMonth : function(e){
13300         this.update(this.activeDate.add("mo", 1));
13301     },
13302
13303     // private
13304     showPrevYear : function(){
13305         this.update(this.activeDate.add("y", -1));
13306     },
13307
13308     // private
13309     showNextYear : function(){
13310         this.update(this.activeDate.add("y", 1));
13311     },
13312
13313     
13314    // private
13315     update : function(date)
13316     {
13317         var vd = this.activeDate;
13318         this.activeDate = date;
13319 //        if(vd && this.el){
13320 //            var t = date.getTime();
13321 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13322 //                Roo.log('using add remove');
13323 //                
13324 //                this.fireEvent('monthchange', this, date);
13325 //                
13326 //                this.cells.removeClass("fc-state-highlight");
13327 //                this.cells.each(function(c){
13328 //                   if(c.dateValue == t){
13329 //                       c.addClass("fc-state-highlight");
13330 //                       setTimeout(function(){
13331 //                            try{c.dom.firstChild.focus();}catch(e){}
13332 //                       }, 50);
13333 //                       return false;
13334 //                   }
13335 //                   return true;
13336 //                });
13337 //                return;
13338 //            }
13339 //        }
13340         
13341         var days = date.getDaysInMonth();
13342         
13343         var firstOfMonth = date.getFirstDateOfMonth();
13344         var startingPos = firstOfMonth.getDay()-this.startDay;
13345         
13346         if(startingPos < this.startDay){
13347             startingPos += 7;
13348         }
13349         
13350         var pm = date.add(Date.MONTH, -1);
13351         var prevStart = pm.getDaysInMonth()-startingPos;
13352 //        
13353         this.cells = this.el.select('.fc-day',true);
13354         this.textNodes = this.el.query('.fc-day-number');
13355         this.cells.addClassOnOver('fc-state-hover');
13356         
13357         var cells = this.cells.elements;
13358         var textEls = this.textNodes;
13359         
13360         Roo.each(cells, function(cell){
13361             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13362         });
13363         
13364         days += startingPos;
13365
13366         // convert everything to numbers so it's fast
13367         var day = 86400000;
13368         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13369         //Roo.log(d);
13370         //Roo.log(pm);
13371         //Roo.log(prevStart);
13372         
13373         var today = new Date().clearTime().getTime();
13374         var sel = date.clearTime().getTime();
13375         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13376         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13377         var ddMatch = this.disabledDatesRE;
13378         var ddText = this.disabledDatesText;
13379         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13380         var ddaysText = this.disabledDaysText;
13381         var format = this.format;
13382         
13383         var setCellClass = function(cal, cell){
13384             cell.row = 0;
13385             cell.events = [];
13386             cell.more = [];
13387             //Roo.log('set Cell Class');
13388             cell.title = "";
13389             var t = d.getTime();
13390             
13391             //Roo.log(d);
13392             
13393             cell.dateValue = t;
13394             if(t == today){
13395                 cell.className += " fc-today";
13396                 cell.className += " fc-state-highlight";
13397                 cell.title = cal.todayText;
13398             }
13399             if(t == sel){
13400                 // disable highlight in other month..
13401                 //cell.className += " fc-state-highlight";
13402                 
13403             }
13404             // disabling
13405             if(t < min) {
13406                 cell.className = " fc-state-disabled";
13407                 cell.title = cal.minText;
13408                 return;
13409             }
13410             if(t > max) {
13411                 cell.className = " fc-state-disabled";
13412                 cell.title = cal.maxText;
13413                 return;
13414             }
13415             if(ddays){
13416                 if(ddays.indexOf(d.getDay()) != -1){
13417                     cell.title = ddaysText;
13418                     cell.className = " fc-state-disabled";
13419                 }
13420             }
13421             if(ddMatch && format){
13422                 var fvalue = d.dateFormat(format);
13423                 if(ddMatch.test(fvalue)){
13424                     cell.title = ddText.replace("%0", fvalue);
13425                     cell.className = " fc-state-disabled";
13426                 }
13427             }
13428             
13429             if (!cell.initialClassName) {
13430                 cell.initialClassName = cell.dom.className;
13431             }
13432             
13433             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13434         };
13435
13436         var i = 0;
13437         
13438         for(; i < startingPos; i++) {
13439             textEls[i].innerHTML = (++prevStart);
13440             d.setDate(d.getDate()+1);
13441             
13442             cells[i].className = "fc-past fc-other-month";
13443             setCellClass(this, cells[i]);
13444         }
13445         
13446         var intDay = 0;
13447         
13448         for(; i < days; i++){
13449             intDay = i - startingPos + 1;
13450             textEls[i].innerHTML = (intDay);
13451             d.setDate(d.getDate()+1);
13452             
13453             cells[i].className = ''; // "x-date-active";
13454             setCellClass(this, cells[i]);
13455         }
13456         var extraDays = 0;
13457         
13458         for(; i < 42; i++) {
13459             textEls[i].innerHTML = (++extraDays);
13460             d.setDate(d.getDate()+1);
13461             
13462             cells[i].className = "fc-future fc-other-month";
13463             setCellClass(this, cells[i]);
13464         }
13465         
13466         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13467         
13468         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13469         
13470         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13471         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13472         
13473         if(totalRows != 6){
13474             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13475             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13476         }
13477         
13478         this.fireEvent('monthchange', this, date);
13479         
13480         
13481         /*
13482         if(!this.internalRender){
13483             var main = this.el.dom.firstChild;
13484             var w = main.offsetWidth;
13485             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13486             Roo.fly(main).setWidth(w);
13487             this.internalRender = true;
13488             // opera does not respect the auto grow header center column
13489             // then, after it gets a width opera refuses to recalculate
13490             // without a second pass
13491             if(Roo.isOpera && !this.secondPass){
13492                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13493                 this.secondPass = true;
13494                 this.update.defer(10, this, [date]);
13495             }
13496         }
13497         */
13498         
13499     },
13500     
13501     findCell : function(dt) {
13502         dt = dt.clearTime().getTime();
13503         var ret = false;
13504         this.cells.each(function(c){
13505             //Roo.log("check " +c.dateValue + '?=' + dt);
13506             if(c.dateValue == dt){
13507                 ret = c;
13508                 return false;
13509             }
13510             return true;
13511         });
13512         
13513         return ret;
13514     },
13515     
13516     findCells : function(ev) {
13517         var s = ev.start.clone().clearTime().getTime();
13518        // Roo.log(s);
13519         var e= ev.end.clone().clearTime().getTime();
13520        // Roo.log(e);
13521         var ret = [];
13522         this.cells.each(function(c){
13523              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13524             
13525             if(c.dateValue > e){
13526                 return ;
13527             }
13528             if(c.dateValue < s){
13529                 return ;
13530             }
13531             ret.push(c);
13532         });
13533         
13534         return ret;    
13535     },
13536     
13537 //    findBestRow: function(cells)
13538 //    {
13539 //        var ret = 0;
13540 //        
13541 //        for (var i =0 ; i < cells.length;i++) {
13542 //            ret  = Math.max(cells[i].rows || 0,ret);
13543 //        }
13544 //        return ret;
13545 //        
13546 //    },
13547     
13548     
13549     addItem : function(ev)
13550     {
13551         // look for vertical location slot in
13552         var cells = this.findCells(ev);
13553         
13554 //        ev.row = this.findBestRow(cells);
13555         
13556         // work out the location.
13557         
13558         var crow = false;
13559         var rows = [];
13560         for(var i =0; i < cells.length; i++) {
13561             
13562             cells[i].row = cells[0].row;
13563             
13564             if(i == 0){
13565                 cells[i].row = cells[i].row + 1;
13566             }
13567             
13568             if (!crow) {
13569                 crow = {
13570                     start : cells[i],
13571                     end :  cells[i]
13572                 };
13573                 continue;
13574             }
13575             if (crow.start.getY() == cells[i].getY()) {
13576                 // on same row.
13577                 crow.end = cells[i];
13578                 continue;
13579             }
13580             // different row.
13581             rows.push(crow);
13582             crow = {
13583                 start: cells[i],
13584                 end : cells[i]
13585             };
13586             
13587         }
13588         
13589         rows.push(crow);
13590         ev.els = [];
13591         ev.rows = rows;
13592         ev.cells = cells;
13593         
13594         cells[0].events.push(ev);
13595         
13596         this.calevents.push(ev);
13597     },
13598     
13599     clearEvents: function() {
13600         
13601         if(!this.calevents){
13602             return;
13603         }
13604         
13605         Roo.each(this.cells.elements, function(c){
13606             c.row = 0;
13607             c.events = [];
13608             c.more = [];
13609         });
13610         
13611         Roo.each(this.calevents, function(e) {
13612             Roo.each(e.els, function(el) {
13613                 el.un('mouseenter' ,this.onEventEnter, this);
13614                 el.un('mouseleave' ,this.onEventLeave, this);
13615                 el.remove();
13616             },this);
13617         },this);
13618         
13619         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13620             e.remove();
13621         });
13622         
13623     },
13624     
13625     renderEvents: function()
13626     {   
13627         var _this = this;
13628         
13629         this.cells.each(function(c) {
13630             
13631             if(c.row < 5){
13632                 return;
13633             }
13634             
13635             var ev = c.events;
13636             
13637             var r = 4;
13638             if(c.row != c.events.length){
13639                 r = 4 - (4 - (c.row - c.events.length));
13640             }
13641             
13642             c.events = ev.slice(0, r);
13643             c.more = ev.slice(r);
13644             
13645             if(c.more.length && c.more.length == 1){
13646                 c.events.push(c.more.pop());
13647             }
13648             
13649             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13650             
13651         });
13652             
13653         this.cells.each(function(c) {
13654             
13655             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13656             
13657             
13658             for (var e = 0; e < c.events.length; e++){
13659                 var ev = c.events[e];
13660                 var rows = ev.rows;
13661                 
13662                 for(var i = 0; i < rows.length; i++) {
13663                 
13664                     // how many rows should it span..
13665
13666                     var  cfg = {
13667                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13668                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13669
13670                         unselectable : "on",
13671                         cn : [
13672                             {
13673                                 cls: 'fc-event-inner',
13674                                 cn : [
13675     //                                {
13676     //                                  tag:'span',
13677     //                                  cls: 'fc-event-time',
13678     //                                  html : cells.length > 1 ? '' : ev.time
13679     //                                },
13680                                     {
13681                                       tag:'span',
13682                                       cls: 'fc-event-title',
13683                                       html : String.format('{0}', ev.title)
13684                                     }
13685
13686
13687                                 ]
13688                             },
13689                             {
13690                                 cls: 'ui-resizable-handle ui-resizable-e',
13691                                 html : '&nbsp;&nbsp;&nbsp'
13692                             }
13693
13694                         ]
13695                     };
13696
13697                     if (i == 0) {
13698                         cfg.cls += ' fc-event-start';
13699                     }
13700                     if ((i+1) == rows.length) {
13701                         cfg.cls += ' fc-event-end';
13702                     }
13703
13704                     var ctr = _this.el.select('.fc-event-container',true).first();
13705                     var cg = ctr.createChild(cfg);
13706
13707                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13708                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13709
13710                     var r = (c.more.length) ? 1 : 0;
13711                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13712                     cg.setWidth(ebox.right - sbox.x -2);
13713
13714                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13715                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13716                     cg.on('click', _this.onEventClick, _this, ev);
13717
13718                     ev.els.push(cg);
13719                     
13720                 }
13721                 
13722             }
13723             
13724             
13725             if(c.more.length){
13726                 var  cfg = {
13727                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13728                     style : 'position: absolute',
13729                     unselectable : "on",
13730                     cn : [
13731                         {
13732                             cls: 'fc-event-inner',
13733                             cn : [
13734                                 {
13735                                   tag:'span',
13736                                   cls: 'fc-event-title',
13737                                   html : 'More'
13738                                 }
13739
13740
13741                             ]
13742                         },
13743                         {
13744                             cls: 'ui-resizable-handle ui-resizable-e',
13745                             html : '&nbsp;&nbsp;&nbsp'
13746                         }
13747
13748                     ]
13749                 };
13750
13751                 var ctr = _this.el.select('.fc-event-container',true).first();
13752                 var cg = ctr.createChild(cfg);
13753
13754                 var sbox = c.select('.fc-day-content',true).first().getBox();
13755                 var ebox = c.select('.fc-day-content',true).first().getBox();
13756                 //Roo.log(cg);
13757                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13758                 cg.setWidth(ebox.right - sbox.x -2);
13759
13760                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13761                 
13762             }
13763             
13764         });
13765         
13766         
13767         
13768     },
13769     
13770     onEventEnter: function (e, el,event,d) {
13771         this.fireEvent('evententer', this, el, event);
13772     },
13773     
13774     onEventLeave: function (e, el,event,d) {
13775         this.fireEvent('eventleave', this, el, event);
13776     },
13777     
13778     onEventClick: function (e, el,event,d) {
13779         this.fireEvent('eventclick', this, el, event);
13780     },
13781     
13782     onMonthChange: function () {
13783         this.store.load();
13784     },
13785     
13786     onMoreEventClick: function(e, el, more)
13787     {
13788         var _this = this;
13789         
13790         this.calpopover.placement = 'right';
13791         this.calpopover.setTitle('More');
13792         
13793         this.calpopover.setContent('');
13794         
13795         var ctr = this.calpopover.el.select('.popover-content', true).first();
13796         
13797         Roo.each(more, function(m){
13798             var cfg = {
13799                 cls : 'fc-event-hori fc-event-draggable',
13800                 html : m.title
13801             }
13802             var cg = ctr.createChild(cfg);
13803             
13804             cg.on('click', _this.onEventClick, _this, m);
13805         });
13806         
13807         this.calpopover.show(el);
13808         
13809         
13810     },
13811     
13812     onLoad: function () 
13813     {   
13814         this.calevents = [];
13815         var cal = this;
13816         
13817         if(this.store.getCount() > 0){
13818             this.store.data.each(function(d){
13819                cal.addItem({
13820                     id : d.data.id,
13821                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13822                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13823                     time : d.data.start_time,
13824                     title : d.data.title,
13825                     description : d.data.description,
13826                     venue : d.data.venue
13827                 });
13828             });
13829         }
13830         
13831         this.renderEvents();
13832         
13833         if(this.calevents.length && this.loadMask){
13834             this.maskEl.hide();
13835         }
13836     },
13837     
13838     onBeforeLoad: function()
13839     {
13840         this.clearEvents();
13841         if(this.loadMask){
13842             this.maskEl.show();
13843         }
13844     }
13845 });
13846
13847  
13848  /*
13849  * - LGPL
13850  *
13851  * element
13852  * 
13853  */
13854
13855 /**
13856  * @class Roo.bootstrap.Popover
13857  * @extends Roo.bootstrap.Component
13858  * Bootstrap Popover class
13859  * @cfg {String} html contents of the popover   (or false to use children..)
13860  * @cfg {String} title of popover (or false to hide)
13861  * @cfg {String} placement how it is placed
13862  * @cfg {String} trigger click || hover (or false to trigger manually)
13863  * @cfg {String} over what (parent or false to trigger manually.)
13864  * @cfg {Number} delay - delay before showing
13865  
13866  * @constructor
13867  * Create a new Popover
13868  * @param {Object} config The config object
13869  */
13870
13871 Roo.bootstrap.Popover = function(config){
13872     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13873 };
13874
13875 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13876     
13877     title: 'Fill in a title',
13878     html: false,
13879     
13880     placement : 'right',
13881     trigger : 'hover', // hover
13882     
13883     delay : 0,
13884     
13885     over: 'parent',
13886     
13887     can_build_overlaid : false,
13888     
13889     getChildContainer : function()
13890     {
13891         return this.el.select('.popover-content',true).first();
13892     },
13893     
13894     getAutoCreate : function(){
13895          Roo.log('make popover?');
13896         var cfg = {
13897            cls : 'popover roo-dynamic',
13898            style: 'display:block',
13899            cn : [
13900                 {
13901                     cls : 'arrow'
13902                 },
13903                 {
13904                     cls : 'popover-inner',
13905                     cn : [
13906                         {
13907                             tag: 'h3',
13908                             cls: 'popover-title',
13909                             html : this.title
13910                         },
13911                         {
13912                             cls : 'popover-content',
13913                             html : this.html
13914                         }
13915                     ]
13916                     
13917                 }
13918            ]
13919         };
13920         
13921         return cfg;
13922     },
13923     setTitle: function(str)
13924     {
13925         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13926     },
13927     setContent: function(str)
13928     {
13929         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13930     },
13931     // as it get's added to the bottom of the page.
13932     onRender : function(ct, position)
13933     {
13934         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13935         if(!this.el){
13936             var cfg = Roo.apply({},  this.getAutoCreate());
13937             cfg.id = Roo.id();
13938             
13939             if (this.cls) {
13940                 cfg.cls += ' ' + this.cls;
13941             }
13942             if (this.style) {
13943                 cfg.style = this.style;
13944             }
13945             Roo.log("adding to ")
13946             this.el = Roo.get(document.body).createChild(cfg, position);
13947             Roo.log(this.el);
13948         }
13949         this.initEvents();
13950     },
13951     
13952     initEvents : function()
13953     {
13954         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13955         this.el.enableDisplayMode('block');
13956         this.el.hide();
13957         if (this.over === false) {
13958             return; 
13959         }
13960         if (this.triggers === false) {
13961             return;
13962         }
13963         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13964         var triggers = this.trigger ? this.trigger.split(' ') : [];
13965         Roo.each(triggers, function(trigger) {
13966         
13967             if (trigger == 'click') {
13968                 on_el.on('click', this.toggle, this);
13969             } else if (trigger != 'manual') {
13970                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
13971                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
13972       
13973                 on_el.on(eventIn  ,this.enter, this);
13974                 on_el.on(eventOut, this.leave, this);
13975             }
13976         }, this);
13977         
13978     },
13979     
13980     
13981     // private
13982     timeout : null,
13983     hoverState : null,
13984     
13985     toggle : function () {
13986         this.hoverState == 'in' ? this.leave() : this.enter();
13987     },
13988     
13989     enter : function () {
13990        
13991     
13992         clearTimeout(this.timeout);
13993     
13994         this.hoverState = 'in';
13995     
13996         if (!this.delay || !this.delay.show) {
13997             this.show();
13998             return;
13999         }
14000         var _t = this;
14001         this.timeout = setTimeout(function () {
14002             if (_t.hoverState == 'in') {
14003                 _t.show();
14004             }
14005         }, this.delay.show)
14006     },
14007     leave : function() {
14008         clearTimeout(this.timeout);
14009     
14010         this.hoverState = 'out';
14011     
14012         if (!this.delay || !this.delay.hide) {
14013             this.hide();
14014             return;
14015         }
14016         var _t = this;
14017         this.timeout = setTimeout(function () {
14018             if (_t.hoverState == 'out') {
14019                 _t.hide();
14020             }
14021         }, this.delay.hide)
14022     },
14023     
14024     show : function (on_el)
14025     {
14026         if (!on_el) {
14027             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14028         }
14029         // set content.
14030         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14031         if (this.html !== false) {
14032             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14033         }
14034         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14035         if (!this.title.length) {
14036             this.el.select('.popover-title',true).hide();
14037         }
14038         
14039         var placement = typeof this.placement == 'function' ?
14040             this.placement.call(this, this.el, on_el) :
14041             this.placement;
14042             
14043         var autoToken = /\s?auto?\s?/i;
14044         var autoPlace = autoToken.test(placement);
14045         if (autoPlace) {
14046             placement = placement.replace(autoToken, '') || 'top';
14047         }
14048         
14049         //this.el.detach()
14050         //this.el.setXY([0,0]);
14051         this.el.show();
14052         this.el.dom.style.display='block';
14053         this.el.addClass(placement);
14054         
14055         //this.el.appendTo(on_el);
14056         
14057         var p = this.getPosition();
14058         var box = this.el.getBox();
14059         
14060         if (autoPlace) {
14061             // fixme..
14062         }
14063         var align = Roo.bootstrap.Popover.alignment[placement];
14064         this.el.alignTo(on_el, align[0],align[1]);
14065         //var arrow = this.el.select('.arrow',true).first();
14066         //arrow.set(align[2], 
14067         
14068         this.el.addClass('in');
14069         this.hoverState = null;
14070         
14071         if (this.el.hasClass('fade')) {
14072             // fade it?
14073         }
14074         
14075     },
14076     hide : function()
14077     {
14078         this.el.setXY([0,0]);
14079         this.el.removeClass('in');
14080         this.el.hide();
14081         
14082     }
14083     
14084 });
14085
14086 Roo.bootstrap.Popover.alignment = {
14087     'left' : ['r-l', [-10,0], 'right'],
14088     'right' : ['l-r', [10,0], 'left'],
14089     'bottom' : ['t-b', [0,10], 'top'],
14090     'top' : [ 'b-t', [0,-10], 'bottom']
14091 };
14092
14093  /*
14094  * - LGPL
14095  *
14096  * Progress
14097  * 
14098  */
14099
14100 /**
14101  * @class Roo.bootstrap.Progress
14102  * @extends Roo.bootstrap.Component
14103  * Bootstrap Progress class
14104  * @cfg {Boolean} striped striped of the progress bar
14105  * @cfg {Boolean} active animated of the progress bar
14106  * 
14107  * 
14108  * @constructor
14109  * Create a new Progress
14110  * @param {Object} config The config object
14111  */
14112
14113 Roo.bootstrap.Progress = function(config){
14114     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14115 };
14116
14117 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14118     
14119     striped : false,
14120     active: false,
14121     
14122     getAutoCreate : function(){
14123         var cfg = {
14124             tag: 'div',
14125             cls: 'progress'
14126         };
14127         
14128         
14129         if(this.striped){
14130             cfg.cls += ' progress-striped';
14131         }
14132       
14133         if(this.active){
14134             cfg.cls += ' active';
14135         }
14136         
14137         
14138         return cfg;
14139     }
14140    
14141 });
14142
14143  
14144
14145  /*
14146  * - LGPL
14147  *
14148  * ProgressBar
14149  * 
14150  */
14151
14152 /**
14153  * @class Roo.bootstrap.ProgressBar
14154  * @extends Roo.bootstrap.Component
14155  * Bootstrap ProgressBar class
14156  * @cfg {Number} aria_valuenow aria-value now
14157  * @cfg {Number} aria_valuemin aria-value min
14158  * @cfg {Number} aria_valuemax aria-value max
14159  * @cfg {String} label label for the progress bar
14160  * @cfg {String} panel (success | info | warning | danger )
14161  * @cfg {String} role role of the progress bar
14162  * @cfg {String} sr_only text
14163  * 
14164  * 
14165  * @constructor
14166  * Create a new ProgressBar
14167  * @param {Object} config The config object
14168  */
14169
14170 Roo.bootstrap.ProgressBar = function(config){
14171     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14172 };
14173
14174 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14175     
14176     aria_valuenow : 0,
14177     aria_valuemin : 0,
14178     aria_valuemax : 100,
14179     label : false,
14180     panel : false,
14181     role : false,
14182     sr_only: false,
14183     
14184     getAutoCreate : function()
14185     {
14186         
14187         var cfg = {
14188             tag: 'div',
14189             cls: 'progress-bar',
14190             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14191         };
14192         
14193         if(this.sr_only){
14194             cfg.cn = {
14195                 tag: 'span',
14196                 cls: 'sr-only',
14197                 html: this.sr_only
14198             }
14199         }
14200         
14201         if(this.role){
14202             cfg.role = this.role;
14203         }
14204         
14205         if(this.aria_valuenow){
14206             cfg['aria-valuenow'] = this.aria_valuenow;
14207         }
14208         
14209         if(this.aria_valuemin){
14210             cfg['aria-valuemin'] = this.aria_valuemin;
14211         }
14212         
14213         if(this.aria_valuemax){
14214             cfg['aria-valuemax'] = this.aria_valuemax;
14215         }
14216         
14217         if(this.label && !this.sr_only){
14218             cfg.html = this.label;
14219         }
14220         
14221         if(this.panel){
14222             cfg.cls += ' progress-bar-' + this.panel;
14223         }
14224         
14225         return cfg;
14226     },
14227     
14228     update : function(aria_valuenow)
14229     {
14230         this.aria_valuenow = aria_valuenow;
14231         
14232         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14233     }
14234    
14235 });
14236
14237  
14238
14239  /*
14240  * - LGPL
14241  *
14242  * column
14243  * 
14244  */
14245
14246 /**
14247  * @class Roo.bootstrap.TabGroup
14248  * @extends Roo.bootstrap.Column
14249  * Bootstrap Column class
14250  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14251  * @cfg {Boolean} carousel true to make the group behave like a carousel
14252  * 
14253  * @constructor
14254  * Create a new TabGroup
14255  * @param {Object} config The config object
14256  */
14257
14258 Roo.bootstrap.TabGroup = function(config){
14259     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14260     if (!this.navId) {
14261         this.navId = Roo.id();
14262     }
14263     this.tabs = [];
14264     Roo.bootstrap.TabGroup.register(this);
14265     
14266 };
14267
14268 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14269     
14270     carousel : false,
14271     transition : false,
14272      
14273     getAutoCreate : function()
14274     {
14275         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14276         
14277         cfg.cls += ' tab-content';
14278         
14279         if (this.carousel) {
14280             cfg.cls += ' carousel slide';
14281             cfg.cn = [{
14282                cls : 'carousel-inner'
14283             }]
14284         }
14285         
14286         
14287         return cfg;
14288     },
14289     getChildContainer : function()
14290     {
14291         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14292     },
14293     
14294     /**
14295     * register a Navigation item
14296     * @param {Roo.bootstrap.NavItem} the navitem to add
14297     */
14298     register : function(item)
14299     {
14300         this.tabs.push( item);
14301         item.navId = this.navId; // not really needed..
14302     
14303     },
14304     
14305     getActivePanel : function()
14306     {
14307         var r = false;
14308         Roo.each(this.tabs, function(t) {
14309             if (t.active) {
14310                 r = t;
14311                 return false;
14312             }
14313             return null;
14314         });
14315         return r;
14316         
14317     },
14318     getPanelByName : function(n)
14319     {
14320         var r = false;
14321         Roo.each(this.tabs, function(t) {
14322             if (t.tabId == n) {
14323                 r = t;
14324                 return false;
14325             }
14326             return null;
14327         });
14328         return r;
14329     },
14330     indexOfPanel : function(p)
14331     {
14332         var r = false;
14333         Roo.each(this.tabs, function(t,i) {
14334             if (t.tabId == p.tabId) {
14335                 r = i;
14336                 return false;
14337             }
14338             return null;
14339         });
14340         return r;
14341     },
14342     /**
14343      * show a specific panel
14344      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14345      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14346      */
14347     showPanel : function (pan)
14348     {
14349         
14350         if (typeof(pan) == 'number') {
14351             pan = this.tabs[pan];
14352         }
14353         if (typeof(pan) == 'string') {
14354             pan = this.getPanelByName(pan);
14355         }
14356         if (pan.tabId == this.getActivePanel().tabId) {
14357             return true;
14358         }
14359         var cur = this.getActivePanel();
14360         
14361         if (false === cur.fireEvent('beforedeactivate')) {
14362             return false;
14363         }
14364         
14365         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14366             
14367             this.transition = true;
14368             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14369             var lr = dir == 'next' ? 'left' : 'right';
14370             pan.el.addClass(dir); // or prev
14371             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14372             cur.el.addClass(lr); // or right
14373             pan.el.addClass(lr);
14374             
14375             var _this = this;
14376             cur.el.on('transitionend', function() {
14377                 Roo.log("trans end?");
14378                 
14379                 pan.el.removeClass([lr,dir]);
14380                 pan.setActive(true);
14381                 
14382                 cur.el.removeClass([lr]);
14383                 cur.setActive(false);
14384                 
14385                 _this.transition = false;
14386                 
14387             }, this, { single:  true } );
14388             return true;
14389         }
14390         
14391         cur.setActive(false);
14392         pan.setActive(true);
14393         return true;
14394         
14395     },
14396     showPanelNext : function()
14397     {
14398         var i = this.indexOfPanel(this.getActivePanel());
14399         if (i > this.tabs.length) {
14400             return;
14401         }
14402         this.showPanel(this.tabs[i+1]);
14403     },
14404     showPanelPrev : function()
14405     {
14406         var i = this.indexOfPanel(this.getActivePanel());
14407         if (i  < 1) {
14408             return;
14409         }
14410         this.showPanel(this.tabs[i-1]);
14411     }
14412     
14413     
14414   
14415 });
14416
14417  
14418
14419  
14420  
14421 Roo.apply(Roo.bootstrap.TabGroup, {
14422     
14423     groups: {},
14424      /**
14425     * register a Navigation Group
14426     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14427     */
14428     register : function(navgrp)
14429     {
14430         this.groups[navgrp.navId] = navgrp;
14431         
14432     },
14433     /**
14434     * fetch a Navigation Group based on the navigation ID
14435     * if one does not exist , it will get created.
14436     * @param {string} the navgroup to add
14437     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14438     */
14439     get: function(navId) {
14440         if (typeof(this.groups[navId]) == 'undefined') {
14441             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14442         }
14443         return this.groups[navId] ;
14444     }
14445     
14446     
14447     
14448 });
14449
14450  /*
14451  * - LGPL
14452  *
14453  * TabPanel
14454  * 
14455  */
14456
14457 /**
14458  * @class Roo.bootstrap.TabPanel
14459  * @extends Roo.bootstrap.Component
14460  * Bootstrap TabPanel class
14461  * @cfg {Boolean} active panel active
14462  * @cfg {String} html panel content
14463  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14464  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14465  * 
14466  * 
14467  * @constructor
14468  * Create a new TabPanel
14469  * @param {Object} config The config object
14470  */
14471
14472 Roo.bootstrap.TabPanel = function(config){
14473     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14474     this.addEvents({
14475         /**
14476              * @event changed
14477              * Fires when the active status changes
14478              * @param {Roo.bootstrap.TabPanel} this
14479              * @param {Boolean} state the new state
14480             
14481          */
14482         'changed': true,
14483         /**
14484              * @event beforedeactivate
14485              * Fires before a tab is de-activated - can be used to do validation on a form.
14486              * @param {Roo.bootstrap.TabPanel} this
14487              * @return {Boolean} false if there is an error
14488             
14489          */
14490         'beforedeactivate': true
14491      });
14492     
14493     this.tabId = this.tabId || Roo.id();
14494   
14495 };
14496
14497 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14498     
14499     active: false,
14500     html: false,
14501     tabId: false,
14502     navId : false,
14503     
14504     getAutoCreate : function(){
14505         var cfg = {
14506             tag: 'div',
14507             // item is needed for carousel - not sure if it has any effect otherwise
14508             cls: 'tab-pane item',
14509             html: this.html || ''
14510         };
14511         
14512         if(this.active){
14513             cfg.cls += ' active';
14514         }
14515         
14516         if(this.tabId){
14517             cfg.tabId = this.tabId;
14518         }
14519         
14520         
14521         return cfg;
14522     },
14523     
14524     initEvents:  function()
14525     {
14526         Roo.log('-------- init events on tab panel ---------');
14527         
14528         var p = this.parent();
14529         this.navId = this.navId || p.navId;
14530         
14531         if (typeof(this.navId) != 'undefined') {
14532             // not really needed.. but just in case.. parent should be a NavGroup.
14533             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14534             Roo.log(['register', tg, this]);
14535             tg.register(this);
14536         }
14537     },
14538     
14539     
14540     onRender : function(ct, position)
14541     {
14542        // Roo.log("Call onRender: " + this.xtype);
14543         
14544         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14545         
14546         
14547         
14548         
14549         
14550     },
14551     
14552     setActive: function(state)
14553     {
14554         Roo.log("panel - set active " + this.tabId + "=" + state);
14555         
14556         this.active = state;
14557         if (!state) {
14558             this.el.removeClass('active');
14559             
14560         } else  if (!this.el.hasClass('active')) {
14561             this.el.addClass('active');
14562         }
14563         this.fireEvent('changed', this, state);
14564     }
14565     
14566     
14567 });
14568  
14569
14570  
14571
14572  /*
14573  * - LGPL
14574  *
14575  * DateField
14576  * 
14577  */
14578
14579 /**
14580  * @class Roo.bootstrap.DateField
14581  * @extends Roo.bootstrap.Input
14582  * Bootstrap DateField class
14583  * @cfg {Number} weekStart default 0
14584  * @cfg {String} viewMode default empty, (months|years)
14585  * @cfg {String} minViewMode default empty, (months|years)
14586  * @cfg {Number} startDate default -Infinity
14587  * @cfg {Number} endDate default Infinity
14588  * @cfg {Boolean} todayHighlight default false
14589  * @cfg {Boolean} todayBtn default false
14590  * @cfg {Boolean} calendarWeeks default false
14591  * @cfg {Object} daysOfWeekDisabled default empty
14592  * @cfg {Boolean} singleMode default false (true | false)
14593  * 
14594  * @cfg {Boolean} keyboardNavigation default true
14595  * @cfg {String} language default en
14596  * 
14597  * @constructor
14598  * Create a new DateField
14599  * @param {Object} config The config object
14600  */
14601
14602 Roo.bootstrap.DateField = function(config){
14603     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14604      this.addEvents({
14605             /**
14606              * @event show
14607              * Fires when this field show.
14608              * @param {Roo.bootstrap.DateField} this
14609              * @param {Mixed} date The date value
14610              */
14611             show : true,
14612             /**
14613              * @event show
14614              * Fires when this field hide.
14615              * @param {Roo.bootstrap.DateField} this
14616              * @param {Mixed} date The date value
14617              */
14618             hide : true,
14619             /**
14620              * @event select
14621              * Fires when select a date.
14622              * @param {Roo.bootstrap.DateField} this
14623              * @param {Mixed} date The date value
14624              */
14625             select : true
14626         });
14627 };
14628
14629 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14630     
14631     /**
14632      * @cfg {String} format
14633      * The default date format string which can be overriden for localization support.  The format must be
14634      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14635      */
14636     format : "m/d/y",
14637     /**
14638      * @cfg {String} altFormats
14639      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14640      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14641      */
14642     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14643     
14644     weekStart : 0,
14645     
14646     viewMode : '',
14647     
14648     minViewMode : '',
14649     
14650     todayHighlight : false,
14651     
14652     todayBtn: false,
14653     
14654     language: 'en',
14655     
14656     keyboardNavigation: true,
14657     
14658     calendarWeeks: false,
14659     
14660     startDate: -Infinity,
14661     
14662     endDate: Infinity,
14663     
14664     daysOfWeekDisabled: [],
14665     
14666     _events: [],
14667     
14668     singleMode : false,
14669     
14670     UTCDate: function()
14671     {
14672         return new Date(Date.UTC.apply(Date, arguments));
14673     },
14674     
14675     UTCToday: function()
14676     {
14677         var today = new Date();
14678         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14679     },
14680     
14681     getDate: function() {
14682             var d = this.getUTCDate();
14683             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14684     },
14685     
14686     getUTCDate: function() {
14687             return this.date;
14688     },
14689     
14690     setDate: function(d) {
14691             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14692     },
14693     
14694     setUTCDate: function(d) {
14695             this.date = d;
14696             this.setValue(this.formatDate(this.date));
14697     },
14698         
14699     onRender: function(ct, position)
14700     {
14701         
14702         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14703         
14704         this.language = this.language || 'en';
14705         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14706         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14707         
14708         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14709         this.format = this.format || 'm/d/y';
14710         this.isInline = false;
14711         this.isInput = true;
14712         this.component = this.el.select('.add-on', true).first() || false;
14713         this.component = (this.component && this.component.length === 0) ? false : this.component;
14714         this.hasInput = this.component && this.inputEL().length;
14715         
14716         if (typeof(this.minViewMode === 'string')) {
14717             switch (this.minViewMode) {
14718                 case 'months':
14719                     this.minViewMode = 1;
14720                     break;
14721                 case 'years':
14722                     this.minViewMode = 2;
14723                     break;
14724                 default:
14725                     this.minViewMode = 0;
14726                     break;
14727             }
14728         }
14729         
14730         if (typeof(this.viewMode === 'string')) {
14731             switch (this.viewMode) {
14732                 case 'months':
14733                     this.viewMode = 1;
14734                     break;
14735                 case 'years':
14736                     this.viewMode = 2;
14737                     break;
14738                 default:
14739                     this.viewMode = 0;
14740                     break;
14741             }
14742         }
14743                 
14744         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14745         
14746 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14747         
14748         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14749         
14750         this.picker().on('mousedown', this.onMousedown, this);
14751         this.picker().on('click', this.onClick, this);
14752         
14753         this.picker().addClass('datepicker-dropdown');
14754         
14755         this.startViewMode = this.viewMode;
14756         
14757         if(this.singleMode){
14758             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14759                 v.setVisibilityMode(Roo.Element.DISPLAY)
14760                 v.hide();
14761             });
14762             
14763             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14764                 v.setStyle('width', '189px');
14765             });
14766         }
14767         
14768         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14769             if(!this.calendarWeeks){
14770                 v.remove();
14771                 return;
14772             }
14773             
14774             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14775             v.attr('colspan', function(i, val){
14776                 return parseInt(val) + 1;
14777             });
14778         })
14779                         
14780         
14781         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14782         
14783         this.setStartDate(this.startDate);
14784         this.setEndDate(this.endDate);
14785         
14786         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14787         
14788         this.fillDow();
14789         this.fillMonths();
14790         this.update();
14791         this.showMode();
14792         
14793         if(this.isInline) {
14794             this.show();
14795         }
14796     },
14797     
14798     picker : function()
14799     {
14800         return this.pickerEl;
14801 //        return this.el.select('.datepicker', true).first();
14802     },
14803     
14804     fillDow: function()
14805     {
14806         var dowCnt = this.weekStart;
14807         
14808         var dow = {
14809             tag: 'tr',
14810             cn: [
14811                 
14812             ]
14813         };
14814         
14815         if(this.calendarWeeks){
14816             dow.cn.push({
14817                 tag: 'th',
14818                 cls: 'cw',
14819                 html: '&nbsp;'
14820             })
14821         }
14822         
14823         while (dowCnt < this.weekStart + 7) {
14824             dow.cn.push({
14825                 tag: 'th',
14826                 cls: 'dow',
14827                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14828             });
14829         }
14830         
14831         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14832     },
14833     
14834     fillMonths: function()
14835     {    
14836         var i = 0;
14837         var months = this.picker().select('>.datepicker-months td', true).first();
14838         
14839         months.dom.innerHTML = '';
14840         
14841         while (i < 12) {
14842             var month = {
14843                 tag: 'span',
14844                 cls: 'month',
14845                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14846             }
14847             
14848             months.createChild(month);
14849         }
14850         
14851     },
14852     
14853     update: function()
14854     {
14855         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;
14856         
14857         if (this.date < this.startDate) {
14858             this.viewDate = new Date(this.startDate);
14859         } else if (this.date > this.endDate) {
14860             this.viewDate = new Date(this.endDate);
14861         } else {
14862             this.viewDate = new Date(this.date);
14863         }
14864         
14865         this.fill();
14866     },
14867     
14868     fill: function() 
14869     {
14870         var d = new Date(this.viewDate),
14871                 year = d.getUTCFullYear(),
14872                 month = d.getUTCMonth(),
14873                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14874                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14875                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14876                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14877                 currentDate = this.date && this.date.valueOf(),
14878                 today = this.UTCToday();
14879         
14880         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14881         
14882 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14883         
14884 //        this.picker.select('>tfoot th.today').
14885 //                                              .text(dates[this.language].today)
14886 //                                              .toggle(this.todayBtn !== false);
14887     
14888         this.updateNavArrows();
14889         this.fillMonths();
14890                                                 
14891         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14892         
14893         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14894          
14895         prevMonth.setUTCDate(day);
14896         
14897         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14898         
14899         var nextMonth = new Date(prevMonth);
14900         
14901         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14902         
14903         nextMonth = nextMonth.valueOf();
14904         
14905         var fillMonths = false;
14906         
14907         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14908         
14909         while(prevMonth.valueOf() < nextMonth) {
14910             var clsName = '';
14911             
14912             if (prevMonth.getUTCDay() === this.weekStart) {
14913                 if(fillMonths){
14914                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14915                 }
14916                     
14917                 fillMonths = {
14918                     tag: 'tr',
14919                     cn: []
14920                 };
14921                 
14922                 if(this.calendarWeeks){
14923                     // ISO 8601: First week contains first thursday.
14924                     // ISO also states week starts on Monday, but we can be more abstract here.
14925                     var
14926                     // Start of current week: based on weekstart/current date
14927                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14928                     // Thursday of this week
14929                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14930                     // First Thursday of year, year from thursday
14931                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14932                     // Calendar week: ms between thursdays, div ms per day, div 7 days
14933                     calWeek =  (th - yth) / 864e5 / 7 + 1;
14934                     
14935                     fillMonths.cn.push({
14936                         tag: 'td',
14937                         cls: 'cw',
14938                         html: calWeek
14939                     });
14940                 }
14941             }
14942             
14943             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14944                 clsName += ' old';
14945             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14946                 clsName += ' new';
14947             }
14948             if (this.todayHighlight &&
14949                 prevMonth.getUTCFullYear() == today.getFullYear() &&
14950                 prevMonth.getUTCMonth() == today.getMonth() &&
14951                 prevMonth.getUTCDate() == today.getDate()) {
14952                 clsName += ' today';
14953             }
14954             
14955             if (currentDate && prevMonth.valueOf() === currentDate) {
14956                 clsName += ' active';
14957             }
14958             
14959             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14960                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14961                     clsName += ' disabled';
14962             }
14963             
14964             fillMonths.cn.push({
14965                 tag: 'td',
14966                 cls: 'day ' + clsName,
14967                 html: prevMonth.getDate()
14968             })
14969             
14970             prevMonth.setDate(prevMonth.getDate()+1);
14971         }
14972           
14973         var currentYear = this.date && this.date.getUTCFullYear();
14974         var currentMonth = this.date && this.date.getUTCMonth();
14975         
14976         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14977         
14978         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14979             v.removeClass('active');
14980             
14981             if(currentYear === year && k === currentMonth){
14982                 v.addClass('active');
14983             }
14984             
14985             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14986                 v.addClass('disabled');
14987             }
14988             
14989         });
14990         
14991         
14992         year = parseInt(year/10, 10) * 10;
14993         
14994         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14995         
14996         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14997         
14998         year -= 1;
14999         for (var i = -1; i < 11; i++) {
15000             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15001                 tag: 'span',
15002                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15003                 html: year
15004             })
15005             
15006             year += 1;
15007         }
15008     },
15009     
15010     showMode: function(dir) 
15011     {
15012         if (dir) {
15013             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15014         }
15015         
15016         Roo.each(this.picker().select('>div',true).elements, function(v){
15017             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15018             v.hide();
15019         });
15020         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15021     },
15022     
15023     place: function()
15024     {
15025         if(this.isInline) return;
15026         
15027         this.picker().removeClass(['bottom', 'top']);
15028         
15029         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15030             /*
15031              * place to the top of element!
15032              *
15033              */
15034             
15035             this.picker().addClass('top');
15036             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15037             
15038             return;
15039         }
15040         
15041         this.picker().addClass('bottom');
15042         
15043         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15044     },
15045     
15046     parseDate : function(value)
15047     {
15048         if(!value || value instanceof Date){
15049             return value;
15050         }
15051         var v = Date.parseDate(value, this.format);
15052         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15053             v = Date.parseDate(value, 'Y-m-d');
15054         }
15055         if(!v && this.altFormats){
15056             if(!this.altFormatsArray){
15057                 this.altFormatsArray = this.altFormats.split("|");
15058             }
15059             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15060                 v = Date.parseDate(value, this.altFormatsArray[i]);
15061             }
15062         }
15063         return v;
15064     },
15065     
15066     formatDate : function(date, fmt)
15067     {   
15068         return (!date || !(date instanceof Date)) ?
15069         date : date.dateFormat(fmt || this.format);
15070     },
15071     
15072     onFocus : function()
15073     {
15074         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15075         this.show();
15076     },
15077     
15078     onBlur : function()
15079     {
15080         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15081         
15082         var d = this.inputEl().getValue();
15083         
15084         this.setValue(d);
15085                 
15086         this.hide();
15087     },
15088     
15089     show : function()
15090     {
15091         this.picker().show();
15092         this.update();
15093         this.place();
15094         
15095         this.fireEvent('show', this, this.date);
15096     },
15097     
15098     hide : function()
15099     {
15100         if(this.isInline) return;
15101         this.picker().hide();
15102         this.viewMode = this.startViewMode;
15103         this.showMode();
15104         
15105         this.fireEvent('hide', this, this.date);
15106         
15107     },
15108     
15109     onMousedown: function(e)
15110     {
15111         e.stopPropagation();
15112         e.preventDefault();
15113     },
15114     
15115     keyup: function(e)
15116     {
15117         Roo.bootstrap.DateField.superclass.keyup.call(this);
15118         this.update();
15119     },
15120
15121     setValue: function(v)
15122     {
15123         
15124         // v can be a string or a date..
15125         
15126         
15127         var d = new Date(this.parseDate(v) ).clearTime();
15128         
15129         if(isNaN(d.getTime())){
15130             this.date = this.viewDate = '';
15131             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15132             return;
15133         }
15134         
15135         v = this.formatDate(d);
15136         
15137         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15138         
15139         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15140      
15141         this.update();
15142
15143         this.fireEvent('select', this, this.date);
15144         
15145     },
15146     
15147     getValue: function()
15148     {
15149         return this.formatDate(this.date);
15150     },
15151     
15152     fireKey: function(e)
15153     {
15154         if (!this.picker().isVisible()){
15155             if (e.keyCode == 27) // allow escape to hide and re-show picker
15156                 this.show();
15157             return;
15158         }
15159         
15160         var dateChanged = false,
15161         dir, day, month,
15162         newDate, newViewDate;
15163         
15164         switch(e.keyCode){
15165             case 27: // escape
15166                 this.hide();
15167                 e.preventDefault();
15168                 break;
15169             case 37: // left
15170             case 39: // right
15171                 if (!this.keyboardNavigation) break;
15172                 dir = e.keyCode == 37 ? -1 : 1;
15173                 
15174                 if (e.ctrlKey){
15175                     newDate = this.moveYear(this.date, dir);
15176                     newViewDate = this.moveYear(this.viewDate, dir);
15177                 } else if (e.shiftKey){
15178                     newDate = this.moveMonth(this.date, dir);
15179                     newViewDate = this.moveMonth(this.viewDate, dir);
15180                 } else {
15181                     newDate = new Date(this.date);
15182                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15183                     newViewDate = new Date(this.viewDate);
15184                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15185                 }
15186                 if (this.dateWithinRange(newDate)){
15187                     this.date = newDate;
15188                     this.viewDate = newViewDate;
15189                     this.setValue(this.formatDate(this.date));
15190 //                    this.update();
15191                     e.preventDefault();
15192                     dateChanged = true;
15193                 }
15194                 break;
15195             case 38: // up
15196             case 40: // down
15197                 if (!this.keyboardNavigation) break;
15198                 dir = e.keyCode == 38 ? -1 : 1;
15199                 if (e.ctrlKey){
15200                     newDate = this.moveYear(this.date, dir);
15201                     newViewDate = this.moveYear(this.viewDate, dir);
15202                 } else if (e.shiftKey){
15203                     newDate = this.moveMonth(this.date, dir);
15204                     newViewDate = this.moveMonth(this.viewDate, dir);
15205                 } else {
15206                     newDate = new Date(this.date);
15207                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15208                     newViewDate = new Date(this.viewDate);
15209                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15210                 }
15211                 if (this.dateWithinRange(newDate)){
15212                     this.date = newDate;
15213                     this.viewDate = newViewDate;
15214                     this.setValue(this.formatDate(this.date));
15215 //                    this.update();
15216                     e.preventDefault();
15217                     dateChanged = true;
15218                 }
15219                 break;
15220             case 13: // enter
15221                 this.setValue(this.formatDate(this.date));
15222                 this.hide();
15223                 e.preventDefault();
15224                 break;
15225             case 9: // tab
15226                 this.setValue(this.formatDate(this.date));
15227                 this.hide();
15228                 break;
15229             case 16: // shift
15230             case 17: // ctrl
15231             case 18: // alt
15232                 break;
15233             default :
15234                 this.hide();
15235                 
15236         }
15237     },
15238     
15239     
15240     onClick: function(e) 
15241     {
15242         e.stopPropagation();
15243         e.preventDefault();
15244         
15245         var target = e.getTarget();
15246         
15247         if(target.nodeName.toLowerCase() === 'i'){
15248             target = Roo.get(target).dom.parentNode;
15249         }
15250         
15251         var nodeName = target.nodeName;
15252         var className = target.className;
15253         var html = target.innerHTML;
15254         //Roo.log(nodeName);
15255         
15256         switch(nodeName.toLowerCase()) {
15257             case 'th':
15258                 switch(className) {
15259                     case 'switch':
15260                         this.showMode(1);
15261                         break;
15262                     case 'prev':
15263                     case 'next':
15264                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15265                         switch(this.viewMode){
15266                                 case 0:
15267                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15268                                         break;
15269                                 case 1:
15270                                 case 2:
15271                                         this.viewDate = this.moveYear(this.viewDate, dir);
15272                                         break;
15273                         }
15274                         this.fill();
15275                         break;
15276                     case 'today':
15277                         var date = new Date();
15278                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15279 //                        this.fill()
15280                         this.setValue(this.formatDate(this.date));
15281                         
15282                         this.hide();
15283                         break;
15284                 }
15285                 break;
15286             case 'span':
15287                 if (className.indexOf('disabled') < 0) {
15288                     this.viewDate.setUTCDate(1);
15289                     if (className.indexOf('month') > -1) {
15290                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15291                     } else {
15292                         var year = parseInt(html, 10) || 0;
15293                         this.viewDate.setUTCFullYear(year);
15294                         
15295                     }
15296                     
15297                     if(this.singleMode){
15298                         this.setValue(this.formatDate(this.viewDate));
15299                         this.hide();
15300                         return;
15301                     }
15302                     
15303                     this.showMode(-1);
15304                     this.fill();
15305                 }
15306                 break;
15307                 
15308             case 'td':
15309                 //Roo.log(className);
15310                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15311                     var day = parseInt(html, 10) || 1;
15312                     var year = this.viewDate.getUTCFullYear(),
15313                         month = this.viewDate.getUTCMonth();
15314
15315                     if (className.indexOf('old') > -1) {
15316                         if(month === 0 ){
15317                             month = 11;
15318                             year -= 1;
15319                         }else{
15320                             month -= 1;
15321                         }
15322                     } else if (className.indexOf('new') > -1) {
15323                         if (month == 11) {
15324                             month = 0;
15325                             year += 1;
15326                         } else {
15327                             month += 1;
15328                         }
15329                     }
15330                     //Roo.log([year,month,day]);
15331                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15332                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15333 //                    this.fill();
15334                     //Roo.log(this.formatDate(this.date));
15335                     this.setValue(this.formatDate(this.date));
15336                     this.hide();
15337                 }
15338                 break;
15339         }
15340     },
15341     
15342     setStartDate: function(startDate)
15343     {
15344         this.startDate = startDate || -Infinity;
15345         if (this.startDate !== -Infinity) {
15346             this.startDate = this.parseDate(this.startDate);
15347         }
15348         this.update();
15349         this.updateNavArrows();
15350     },
15351
15352     setEndDate: function(endDate)
15353     {
15354         this.endDate = endDate || Infinity;
15355         if (this.endDate !== Infinity) {
15356             this.endDate = this.parseDate(this.endDate);
15357         }
15358         this.update();
15359         this.updateNavArrows();
15360     },
15361     
15362     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15363     {
15364         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15365         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15366             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15367         }
15368         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15369             return parseInt(d, 10);
15370         });
15371         this.update();
15372         this.updateNavArrows();
15373     },
15374     
15375     updateNavArrows: function() 
15376     {
15377         if(this.singleMode){
15378             return;
15379         }
15380         
15381         var d = new Date(this.viewDate),
15382         year = d.getUTCFullYear(),
15383         month = d.getUTCMonth();
15384         
15385         Roo.each(this.picker().select('.prev', true).elements, function(v){
15386             v.show();
15387             switch (this.viewMode) {
15388                 case 0:
15389
15390                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15391                         v.hide();
15392                     }
15393                     break;
15394                 case 1:
15395                 case 2:
15396                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15397                         v.hide();
15398                     }
15399                     break;
15400             }
15401         });
15402         
15403         Roo.each(this.picker().select('.next', true).elements, function(v){
15404             v.show();
15405             switch (this.viewMode) {
15406                 case 0:
15407
15408                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15409                         v.hide();
15410                     }
15411                     break;
15412                 case 1:
15413                 case 2:
15414                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15415                         v.hide();
15416                     }
15417                     break;
15418             }
15419         })
15420     },
15421     
15422     moveMonth: function(date, dir)
15423     {
15424         if (!dir) return date;
15425         var new_date = new Date(date.valueOf()),
15426         day = new_date.getUTCDate(),
15427         month = new_date.getUTCMonth(),
15428         mag = Math.abs(dir),
15429         new_month, test;
15430         dir = dir > 0 ? 1 : -1;
15431         if (mag == 1){
15432             test = dir == -1
15433             // If going back one month, make sure month is not current month
15434             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15435             ? function(){
15436                 return new_date.getUTCMonth() == month;
15437             }
15438             // If going forward one month, make sure month is as expected
15439             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15440             : function(){
15441                 return new_date.getUTCMonth() != new_month;
15442             };
15443             new_month = month + dir;
15444             new_date.setUTCMonth(new_month);
15445             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15446             if (new_month < 0 || new_month > 11)
15447                 new_month = (new_month + 12) % 12;
15448         } else {
15449             // For magnitudes >1, move one month at a time...
15450             for (var i=0; i<mag; i++)
15451                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15452                 new_date = this.moveMonth(new_date, dir);
15453             // ...then reset the day, keeping it in the new month
15454             new_month = new_date.getUTCMonth();
15455             new_date.setUTCDate(day);
15456             test = function(){
15457                 return new_month != new_date.getUTCMonth();
15458             };
15459         }
15460         // Common date-resetting loop -- if date is beyond end of month, make it
15461         // end of month
15462         while (test()){
15463             new_date.setUTCDate(--day);
15464             new_date.setUTCMonth(new_month);
15465         }
15466         return new_date;
15467     },
15468
15469     moveYear: function(date, dir)
15470     {
15471         return this.moveMonth(date, dir*12);
15472     },
15473
15474     dateWithinRange: function(date)
15475     {
15476         return date >= this.startDate && date <= this.endDate;
15477     },
15478
15479     
15480     remove: function() 
15481     {
15482         this.picker().remove();
15483     }
15484    
15485 });
15486
15487 Roo.apply(Roo.bootstrap.DateField,  {
15488     
15489     head : {
15490         tag: 'thead',
15491         cn: [
15492         {
15493             tag: 'tr',
15494             cn: [
15495             {
15496                 tag: 'th',
15497                 cls: 'prev',
15498                 html: '<i class="fa fa-arrow-left"/>'
15499             },
15500             {
15501                 tag: 'th',
15502                 cls: 'switch',
15503                 colspan: '5'
15504             },
15505             {
15506                 tag: 'th',
15507                 cls: 'next',
15508                 html: '<i class="fa fa-arrow-right"/>'
15509             }
15510
15511             ]
15512         }
15513         ]
15514     },
15515     
15516     content : {
15517         tag: 'tbody',
15518         cn: [
15519         {
15520             tag: 'tr',
15521             cn: [
15522             {
15523                 tag: 'td',
15524                 colspan: '7'
15525             }
15526             ]
15527         }
15528         ]
15529     },
15530     
15531     footer : {
15532         tag: 'tfoot',
15533         cn: [
15534         {
15535             tag: 'tr',
15536             cn: [
15537             {
15538                 tag: 'th',
15539                 colspan: '7',
15540                 cls: 'today'
15541             }
15542                     
15543             ]
15544         }
15545         ]
15546     },
15547     
15548     dates:{
15549         en: {
15550             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15551             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15552             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15553             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15554             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15555             today: "Today"
15556         }
15557     },
15558     
15559     modes: [
15560     {
15561         clsName: 'days',
15562         navFnc: 'Month',
15563         navStep: 1
15564     },
15565     {
15566         clsName: 'months',
15567         navFnc: 'FullYear',
15568         navStep: 1
15569     },
15570     {
15571         clsName: 'years',
15572         navFnc: 'FullYear',
15573         navStep: 10
15574     }]
15575 });
15576
15577 Roo.apply(Roo.bootstrap.DateField,  {
15578   
15579     template : {
15580         tag: 'div',
15581         cls: 'datepicker dropdown-menu roo-dynamic',
15582         cn: [
15583         {
15584             tag: 'div',
15585             cls: 'datepicker-days',
15586             cn: [
15587             {
15588                 tag: 'table',
15589                 cls: 'table-condensed',
15590                 cn:[
15591                 Roo.bootstrap.DateField.head,
15592                 {
15593                     tag: 'tbody'
15594                 },
15595                 Roo.bootstrap.DateField.footer
15596                 ]
15597             }
15598             ]
15599         },
15600         {
15601             tag: 'div',
15602             cls: 'datepicker-months',
15603             cn: [
15604             {
15605                 tag: 'table',
15606                 cls: 'table-condensed',
15607                 cn:[
15608                 Roo.bootstrap.DateField.head,
15609                 Roo.bootstrap.DateField.content,
15610                 Roo.bootstrap.DateField.footer
15611                 ]
15612             }
15613             ]
15614         },
15615         {
15616             tag: 'div',
15617             cls: 'datepicker-years',
15618             cn: [
15619             {
15620                 tag: 'table',
15621                 cls: 'table-condensed',
15622                 cn:[
15623                 Roo.bootstrap.DateField.head,
15624                 Roo.bootstrap.DateField.content,
15625                 Roo.bootstrap.DateField.footer
15626                 ]
15627             }
15628             ]
15629         }
15630         ]
15631     }
15632 });
15633
15634  
15635
15636  /*
15637  * - LGPL
15638  *
15639  * TimeField
15640  * 
15641  */
15642
15643 /**
15644  * @class Roo.bootstrap.TimeField
15645  * @extends Roo.bootstrap.Input
15646  * Bootstrap DateField class
15647  * 
15648  * 
15649  * @constructor
15650  * Create a new TimeField
15651  * @param {Object} config The config object
15652  */
15653
15654 Roo.bootstrap.TimeField = function(config){
15655     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15656     this.addEvents({
15657             /**
15658              * @event show
15659              * Fires when this field show.
15660              * @param {Roo.bootstrap.DateField} thisthis
15661              * @param {Mixed} date The date value
15662              */
15663             show : true,
15664             /**
15665              * @event show
15666              * Fires when this field hide.
15667              * @param {Roo.bootstrap.DateField} this
15668              * @param {Mixed} date The date value
15669              */
15670             hide : true,
15671             /**
15672              * @event select
15673              * Fires when select a date.
15674              * @param {Roo.bootstrap.DateField} this
15675              * @param {Mixed} date The date value
15676              */
15677             select : true
15678         });
15679 };
15680
15681 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15682     
15683     /**
15684      * @cfg {String} format
15685      * The default time format string which can be overriden for localization support.  The format must be
15686      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15687      */
15688     format : "H:i",
15689        
15690     onRender: function(ct, position)
15691     {
15692         
15693         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15694                 
15695         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15696         
15697         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15698         
15699         this.pop = this.picker().select('>.datepicker-time',true).first();
15700         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15701         
15702         this.picker().on('mousedown', this.onMousedown, this);
15703         this.picker().on('click', this.onClick, this);
15704         
15705         this.picker().addClass('datepicker-dropdown');
15706     
15707         this.fillTime();
15708         this.update();
15709             
15710         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15711         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15712         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15713         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15714         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15715         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15716
15717     },
15718     
15719     fireKey: function(e){
15720         if (!this.picker().isVisible()){
15721             if (e.keyCode == 27) { // allow escape to hide and re-show picker
15722                 this.show();
15723             }
15724             return;
15725         }
15726
15727         e.preventDefault();
15728         
15729         switch(e.keyCode){
15730             case 27: // escape
15731                 this.hide();
15732                 break;
15733             case 37: // left
15734             case 39: // right
15735                 this.onTogglePeriod();
15736                 break;
15737             case 38: // up
15738                 this.onIncrementMinutes();
15739                 break;
15740             case 40: // down
15741                 this.onDecrementMinutes();
15742                 break;
15743             case 13: // enter
15744             case 9: // tab
15745                 this.setTime();
15746                 break;
15747         }
15748     },
15749     
15750     onClick: function(e) {
15751         e.stopPropagation();
15752         e.preventDefault();
15753     },
15754     
15755     picker : function()
15756     {
15757         return this.el.select('.datepicker', true).first();
15758     },
15759     
15760     fillTime: function()
15761     {    
15762         var time = this.pop.select('tbody', true).first();
15763         
15764         time.dom.innerHTML = '';
15765         
15766         time.createChild({
15767             tag: 'tr',
15768             cn: [
15769                 {
15770                     tag: 'td',
15771                     cn: [
15772                         {
15773                             tag: 'a',
15774                             href: '#',
15775                             cls: 'btn',
15776                             cn: [
15777                                 {
15778                                     tag: 'span',
15779                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15780                                 }
15781                             ]
15782                         } 
15783                     ]
15784                 },
15785                 {
15786                     tag: 'td',
15787                     cls: 'separator'
15788                 },
15789                 {
15790                     tag: 'td',
15791                     cn: [
15792                         {
15793                             tag: 'a',
15794                             href: '#',
15795                             cls: 'btn',
15796                             cn: [
15797                                 {
15798                                     tag: 'span',
15799                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15800                                 }
15801                             ]
15802                         }
15803                     ]
15804                 },
15805                 {
15806                     tag: 'td',
15807                     cls: 'separator'
15808                 }
15809             ]
15810         });
15811         
15812         time.createChild({
15813             tag: 'tr',
15814             cn: [
15815                 {
15816                     tag: 'td',
15817                     cn: [
15818                         {
15819                             tag: 'span',
15820                             cls: 'timepicker-hour',
15821                             html: '00'
15822                         }  
15823                     ]
15824                 },
15825                 {
15826                     tag: 'td',
15827                     cls: 'separator',
15828                     html: ':'
15829                 },
15830                 {
15831                     tag: 'td',
15832                     cn: [
15833                         {
15834                             tag: 'span',
15835                             cls: 'timepicker-minute',
15836                             html: '00'
15837                         }  
15838                     ]
15839                 },
15840                 {
15841                     tag: 'td',
15842                     cls: 'separator'
15843                 },
15844                 {
15845                     tag: 'td',
15846                     cn: [
15847                         {
15848                             tag: 'button',
15849                             type: 'button',
15850                             cls: 'btn btn-primary period',
15851                             html: 'AM'
15852                             
15853                         }
15854                     ]
15855                 }
15856             ]
15857         });
15858         
15859         time.createChild({
15860             tag: 'tr',
15861             cn: [
15862                 {
15863                     tag: 'td',
15864                     cn: [
15865                         {
15866                             tag: 'a',
15867                             href: '#',
15868                             cls: 'btn',
15869                             cn: [
15870                                 {
15871                                     tag: 'span',
15872                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
15873                                 }
15874                             ]
15875                         }
15876                     ]
15877                 },
15878                 {
15879                     tag: 'td',
15880                     cls: 'separator'
15881                 },
15882                 {
15883                     tag: 'td',
15884                     cn: [
15885                         {
15886                             tag: 'a',
15887                             href: '#',
15888                             cls: 'btn',
15889                             cn: [
15890                                 {
15891                                     tag: 'span',
15892                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
15893                                 }
15894                             ]
15895                         }
15896                     ]
15897                 },
15898                 {
15899                     tag: 'td',
15900                     cls: 'separator'
15901                 }
15902             ]
15903         });
15904         
15905     },
15906     
15907     update: function()
15908     {
15909         
15910         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15911         
15912         this.fill();
15913     },
15914     
15915     fill: function() 
15916     {
15917         var hours = this.time.getHours();
15918         var minutes = this.time.getMinutes();
15919         var period = 'AM';
15920         
15921         if(hours > 11){
15922             period = 'PM';
15923         }
15924         
15925         if(hours == 0){
15926             hours = 12;
15927         }
15928         
15929         
15930         if(hours > 12){
15931             hours = hours - 12;
15932         }
15933         
15934         if(hours < 10){
15935             hours = '0' + hours;
15936         }
15937         
15938         if(minutes < 10){
15939             minutes = '0' + minutes;
15940         }
15941         
15942         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15943         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15944         this.pop.select('button', true).first().dom.innerHTML = period;
15945         
15946     },
15947     
15948     place: function()
15949     {   
15950         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15951         
15952         var cls = ['bottom'];
15953         
15954         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15955             cls.pop();
15956             cls.push('top');
15957         }
15958         
15959         cls.push('right');
15960         
15961         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15962             cls.pop();
15963             cls.push('left');
15964         }
15965         
15966         this.picker().addClass(cls.join('-'));
15967         
15968         var _this = this;
15969         
15970         Roo.each(cls, function(c){
15971             if(c == 'bottom'){
15972                 _this.picker().setTop(_this.inputEl().getHeight());
15973                 return;
15974             }
15975             if(c == 'top'){
15976                 _this.picker().setTop(0 - _this.picker().getHeight());
15977                 return;
15978             }
15979             
15980             if(c == 'left'){
15981                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15982                 return;
15983             }
15984             if(c == 'right'){
15985                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15986                 return;
15987             }
15988         });
15989         
15990     },
15991   
15992     onFocus : function()
15993     {
15994         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15995         this.show();
15996     },
15997     
15998     onBlur : function()
15999     {
16000         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16001         this.hide();
16002     },
16003     
16004     show : function()
16005     {
16006         this.picker().show();
16007         this.pop.show();
16008         this.update();
16009         this.place();
16010         
16011         this.fireEvent('show', this, this.date);
16012     },
16013     
16014     hide : function()
16015     {
16016         this.picker().hide();
16017         this.pop.hide();
16018         
16019         this.fireEvent('hide', this, this.date);
16020     },
16021     
16022     setTime : function()
16023     {
16024         this.hide();
16025         this.setValue(this.time.format(this.format));
16026         
16027         this.fireEvent('select', this, this.date);
16028         
16029         
16030     },
16031     
16032     onMousedown: function(e){
16033         e.stopPropagation();
16034         e.preventDefault();
16035     },
16036     
16037     onIncrementHours: function()
16038     {
16039         Roo.log('onIncrementHours');
16040         this.time = this.time.add(Date.HOUR, 1);
16041         this.update();
16042         
16043     },
16044     
16045     onDecrementHours: function()
16046     {
16047         Roo.log('onDecrementHours');
16048         this.time = this.time.add(Date.HOUR, -1);
16049         this.update();
16050     },
16051     
16052     onIncrementMinutes: function()
16053     {
16054         Roo.log('onIncrementMinutes');
16055         this.time = this.time.add(Date.MINUTE, 1);
16056         this.update();
16057     },
16058     
16059     onDecrementMinutes: function()
16060     {
16061         Roo.log('onDecrementMinutes');
16062         this.time = this.time.add(Date.MINUTE, -1);
16063         this.update();
16064     },
16065     
16066     onTogglePeriod: function()
16067     {
16068         Roo.log('onTogglePeriod');
16069         this.time = this.time.add(Date.HOUR, 12);
16070         this.update();
16071     }
16072     
16073    
16074 });
16075
16076 Roo.apply(Roo.bootstrap.TimeField,  {
16077     
16078     content : {
16079         tag: 'tbody',
16080         cn: [
16081             {
16082                 tag: 'tr',
16083                 cn: [
16084                 {
16085                     tag: 'td',
16086                     colspan: '7'
16087                 }
16088                 ]
16089             }
16090         ]
16091     },
16092     
16093     footer : {
16094         tag: 'tfoot',
16095         cn: [
16096             {
16097                 tag: 'tr',
16098                 cn: [
16099                 {
16100                     tag: 'th',
16101                     colspan: '7',
16102                     cls: '',
16103                     cn: [
16104                         {
16105                             tag: 'button',
16106                             cls: 'btn btn-info ok',
16107                             html: 'OK'
16108                         }
16109                     ]
16110                 }
16111
16112                 ]
16113             }
16114         ]
16115     }
16116 });
16117
16118 Roo.apply(Roo.bootstrap.TimeField,  {
16119   
16120     template : {
16121         tag: 'div',
16122         cls: 'datepicker dropdown-menu',
16123         cn: [
16124             {
16125                 tag: 'div',
16126                 cls: 'datepicker-time',
16127                 cn: [
16128                 {
16129                     tag: 'table',
16130                     cls: 'table-condensed',
16131                     cn:[
16132                     Roo.bootstrap.TimeField.content,
16133                     Roo.bootstrap.TimeField.footer
16134                     ]
16135                 }
16136                 ]
16137             }
16138         ]
16139     }
16140 });
16141
16142  
16143
16144  /*
16145  * - LGPL
16146  *
16147  * MonthField
16148  * 
16149  */
16150
16151 /**
16152  * @class Roo.bootstrap.MonthField
16153  * @extends Roo.bootstrap.Input
16154  * Bootstrap MonthField class
16155  * 
16156  * @cfg {String} language default en
16157  * 
16158  * @constructor
16159  * Create a new MonthField
16160  * @param {Object} config The config object
16161  */
16162
16163 Roo.bootstrap.MonthField = function(config){
16164     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16165     
16166     this.addEvents({
16167         /**
16168          * @event show
16169          * Fires when this field show.
16170          * @param {Roo.bootstrap.MonthField} this
16171          * @param {Mixed} date The date value
16172          */
16173         show : true,
16174         /**
16175          * @event show
16176          * Fires when this field hide.
16177          * @param {Roo.bootstrap.MonthField} this
16178          * @param {Mixed} date The date value
16179          */
16180         hide : true,
16181         /**
16182          * @event select
16183          * Fires when select a date.
16184          * @param {Roo.bootstrap.MonthField} this
16185          * @param {Mixed} date The date value
16186          */
16187         select : true
16188     });
16189 };
16190
16191 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16192     
16193     onRender: function(ct, position)
16194     {
16195         
16196         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16197         
16198         this.language = this.language || 'en';
16199         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16200         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16201         
16202         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16203         this.isInline = false;
16204         this.isInput = true;
16205         this.component = this.el.select('.add-on', true).first() || false;
16206         this.component = (this.component && this.component.length === 0) ? false : this.component;
16207         this.hasInput = this.component && this.inputEL().length;
16208         
16209         this.minViewMode = 1;
16210         this.viewMode = 1;
16211                 
16212         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16213         
16214         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16215         
16216         this.picker().on('mousedown', this.onMousedown, this);
16217         this.picker().on('click', this.onClick, this);
16218         
16219         this.picker().addClass('datepicker-dropdown');
16220         
16221         this.startViewMode = this.viewMode;
16222
16223         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16224             v.setStyle('width', '189px');
16225         });
16226         
16227         this.fillMonths();
16228         this.update();
16229         
16230         if(this.isInline) {
16231             this.show();
16232         }
16233     },
16234     
16235     setValue: function(v)
16236     {   
16237         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16238         
16239         this.update();
16240
16241         this.fireEvent('select', this, this.date);
16242         
16243     },
16244     
16245     getValue: function()
16246     {
16247         return this.value;
16248     },
16249     
16250     onClick: function(e) 
16251     {
16252         e.stopPropagation();
16253         e.preventDefault();
16254         
16255         var target = e.getTarget();
16256         
16257         if(target.nodeName.toLowerCase() === 'i'){
16258             target = Roo.get(target).dom.parentNode;
16259         }
16260         
16261         var nodeName = target.nodeName;
16262         var className = target.className;
16263         var html = target.innerHTML;
16264         
16265         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16266             return;
16267         }
16268         
16269         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16270         
16271         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16272         
16273         this.hide();
16274                         
16275     },
16276     
16277     picker : function()
16278     {
16279         return this.pickerEl;
16280     },
16281     
16282     fillMonths: function()
16283     {    
16284         var i = 0
16285         var months = this.picker().select('>.datepicker-months td', true).first();
16286         
16287         months.dom.innerHTML = '';
16288         
16289         while (i < 12) {
16290             var month = {
16291                 tag: 'span',
16292                 cls: 'month',
16293                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16294             }
16295             
16296             months.createChild(month);
16297         }
16298         
16299     },
16300     
16301     update: function()
16302     {
16303         var _this = this;
16304         
16305         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16306             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16307         }
16308         
16309         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16310             e.removeClass('active');
16311             
16312             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16313                 e.addClass('active');
16314             }
16315         })
16316     },
16317     
16318     place: function()
16319     {
16320         if(this.isInline) return;
16321         
16322         this.picker().removeClass(['bottom', 'top']);
16323         
16324         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16325             /*
16326              * place to the top of element!
16327              *
16328              */
16329             
16330             this.picker().addClass('top');
16331             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16332             
16333             return;
16334         }
16335         
16336         this.picker().addClass('bottom');
16337         
16338         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16339     },
16340     
16341     onFocus : function()
16342     {
16343         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16344         this.show();
16345     },
16346     
16347     onBlur : function()
16348     {
16349         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16350         
16351         var d = this.inputEl().getValue();
16352         
16353         this.setValue(d);
16354                 
16355         this.hide();
16356     },
16357     
16358     show : function()
16359     {
16360         this.picker().show();
16361         this.picker().select('>.datepicker-months', true).first().show();
16362         this.update();
16363         this.place();
16364         
16365         this.fireEvent('show', this, this.date);
16366     },
16367     
16368     hide : function()
16369     {
16370         if(this.isInline) return;
16371         this.picker().hide();
16372         this.fireEvent('hide', this, this.date);
16373         
16374     },
16375     
16376     onMousedown: function(e)
16377     {
16378         e.stopPropagation();
16379         e.preventDefault();
16380     },
16381     
16382     keyup: function(e)
16383     {
16384         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16385         this.update();
16386     },
16387
16388     fireKey: function(e)
16389     {
16390         if (!this.picker().isVisible()){
16391             if (e.keyCode == 27) // allow escape to hide and re-show picker
16392                 this.show();
16393             return;
16394         }
16395         
16396         var dir;
16397         
16398         switch(e.keyCode){
16399             case 27: // escape
16400                 this.hide();
16401                 e.preventDefault();
16402                 break;
16403             case 37: // left
16404             case 39: // right
16405                 dir = e.keyCode == 37 ? -1 : 1;
16406                 
16407                 this.vIndex = this.vIndex + dir;
16408                 
16409                 if(this.vIndex < 0){
16410                     this.vIndex = 0;
16411                 }
16412                 
16413                 if(this.vIndex > 11){
16414                     this.vIndex = 11;
16415                 }
16416                 
16417                 if(isNaN(this.vIndex)){
16418                     this.vIndex = 0;
16419                 }
16420                 
16421                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16422                 
16423                 break;
16424             case 38: // up
16425             case 40: // down
16426                 
16427                 dir = e.keyCode == 38 ? -1 : 1;
16428                 
16429                 this.vIndex = this.vIndex + dir * 4;
16430                 
16431                 if(this.vIndex < 0){
16432                     this.vIndex = 0;
16433                 }
16434                 
16435                 if(this.vIndex > 11){
16436                     this.vIndex = 11;
16437                 }
16438                 
16439                 if(isNaN(this.vIndex)){
16440                     this.vIndex = 0;
16441                 }
16442                 
16443                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16444                 break;
16445                 
16446             case 13: // enter
16447                 
16448                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16449                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16450                 }
16451                 
16452                 this.hide();
16453                 e.preventDefault();
16454                 break;
16455             case 9: // tab
16456                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16457                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16458                 }
16459                 this.hide();
16460                 break;
16461             case 16: // shift
16462             case 17: // ctrl
16463             case 18: // alt
16464                 break;
16465             default :
16466                 this.hide();
16467                 
16468         }
16469     },
16470     
16471     remove: function() 
16472     {
16473         this.picker().remove();
16474     }
16475    
16476 });
16477
16478 Roo.apply(Roo.bootstrap.MonthField,  {
16479     
16480     content : {
16481         tag: 'tbody',
16482         cn: [
16483         {
16484             tag: 'tr',
16485             cn: [
16486             {
16487                 tag: 'td',
16488                 colspan: '7'
16489             }
16490             ]
16491         }
16492         ]
16493     },
16494     
16495     dates:{
16496         en: {
16497             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16498             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16499         }
16500     }
16501 });
16502
16503 Roo.apply(Roo.bootstrap.MonthField,  {
16504   
16505     template : {
16506         tag: 'div',
16507         cls: 'datepicker dropdown-menu roo-dynamic',
16508         cn: [
16509             {
16510                 tag: 'div',
16511                 cls: 'datepicker-months',
16512                 cn: [
16513                 {
16514                     tag: 'table',
16515                     cls: 'table-condensed',
16516                     cn:[
16517                         Roo.bootstrap.DateField.content
16518                     ]
16519                 }
16520                 ]
16521             }
16522         ]
16523     }
16524 });
16525
16526  
16527
16528  
16529  /*
16530  * - LGPL
16531  *
16532  * CheckBox
16533  * 
16534  */
16535
16536 /**
16537  * @class Roo.bootstrap.CheckBox
16538  * @extends Roo.bootstrap.Input
16539  * Bootstrap CheckBox class
16540  * 
16541  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16542  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16543  * @cfg {String} boxLabel The text that appears beside the checkbox
16544  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16545  * @cfg {Boolean} checked initnal the element
16546  * @cfg {Boolean} inline inline the element (default false)
16547  * 
16548  * @constructor
16549  * Create a new CheckBox
16550  * @param {Object} config The config object
16551  */
16552
16553 Roo.bootstrap.CheckBox = function(config){
16554     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16555    
16556     this.addEvents({
16557         /**
16558         * @event check
16559         * Fires when the element is checked or unchecked.
16560         * @param {Roo.bootstrap.CheckBox} this This input
16561         * @param {Boolean} checked The new checked value
16562         */
16563        check : true
16564     });
16565 };
16566
16567 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16568     
16569     inputType: 'checkbox',
16570     inputValue: 1,
16571     valueOff: 0,
16572     boxLabel: false,
16573     checked: false,
16574     weight : false,
16575     inline: false,
16576     
16577     getAutoCreate : function()
16578     {
16579         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16580         
16581         var id = Roo.id();
16582         
16583         var cfg = {};
16584         
16585         cfg.cls = 'form-group ' + this.inputType; //input-group
16586         
16587         if(this.inline){
16588             cfg.cls += ' ' + this.inputType + '-inline';
16589         }
16590         
16591         var input =  {
16592             tag: 'input',
16593             id : id,
16594             type : this.inputType,
16595             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16596             cls : 'roo-' + this.inputType, //'form-box',
16597             placeholder : this.placeholder || ''
16598             
16599         };
16600         
16601         if (this.weight) { // Validity check?
16602             cfg.cls += " " + this.inputType + "-" + this.weight;
16603         }
16604         
16605         if (this.disabled) {
16606             input.disabled=true;
16607         }
16608         
16609         if(this.checked){
16610             input.checked = this.checked;
16611         }
16612         
16613         if (this.name) {
16614             input.name = this.name;
16615         }
16616         
16617         if (this.size) {
16618             input.cls += ' input-' + this.size;
16619         }
16620         
16621         var settings=this;
16622         
16623         ['xs','sm','md','lg'].map(function(size){
16624             if (settings[size]) {
16625                 cfg.cls += ' col-' + size + '-' + settings[size];
16626             }
16627         });
16628         
16629        
16630         
16631         var inputblock = input;
16632         
16633         
16634         
16635         
16636         if (this.before || this.after) {
16637             
16638             inputblock = {
16639                 cls : 'input-group',
16640                 cn :  [] 
16641             };
16642             
16643             if (this.before) {
16644                 inputblock.cn.push({
16645                     tag :'span',
16646                     cls : 'input-group-addon',
16647                     html : this.before
16648                 });
16649             }
16650             
16651             inputblock.cn.push(input);
16652             
16653             if (this.after) {
16654                 inputblock.cn.push({
16655                     tag :'span',
16656                     cls : 'input-group-addon',
16657                     html : this.after
16658                 });
16659             }
16660             
16661         }
16662         
16663         if (align ==='left' && this.fieldLabel.length) {
16664                 Roo.log("left and has label");
16665                 cfg.cn = [
16666                     
16667                     {
16668                         tag: 'label',
16669                         'for' :  id,
16670                         cls : 'control-label col-md-' + this.labelWidth,
16671                         html : this.fieldLabel
16672                         
16673                     },
16674                     {
16675                         cls : "col-md-" + (12 - this.labelWidth), 
16676                         cn: [
16677                             inputblock
16678                         ]
16679                     }
16680                     
16681                 ];
16682         } else if ( this.fieldLabel.length) {
16683                 Roo.log(" label");
16684                 cfg.cn = [
16685                    
16686                     {
16687                         tag: this.boxLabel ? 'span' : 'label',
16688                         'for': id,
16689                         cls: 'control-label box-input-label',
16690                         //cls : 'input-group-addon',
16691                         html : this.fieldLabel
16692                         
16693                     },
16694                     
16695                     inputblock
16696                     
16697                 ];
16698
16699         } else {
16700             
16701                 Roo.log(" no label && no align");
16702                 cfg.cn = [  inputblock ] ;
16703                 
16704                 
16705         }
16706         if(this.boxLabel){
16707              var boxLabelCfg = {
16708                 tag: 'label',
16709                 //'for': id, // box label is handled by onclick - so no for...
16710                 cls: 'box-label',
16711                 html: this.boxLabel
16712             }
16713             
16714             if(this.tooltip){
16715                 boxLabelCfg.tooltip = this.tooltip;
16716             }
16717              
16718             cfg.cn.push(boxLabelCfg);
16719         }
16720         
16721         
16722        
16723         return cfg;
16724         
16725     },
16726     
16727     /**
16728      * return the real input element.
16729      */
16730     inputEl: function ()
16731     {
16732         return this.el.select('input.roo-' + this.inputType,true).first();
16733     },
16734     
16735     labelEl: function()
16736     {
16737         return this.el.select('label.control-label',true).first();
16738     },
16739     /* depricated... */
16740     
16741     label: function()
16742     {
16743         return this.labelEl();
16744     },
16745     
16746     initEvents : function()
16747     {
16748 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16749         
16750         this.inputEl().on('click', this.onClick,  this);
16751         if (this.boxLabel) { 
16752             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
16753         }
16754         
16755     },
16756     
16757     onClick : function()
16758     {   
16759         this.setChecked(!this.checked);
16760     },
16761     
16762     setChecked : function(state,suppressEvent)
16763     {
16764         if(this.inputType == 'radio'){
16765             
16766             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16767                 e.dom.checked = false;
16768             });
16769             
16770             this.inputEl().dom.checked = true;
16771             
16772             if(suppressEvent !== true){
16773                 this.fireEvent('check', this, true);
16774             }
16775             
16776             this.inputEl().dom.value = this.inputValue;
16777             
16778             return;
16779         }
16780         
16781         this.checked = state;
16782         
16783         if(suppressEvent !== true){
16784             this.fireEvent('check', this, state);
16785         }
16786         
16787         this.inputEl().dom.checked = state;
16788         
16789         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16790         
16791     },
16792     
16793     getValue : function()
16794     {
16795         if(this.inputType == 'radio'){
16796             return this.getGroupValue();
16797         }
16798         
16799         return this.inputEl().getValue();
16800         
16801     },
16802     
16803     getGroupValue : function()
16804     {
16805         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16806             return '';
16807         }
16808         
16809         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16810     },
16811     
16812     setValue : function(v,suppressEvent)
16813     {
16814         if(this.inputType == 'radio'){
16815             this.setGroupValue(v, suppressEvent);
16816             return;
16817         }
16818         
16819         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16820     },
16821     
16822     setGroupValue : function(v, suppressEvent)
16823     {
16824         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16825             e.dom.checked = false;
16826             
16827             if(e.dom.value == v){
16828                 e.dom.checked = true;
16829             }
16830         });
16831         
16832         if(suppressEvent !== true){
16833             this.fireEvent('check', this, true);
16834         }
16835
16836         return;
16837     }
16838     
16839 });
16840
16841  
16842 /*
16843  * - LGPL
16844  *
16845  * Radio
16846  *
16847  *
16848  * not inline
16849  *<div class="radio">
16850   <label>
16851     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
16852     Option one is this and that&mdash;be sure to include why it's great
16853   </label>
16854 </div>
16855  *
16856  *
16857  *inline
16858  *<span>
16859  *<label class="radio-inline">fieldLabel</label>
16860  *<label class="radio-inline">
16861   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
16862 </label>
16863 <span>
16864  * 
16865  * 
16866  */
16867
16868 /**
16869  * @class Roo.bootstrap.Radio
16870  * @extends Roo.bootstrap.CheckBox
16871  * Bootstrap Radio class
16872
16873  * @constructor
16874  * Create a new Radio
16875  * @param {Object} config The config object
16876  */
16877
16878 Roo.bootstrap.Radio = function(config){
16879     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16880    
16881 };
16882
16883 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
16884     
16885     inputType: 'radio',
16886     inputValue: '',
16887     valueOff: '',
16888     
16889     getAutoCreate : function()
16890     {
16891         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16892         align = align || 'left'; // default...
16893         
16894         
16895         
16896         var id = Roo.id();
16897         
16898         var cfg = {
16899                 tag : this.inline ? 'span' : 'div',
16900                 cls : '',
16901                 cn : []
16902         };
16903         
16904         var inline = this.inline ? ' radio-inline' : '';
16905         
16906         var lbl = {
16907                 tag: 'label' ,
16908                 // does not need for, as we wrap the input with it..
16909                 'for' : id,
16910                 cls : 'control-label box-label' + inline,
16911                 cn : []
16912         };
16913         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
16914         
16915         var fieldLabel = {
16916             tag: 'label' ,
16917             //cls : 'control-label' + inline,
16918             html : this.fieldLabel,
16919             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
16920         };
16921         
16922  
16923         
16924         
16925         var input =  {
16926             tag: 'input',
16927             id : id,
16928             type : this.inputType,
16929             //value : (!this.checked) ? this.valueOff : this.inputValue,
16930             value : this.inputValue,
16931             cls : 'roo-radio',
16932             placeholder : this.placeholder || '' // ?? needed????
16933             
16934         };
16935         if (this.weight) { // Validity check?
16936             input.cls += " radio-" + this.weight;
16937         }
16938         if (this.disabled) {
16939             input.disabled=true;
16940         }
16941         
16942         if(this.checked){
16943             input.checked = this.checked;
16944         }
16945         
16946         if (this.name) {
16947             input.name = this.name;
16948         }
16949         
16950         if (this.size) {
16951             input.cls += ' input-' + this.size;
16952         }
16953         
16954         //?? can span's inline have a width??
16955         
16956         var settings=this;
16957         ['xs','sm','md','lg'].map(function(size){
16958             if (settings[size]) {
16959                 cfg.cls += ' col-' + size + '-' + settings[size];
16960             }
16961         });
16962         
16963         var inputblock = input;
16964         
16965         if (this.before || this.after) {
16966             
16967             inputblock = {
16968                 cls : 'input-group',
16969                 tag : 'span',
16970                 cn :  [] 
16971             };
16972             if (this.before) {
16973                 inputblock.cn.push({
16974                     tag :'span',
16975                     cls : 'input-group-addon',
16976                     html : this.before
16977                 });
16978             }
16979             inputblock.cn.push(input);
16980             if (this.after) {
16981                 inputblock.cn.push({
16982                     tag :'span',
16983                     cls : 'input-group-addon',
16984                     html : this.after
16985                 });
16986             }
16987             
16988         };
16989         
16990         
16991         if (this.fieldLabel && this.fieldLabel.length) {
16992             cfg.cn.push(fieldLabel);
16993         }
16994        
16995         // normal bootstrap puts the input inside the label.
16996         // however with our styled version - it has to go after the input.
16997        
16998         //lbl.cn.push(inputblock);
16999         
17000         var lblwrap =  {
17001             tag: 'span',
17002             cls: 'radio' + inline,
17003             cn: [
17004                 inputblock,
17005                 lbl
17006             ]
17007         };
17008         
17009         cfg.cn.push( lblwrap);
17010         
17011         if(this.boxLabel){
17012             lbl.cn.push({
17013                 tag: 'span',
17014                 html: this.boxLabel
17015             })
17016         }
17017          
17018         
17019         return cfg;
17020         
17021     },
17022     
17023     initEvents : function()
17024     {
17025 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17026         
17027         this.inputEl().on('click', this.onClick,  this);
17028         if (this.boxLabel) {
17029             Roo.log('find label')
17030             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17031         }
17032         
17033     },
17034     
17035     inputEl: function ()
17036     {
17037         return this.el.select('input.roo-radio',true).first();
17038     },
17039     onClick : function()
17040     {   
17041         Roo.log("click");
17042         this.setChecked(true);
17043     },
17044     
17045     setChecked : function(state,suppressEvent)
17046     {
17047         if(state){
17048             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17049                 v.dom.checked = false;
17050             });
17051         }
17052         Roo.log(this.inputEl().dom);
17053         this.checked = state;
17054         this.inputEl().dom.checked = state;
17055         
17056         if(suppressEvent !== true){
17057             this.fireEvent('check', this, state);
17058         }
17059         
17060         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17061         
17062     },
17063     
17064     getGroupValue : function()
17065     {
17066         var value = '';
17067         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17068             if(v.dom.checked == true){
17069                 value = v.dom.value;
17070             }
17071         });
17072         
17073         return value;
17074     },
17075     
17076     /**
17077      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17078      * @return {Mixed} value The field value
17079      */
17080     getValue : function(){
17081         return this.getGroupValue();
17082     }
17083     
17084 });
17085
17086  
17087 //<script type="text/javascript">
17088
17089 /*
17090  * Based  Ext JS Library 1.1.1
17091  * Copyright(c) 2006-2007, Ext JS, LLC.
17092  * LGPL
17093  *
17094  */
17095  
17096 /**
17097  * @class Roo.HtmlEditorCore
17098  * @extends Roo.Component
17099  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17100  *
17101  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17102  */
17103
17104 Roo.HtmlEditorCore = function(config){
17105     
17106     
17107     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17108     
17109     
17110     this.addEvents({
17111         /**
17112          * @event initialize
17113          * Fires when the editor is fully initialized (including the iframe)
17114          * @param {Roo.HtmlEditorCore} this
17115          */
17116         initialize: true,
17117         /**
17118          * @event activate
17119          * Fires when the editor is first receives the focus. Any insertion must wait
17120          * until after this event.
17121          * @param {Roo.HtmlEditorCore} this
17122          */
17123         activate: true,
17124          /**
17125          * @event beforesync
17126          * Fires before the textarea is updated with content from the editor iframe. Return false
17127          * to cancel the sync.
17128          * @param {Roo.HtmlEditorCore} this
17129          * @param {String} html
17130          */
17131         beforesync: true,
17132          /**
17133          * @event beforepush
17134          * Fires before the iframe editor is updated with content from the textarea. Return false
17135          * to cancel the push.
17136          * @param {Roo.HtmlEditorCore} this
17137          * @param {String} html
17138          */
17139         beforepush: true,
17140          /**
17141          * @event sync
17142          * Fires when the textarea is updated with content from the editor iframe.
17143          * @param {Roo.HtmlEditorCore} this
17144          * @param {String} html
17145          */
17146         sync: true,
17147          /**
17148          * @event push
17149          * Fires when the iframe editor is updated with content from the textarea.
17150          * @param {Roo.HtmlEditorCore} this
17151          * @param {String} html
17152          */
17153         push: true,
17154         
17155         /**
17156          * @event editorevent
17157          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17158          * @param {Roo.HtmlEditorCore} this
17159          */
17160         editorevent: true
17161         
17162     });
17163     
17164     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17165     
17166     // defaults : white / black...
17167     this.applyBlacklists();
17168     
17169     
17170     
17171 };
17172
17173
17174 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17175
17176
17177      /**
17178      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17179      */
17180     
17181     owner : false,
17182     
17183      /**
17184      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17185      *                        Roo.resizable.
17186      */
17187     resizable : false,
17188      /**
17189      * @cfg {Number} height (in pixels)
17190      */   
17191     height: 300,
17192    /**
17193      * @cfg {Number} width (in pixels)
17194      */   
17195     width: 500,
17196     
17197     /**
17198      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17199      * 
17200      */
17201     stylesheets: false,
17202     
17203     // id of frame..
17204     frameId: false,
17205     
17206     // private properties
17207     validationEvent : false,
17208     deferHeight: true,
17209     initialized : false,
17210     activated : false,
17211     sourceEditMode : false,
17212     onFocus : Roo.emptyFn,
17213     iframePad:3,
17214     hideMode:'offsets',
17215     
17216     clearUp: true,
17217     
17218     // blacklist + whitelisted elements..
17219     black: false,
17220     white: false,
17221      
17222     
17223
17224     /**
17225      * Protected method that will not generally be called directly. It
17226      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17227      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17228      */
17229     getDocMarkup : function(){
17230         // body styles..
17231         var st = '';
17232         
17233         // inherit styels from page...?? 
17234         if (this.stylesheets === false) {
17235             
17236             Roo.get(document.head).select('style').each(function(node) {
17237                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17238             });
17239             
17240             Roo.get(document.head).select('link').each(function(node) { 
17241                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17242             });
17243             
17244         } else if (!this.stylesheets.length) {
17245                 // simple..
17246                 st = '<style type="text/css">' +
17247                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17248                    '</style>';
17249         } else { 
17250             
17251         }
17252         
17253         st +=  '<style type="text/css">' +
17254             'IMG { cursor: pointer } ' +
17255         '</style>';
17256
17257         
17258         return '<html><head>' + st  +
17259             //<style type="text/css">' +
17260             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17261             //'</style>' +
17262             ' </head><body class="roo-htmleditor-body"></body></html>';
17263     },
17264
17265     // private
17266     onRender : function(ct, position)
17267     {
17268         var _t = this;
17269         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17270         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17271         
17272         
17273         this.el.dom.style.border = '0 none';
17274         this.el.dom.setAttribute('tabIndex', -1);
17275         this.el.addClass('x-hidden hide');
17276         
17277         
17278         
17279         if(Roo.isIE){ // fix IE 1px bogus margin
17280             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17281         }
17282        
17283         
17284         this.frameId = Roo.id();
17285         
17286          
17287         
17288         var iframe = this.owner.wrap.createChild({
17289             tag: 'iframe',
17290             cls: 'form-control', // bootstrap..
17291             id: this.frameId,
17292             name: this.frameId,
17293             frameBorder : 'no',
17294             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17295         }, this.el
17296         );
17297         
17298         
17299         this.iframe = iframe.dom;
17300
17301          this.assignDocWin();
17302         
17303         this.doc.designMode = 'on';
17304        
17305         this.doc.open();
17306         this.doc.write(this.getDocMarkup());
17307         this.doc.close();
17308
17309         
17310         var task = { // must defer to wait for browser to be ready
17311             run : function(){
17312                 //console.log("run task?" + this.doc.readyState);
17313                 this.assignDocWin();
17314                 if(this.doc.body || this.doc.readyState == 'complete'){
17315                     try {
17316                         this.doc.designMode="on";
17317                     } catch (e) {
17318                         return;
17319                     }
17320                     Roo.TaskMgr.stop(task);
17321                     this.initEditor.defer(10, this);
17322                 }
17323             },
17324             interval : 10,
17325             duration: 10000,
17326             scope: this
17327         };
17328         Roo.TaskMgr.start(task);
17329
17330     },
17331
17332     // private
17333     onResize : function(w, h)
17334     {
17335          Roo.log('resize: ' +w + ',' + h );
17336         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17337         if(!this.iframe){
17338             return;
17339         }
17340         if(typeof w == 'number'){
17341             
17342             this.iframe.style.width = w + 'px';
17343         }
17344         if(typeof h == 'number'){
17345             
17346             this.iframe.style.height = h + 'px';
17347             if(this.doc){
17348                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17349             }
17350         }
17351         
17352     },
17353
17354     /**
17355      * Toggles the editor between standard and source edit mode.
17356      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17357      */
17358     toggleSourceEdit : function(sourceEditMode){
17359         
17360         this.sourceEditMode = sourceEditMode === true;
17361         
17362         if(this.sourceEditMode){
17363  
17364             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17365             
17366         }else{
17367             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17368             //this.iframe.className = '';
17369             this.deferFocus();
17370         }
17371         //this.setSize(this.owner.wrap.getSize());
17372         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17373     },
17374
17375     
17376   
17377
17378     /**
17379      * Protected method that will not generally be called directly. If you need/want
17380      * custom HTML cleanup, this is the method you should override.
17381      * @param {String} html The HTML to be cleaned
17382      * return {String} The cleaned HTML
17383      */
17384     cleanHtml : function(html){
17385         html = String(html);
17386         if(html.length > 5){
17387             if(Roo.isSafari){ // strip safari nonsense
17388                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17389             }
17390         }
17391         if(html == '&nbsp;'){
17392             html = '';
17393         }
17394         return html;
17395     },
17396
17397     /**
17398      * HTML Editor -> Textarea
17399      * Protected method that will not generally be called directly. Syncs the contents
17400      * of the editor iframe with the textarea.
17401      */
17402     syncValue : function(){
17403         if(this.initialized){
17404             var bd = (this.doc.body || this.doc.documentElement);
17405             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17406             var html = bd.innerHTML;
17407             if(Roo.isSafari){
17408                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17409                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17410                 if(m && m[1]){
17411                     html = '<div style="'+m[0]+'">' + html + '</div>';
17412                 }
17413             }
17414             html = this.cleanHtml(html);
17415             // fix up the special chars.. normaly like back quotes in word...
17416             // however we do not want to do this with chinese..
17417             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17418                 var cc = b.charCodeAt();
17419                 if (
17420                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17421                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17422                     (cc >= 0xf900 && cc < 0xfb00 )
17423                 ) {
17424                         return b;
17425                 }
17426                 return "&#"+cc+";" 
17427             });
17428             if(this.owner.fireEvent('beforesync', this, html) !== false){
17429                 this.el.dom.value = html;
17430                 this.owner.fireEvent('sync', this, html);
17431             }
17432         }
17433     },
17434
17435     /**
17436      * Protected method that will not generally be called directly. Pushes the value of the textarea
17437      * into the iframe editor.
17438      */
17439     pushValue : function(){
17440         if(this.initialized){
17441             var v = this.el.dom.value.trim();
17442             
17443 //            if(v.length < 1){
17444 //                v = '&#160;';
17445 //            }
17446             
17447             if(this.owner.fireEvent('beforepush', this, v) !== false){
17448                 var d = (this.doc.body || this.doc.documentElement);
17449                 d.innerHTML = v;
17450                 this.cleanUpPaste();
17451                 this.el.dom.value = d.innerHTML;
17452                 this.owner.fireEvent('push', this, v);
17453             }
17454         }
17455     },
17456
17457     // private
17458     deferFocus : function(){
17459         this.focus.defer(10, this);
17460     },
17461
17462     // doc'ed in Field
17463     focus : function(){
17464         if(this.win && !this.sourceEditMode){
17465             this.win.focus();
17466         }else{
17467             this.el.focus();
17468         }
17469     },
17470     
17471     assignDocWin: function()
17472     {
17473         var iframe = this.iframe;
17474         
17475          if(Roo.isIE){
17476             this.doc = iframe.contentWindow.document;
17477             this.win = iframe.contentWindow;
17478         } else {
17479 //            if (!Roo.get(this.frameId)) {
17480 //                return;
17481 //            }
17482 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17483 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17484             
17485             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17486                 return;
17487             }
17488             
17489             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17490             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17491         }
17492     },
17493     
17494     // private
17495     initEditor : function(){
17496         //console.log("INIT EDITOR");
17497         this.assignDocWin();
17498         
17499         
17500         
17501         this.doc.designMode="on";
17502         this.doc.open();
17503         this.doc.write(this.getDocMarkup());
17504         this.doc.close();
17505         
17506         var dbody = (this.doc.body || this.doc.documentElement);
17507         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17508         // this copies styles from the containing element into thsi one..
17509         // not sure why we need all of this..
17510         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17511         
17512         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17513         //ss['background-attachment'] = 'fixed'; // w3c
17514         dbody.bgProperties = 'fixed'; // ie
17515         //Roo.DomHelper.applyStyles(dbody, ss);
17516         Roo.EventManager.on(this.doc, {
17517             //'mousedown': this.onEditorEvent,
17518             'mouseup': this.onEditorEvent,
17519             'dblclick': this.onEditorEvent,
17520             'click': this.onEditorEvent,
17521             'keyup': this.onEditorEvent,
17522             buffer:100,
17523             scope: this
17524         });
17525         if(Roo.isGecko){
17526             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17527         }
17528         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17529             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17530         }
17531         this.initialized = true;
17532
17533         this.owner.fireEvent('initialize', this);
17534         this.pushValue();
17535     },
17536
17537     // private
17538     onDestroy : function(){
17539         
17540         
17541         
17542         if(this.rendered){
17543             
17544             //for (var i =0; i < this.toolbars.length;i++) {
17545             //    // fixme - ask toolbars for heights?
17546             //    this.toolbars[i].onDestroy();
17547            // }
17548             
17549             //this.wrap.dom.innerHTML = '';
17550             //this.wrap.remove();
17551         }
17552     },
17553
17554     // private
17555     onFirstFocus : function(){
17556         
17557         this.assignDocWin();
17558         
17559         
17560         this.activated = true;
17561          
17562     
17563         if(Roo.isGecko){ // prevent silly gecko errors
17564             this.win.focus();
17565             var s = this.win.getSelection();
17566             if(!s.focusNode || s.focusNode.nodeType != 3){
17567                 var r = s.getRangeAt(0);
17568                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17569                 r.collapse(true);
17570                 this.deferFocus();
17571             }
17572             try{
17573                 this.execCmd('useCSS', true);
17574                 this.execCmd('styleWithCSS', false);
17575             }catch(e){}
17576         }
17577         this.owner.fireEvent('activate', this);
17578     },
17579
17580     // private
17581     adjustFont: function(btn){
17582         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17583         //if(Roo.isSafari){ // safari
17584         //    adjust *= 2;
17585        // }
17586         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17587         if(Roo.isSafari){ // safari
17588             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17589             v =  (v < 10) ? 10 : v;
17590             v =  (v > 48) ? 48 : v;
17591             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17592             
17593         }
17594         
17595         
17596         v = Math.max(1, v+adjust);
17597         
17598         this.execCmd('FontSize', v  );
17599     },
17600
17601     onEditorEvent : function(e){
17602         this.owner.fireEvent('editorevent', this, e);
17603       //  this.updateToolbar();
17604         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17605     },
17606
17607     insertTag : function(tg)
17608     {
17609         // could be a bit smarter... -> wrap the current selected tRoo..
17610         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17611             
17612             range = this.createRange(this.getSelection());
17613             var wrappingNode = this.doc.createElement(tg.toLowerCase());
17614             wrappingNode.appendChild(range.extractContents());
17615             range.insertNode(wrappingNode);
17616
17617             return;
17618             
17619             
17620             
17621         }
17622         this.execCmd("formatblock",   tg);
17623         
17624     },
17625     
17626     insertText : function(txt)
17627     {
17628         
17629         
17630         var range = this.createRange();
17631         range.deleteContents();
17632                //alert(Sender.getAttribute('label'));
17633                
17634         range.insertNode(this.doc.createTextNode(txt));
17635     } ,
17636     
17637      
17638
17639     /**
17640      * Executes a Midas editor command on the editor document and performs necessary focus and
17641      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17642      * @param {String} cmd The Midas command
17643      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17644      */
17645     relayCmd : function(cmd, value){
17646         this.win.focus();
17647         this.execCmd(cmd, value);
17648         this.owner.fireEvent('editorevent', this);
17649         //this.updateToolbar();
17650         this.owner.deferFocus();
17651     },
17652
17653     /**
17654      * Executes a Midas editor command directly on the editor document.
17655      * For visual commands, you should use {@link #relayCmd} instead.
17656      * <b>This should only be called after the editor is initialized.</b>
17657      * @param {String} cmd The Midas command
17658      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17659      */
17660     execCmd : function(cmd, value){
17661         this.doc.execCommand(cmd, false, value === undefined ? null : value);
17662         this.syncValue();
17663     },
17664  
17665  
17666    
17667     /**
17668      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17669      * to insert tRoo.
17670      * @param {String} text | dom node.. 
17671      */
17672     insertAtCursor : function(text)
17673     {
17674         
17675         
17676         
17677         if(!this.activated){
17678             return;
17679         }
17680         /*
17681         if(Roo.isIE){
17682             this.win.focus();
17683             var r = this.doc.selection.createRange();
17684             if(r){
17685                 r.collapse(true);
17686                 r.pasteHTML(text);
17687                 this.syncValue();
17688                 this.deferFocus();
17689             
17690             }
17691             return;
17692         }
17693         */
17694         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17695             this.win.focus();
17696             
17697             
17698             // from jquery ui (MIT licenced)
17699             var range, node;
17700             var win = this.win;
17701             
17702             if (win.getSelection && win.getSelection().getRangeAt) {
17703                 range = win.getSelection().getRangeAt(0);
17704                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17705                 range.insertNode(node);
17706             } else if (win.document.selection && win.document.selection.createRange) {
17707                 // no firefox support
17708                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17709                 win.document.selection.createRange().pasteHTML(txt);
17710             } else {
17711                 // no firefox support
17712                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17713                 this.execCmd('InsertHTML', txt);
17714             } 
17715             
17716             this.syncValue();
17717             
17718             this.deferFocus();
17719         }
17720     },
17721  // private
17722     mozKeyPress : function(e){
17723         if(e.ctrlKey){
17724             var c = e.getCharCode(), cmd;
17725           
17726             if(c > 0){
17727                 c = String.fromCharCode(c).toLowerCase();
17728                 switch(c){
17729                     case 'b':
17730                         cmd = 'bold';
17731                         break;
17732                     case 'i':
17733                         cmd = 'italic';
17734                         break;
17735                     
17736                     case 'u':
17737                         cmd = 'underline';
17738                         break;
17739                     
17740                     case 'v':
17741                         this.cleanUpPaste.defer(100, this);
17742                         return;
17743                         
17744                 }
17745                 if(cmd){
17746                     this.win.focus();
17747                     this.execCmd(cmd);
17748                     this.deferFocus();
17749                     e.preventDefault();
17750                 }
17751                 
17752             }
17753         }
17754     },
17755
17756     // private
17757     fixKeys : function(){ // load time branching for fastest keydown performance
17758         if(Roo.isIE){
17759             return function(e){
17760                 var k = e.getKey(), r;
17761                 if(k == e.TAB){
17762                     e.stopEvent();
17763                     r = this.doc.selection.createRange();
17764                     if(r){
17765                         r.collapse(true);
17766                         r.pasteHTML('&#160;&#160;&#160;&#160;');
17767                         this.deferFocus();
17768                     }
17769                     return;
17770                 }
17771                 
17772                 if(k == e.ENTER){
17773                     r = this.doc.selection.createRange();
17774                     if(r){
17775                         var target = r.parentElement();
17776                         if(!target || target.tagName.toLowerCase() != 'li'){
17777                             e.stopEvent();
17778                             r.pasteHTML('<br />');
17779                             r.collapse(false);
17780                             r.select();
17781                         }
17782                     }
17783                 }
17784                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17785                     this.cleanUpPaste.defer(100, this);
17786                     return;
17787                 }
17788                 
17789                 
17790             };
17791         }else if(Roo.isOpera){
17792             return function(e){
17793                 var k = e.getKey();
17794                 if(k == e.TAB){
17795                     e.stopEvent();
17796                     this.win.focus();
17797                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
17798                     this.deferFocus();
17799                 }
17800                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17801                     this.cleanUpPaste.defer(100, this);
17802                     return;
17803                 }
17804                 
17805             };
17806         }else if(Roo.isSafari){
17807             return function(e){
17808                 var k = e.getKey();
17809                 
17810                 if(k == e.TAB){
17811                     e.stopEvent();
17812                     this.execCmd('InsertText','\t');
17813                     this.deferFocus();
17814                     return;
17815                 }
17816                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17817                     this.cleanUpPaste.defer(100, this);
17818                     return;
17819                 }
17820                 
17821              };
17822         }
17823     }(),
17824     
17825     getAllAncestors: function()
17826     {
17827         var p = this.getSelectedNode();
17828         var a = [];
17829         if (!p) {
17830             a.push(p); // push blank onto stack..
17831             p = this.getParentElement();
17832         }
17833         
17834         
17835         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17836             a.push(p);
17837             p = p.parentNode;
17838         }
17839         a.push(this.doc.body);
17840         return a;
17841     },
17842     lastSel : false,
17843     lastSelNode : false,
17844     
17845     
17846     getSelection : function() 
17847     {
17848         this.assignDocWin();
17849         return Roo.isIE ? this.doc.selection : this.win.getSelection();
17850     },
17851     
17852     getSelectedNode: function() 
17853     {
17854         // this may only work on Gecko!!!
17855         
17856         // should we cache this!!!!
17857         
17858         
17859         
17860          
17861         var range = this.createRange(this.getSelection()).cloneRange();
17862         
17863         if (Roo.isIE) {
17864             var parent = range.parentElement();
17865             while (true) {
17866                 var testRange = range.duplicate();
17867                 testRange.moveToElementText(parent);
17868                 if (testRange.inRange(range)) {
17869                     break;
17870                 }
17871                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17872                     break;
17873                 }
17874                 parent = parent.parentElement;
17875             }
17876             return parent;
17877         }
17878         
17879         // is ancestor a text element.
17880         var ac =  range.commonAncestorContainer;
17881         if (ac.nodeType == 3) {
17882             ac = ac.parentNode;
17883         }
17884         
17885         var ar = ac.childNodes;
17886          
17887         var nodes = [];
17888         var other_nodes = [];
17889         var has_other_nodes = false;
17890         for (var i=0;i<ar.length;i++) {
17891             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
17892                 continue;
17893             }
17894             // fullly contained node.
17895             
17896             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17897                 nodes.push(ar[i]);
17898                 continue;
17899             }
17900             
17901             // probably selected..
17902             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17903                 other_nodes.push(ar[i]);
17904                 continue;
17905             }
17906             // outer..
17907             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
17908                 continue;
17909             }
17910             
17911             
17912             has_other_nodes = true;
17913         }
17914         if (!nodes.length && other_nodes.length) {
17915             nodes= other_nodes;
17916         }
17917         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17918             return false;
17919         }
17920         
17921         return nodes[0];
17922     },
17923     createRange: function(sel)
17924     {
17925         // this has strange effects when using with 
17926         // top toolbar - not sure if it's a great idea.
17927         //this.editor.contentWindow.focus();
17928         if (typeof sel != "undefined") {
17929             try {
17930                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17931             } catch(e) {
17932                 return this.doc.createRange();
17933             }
17934         } else {
17935             return this.doc.createRange();
17936         }
17937     },
17938     getParentElement: function()
17939     {
17940         
17941         this.assignDocWin();
17942         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17943         
17944         var range = this.createRange(sel);
17945          
17946         try {
17947             var p = range.commonAncestorContainer;
17948             while (p.nodeType == 3) { // text node
17949                 p = p.parentNode;
17950             }
17951             return p;
17952         } catch (e) {
17953             return null;
17954         }
17955     
17956     },
17957     /***
17958      *
17959      * Range intersection.. the hard stuff...
17960      *  '-1' = before
17961      *  '0' = hits..
17962      *  '1' = after.
17963      *         [ -- selected range --- ]
17964      *   [fail]                        [fail]
17965      *
17966      *    basically..
17967      *      if end is before start or  hits it. fail.
17968      *      if start is after end or hits it fail.
17969      *
17970      *   if either hits (but other is outside. - then it's not 
17971      *   
17972      *    
17973      **/
17974     
17975     
17976     // @see http://www.thismuchiknow.co.uk/?p=64.
17977     rangeIntersectsNode : function(range, node)
17978     {
17979         var nodeRange = node.ownerDocument.createRange();
17980         try {
17981             nodeRange.selectNode(node);
17982         } catch (e) {
17983             nodeRange.selectNodeContents(node);
17984         }
17985     
17986         var rangeStartRange = range.cloneRange();
17987         rangeStartRange.collapse(true);
17988     
17989         var rangeEndRange = range.cloneRange();
17990         rangeEndRange.collapse(false);
17991     
17992         var nodeStartRange = nodeRange.cloneRange();
17993         nodeStartRange.collapse(true);
17994     
17995         var nodeEndRange = nodeRange.cloneRange();
17996         nodeEndRange.collapse(false);
17997     
17998         return rangeStartRange.compareBoundaryPoints(
17999                  Range.START_TO_START, nodeEndRange) == -1 &&
18000                rangeEndRange.compareBoundaryPoints(
18001                  Range.START_TO_START, nodeStartRange) == 1;
18002         
18003          
18004     },
18005     rangeCompareNode : function(range, node)
18006     {
18007         var nodeRange = node.ownerDocument.createRange();
18008         try {
18009             nodeRange.selectNode(node);
18010         } catch (e) {
18011             nodeRange.selectNodeContents(node);
18012         }
18013         
18014         
18015         range.collapse(true);
18016     
18017         nodeRange.collapse(true);
18018      
18019         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18020         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18021          
18022         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18023         
18024         var nodeIsBefore   =  ss == 1;
18025         var nodeIsAfter    = ee == -1;
18026         
18027         if (nodeIsBefore && nodeIsAfter)
18028             return 0; // outer
18029         if (!nodeIsBefore && nodeIsAfter)
18030             return 1; //right trailed.
18031         
18032         if (nodeIsBefore && !nodeIsAfter)
18033             return 2;  // left trailed.
18034         // fully contined.
18035         return 3;
18036     },
18037
18038     // private? - in a new class?
18039     cleanUpPaste :  function()
18040     {
18041         // cleans up the whole document..
18042         Roo.log('cleanuppaste');
18043         
18044         this.cleanUpChildren(this.doc.body);
18045         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18046         if (clean != this.doc.body.innerHTML) {
18047             this.doc.body.innerHTML = clean;
18048         }
18049         
18050     },
18051     
18052     cleanWordChars : function(input) {// change the chars to hex code
18053         var he = Roo.HtmlEditorCore;
18054         
18055         var output = input;
18056         Roo.each(he.swapCodes, function(sw) { 
18057             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18058             
18059             output = output.replace(swapper, sw[1]);
18060         });
18061         
18062         return output;
18063     },
18064     
18065     
18066     cleanUpChildren : function (n)
18067     {
18068         if (!n.childNodes.length) {
18069             return;
18070         }
18071         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18072            this.cleanUpChild(n.childNodes[i]);
18073         }
18074     },
18075     
18076     
18077         
18078     
18079     cleanUpChild : function (node)
18080     {
18081         var ed = this;
18082         //console.log(node);
18083         if (node.nodeName == "#text") {
18084             // clean up silly Windows -- stuff?
18085             return; 
18086         }
18087         if (node.nodeName == "#comment") {
18088             node.parentNode.removeChild(node);
18089             // clean up silly Windows -- stuff?
18090             return; 
18091         }
18092         var lcname = node.tagName.toLowerCase();
18093         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18094         // whitelist of tags..
18095         
18096         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18097             // remove node.
18098             node.parentNode.removeChild(node);
18099             return;
18100             
18101         }
18102         
18103         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18104         
18105         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18106         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18107         
18108         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18109         //    remove_keep_children = true;
18110         //}
18111         
18112         if (remove_keep_children) {
18113             this.cleanUpChildren(node);
18114             // inserts everything just before this node...
18115             while (node.childNodes.length) {
18116                 var cn = node.childNodes[0];
18117                 node.removeChild(cn);
18118                 node.parentNode.insertBefore(cn, node);
18119             }
18120             node.parentNode.removeChild(node);
18121             return;
18122         }
18123         
18124         if (!node.attributes || !node.attributes.length) {
18125             this.cleanUpChildren(node);
18126             return;
18127         }
18128         
18129         function cleanAttr(n,v)
18130         {
18131             
18132             if (v.match(/^\./) || v.match(/^\//)) {
18133                 return;
18134             }
18135             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18136                 return;
18137             }
18138             if (v.match(/^#/)) {
18139                 return;
18140             }
18141 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18142             node.removeAttribute(n);
18143             
18144         }
18145         
18146         var cwhite = this.cwhite;
18147         var cblack = this.cblack;
18148             
18149         function cleanStyle(n,v)
18150         {
18151             if (v.match(/expression/)) { //XSS?? should we even bother..
18152                 node.removeAttribute(n);
18153                 return;
18154             }
18155             
18156             var parts = v.split(/;/);
18157             var clean = [];
18158             
18159             Roo.each(parts, function(p) {
18160                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18161                 if (!p.length) {
18162                     return true;
18163                 }
18164                 var l = p.split(':').shift().replace(/\s+/g,'');
18165                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18166                 
18167                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18168 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18169                     //node.removeAttribute(n);
18170                     return true;
18171                 }
18172                 //Roo.log()
18173                 // only allow 'c whitelisted system attributes'
18174                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18175 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18176                     //node.removeAttribute(n);
18177                     return true;
18178                 }
18179                 
18180                 
18181                  
18182                 
18183                 clean.push(p);
18184                 return true;
18185             });
18186             if (clean.length) { 
18187                 node.setAttribute(n, clean.join(';'));
18188             } else {
18189                 node.removeAttribute(n);
18190             }
18191             
18192         }
18193         
18194         
18195         for (var i = node.attributes.length-1; i > -1 ; i--) {
18196             var a = node.attributes[i];
18197             //console.log(a);
18198             
18199             if (a.name.toLowerCase().substr(0,2)=='on')  {
18200                 node.removeAttribute(a.name);
18201                 continue;
18202             }
18203             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18204                 node.removeAttribute(a.name);
18205                 continue;
18206             }
18207             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18208                 cleanAttr(a.name,a.value); // fixme..
18209                 continue;
18210             }
18211             if (a.name == 'style') {
18212                 cleanStyle(a.name,a.value);
18213                 continue;
18214             }
18215             /// clean up MS crap..
18216             // tecnically this should be a list of valid class'es..
18217             
18218             
18219             if (a.name == 'class') {
18220                 if (a.value.match(/^Mso/)) {
18221                     node.className = '';
18222                 }
18223                 
18224                 if (a.value.match(/body/)) {
18225                     node.className = '';
18226                 }
18227                 continue;
18228             }
18229             
18230             // style cleanup!?
18231             // class cleanup?
18232             
18233         }
18234         
18235         
18236         this.cleanUpChildren(node);
18237         
18238         
18239     },
18240     /**
18241      * Clean up MS wordisms...
18242      */
18243     cleanWord : function(node)
18244     {
18245         var _t = this;
18246         var cleanWordChildren = function()
18247         {
18248             if (!node.childNodes.length) {
18249                 return;
18250             }
18251             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18252                _t.cleanWord(node.childNodes[i]);
18253             }
18254         }
18255         
18256         
18257         if (!node) {
18258             this.cleanWord(this.doc.body);
18259             return;
18260         }
18261         if (node.nodeName == "#text") {
18262             // clean up silly Windows -- stuff?
18263             return; 
18264         }
18265         if (node.nodeName == "#comment") {
18266             node.parentNode.removeChild(node);
18267             // clean up silly Windows -- stuff?
18268             return; 
18269         }
18270         
18271         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18272             node.parentNode.removeChild(node);
18273             return;
18274         }
18275         
18276         // remove - but keep children..
18277         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18278             while (node.childNodes.length) {
18279                 var cn = node.childNodes[0];
18280                 node.removeChild(cn);
18281                 node.parentNode.insertBefore(cn, node);
18282             }
18283             node.parentNode.removeChild(node);
18284             cleanWordChildren();
18285             return;
18286         }
18287         // clean styles
18288         if (node.className.length) {
18289             
18290             var cn = node.className.split(/\W+/);
18291             var cna = [];
18292             Roo.each(cn, function(cls) {
18293                 if (cls.match(/Mso[a-zA-Z]+/)) {
18294                     return;
18295                 }
18296                 cna.push(cls);
18297             });
18298             node.className = cna.length ? cna.join(' ') : '';
18299             if (!cna.length) {
18300                 node.removeAttribute("class");
18301             }
18302         }
18303         
18304         if (node.hasAttribute("lang")) {
18305             node.removeAttribute("lang");
18306         }
18307         
18308         if (node.hasAttribute("style")) {
18309             
18310             var styles = node.getAttribute("style").split(";");
18311             var nstyle = [];
18312             Roo.each(styles, function(s) {
18313                 if (!s.match(/:/)) {
18314                     return;
18315                 }
18316                 var kv = s.split(":");
18317                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18318                     return;
18319                 }
18320                 // what ever is left... we allow.
18321                 nstyle.push(s);
18322             });
18323             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18324             if (!nstyle.length) {
18325                 node.removeAttribute('style');
18326             }
18327         }
18328         
18329         cleanWordChildren();
18330         
18331         
18332     },
18333     domToHTML : function(currentElement, depth, nopadtext) {
18334         
18335         depth = depth || 0;
18336         nopadtext = nopadtext || false;
18337     
18338         if (!currentElement) {
18339             return this.domToHTML(this.doc.body);
18340         }
18341         
18342         //Roo.log(currentElement);
18343         var j;
18344         var allText = false;
18345         var nodeName = currentElement.nodeName;
18346         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18347         
18348         if  (nodeName == '#text') {
18349             
18350             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18351         }
18352         
18353         
18354         var ret = '';
18355         if (nodeName != 'BODY') {
18356              
18357             var i = 0;
18358             // Prints the node tagName, such as <A>, <IMG>, etc
18359             if (tagName) {
18360                 var attr = [];
18361                 for(i = 0; i < currentElement.attributes.length;i++) {
18362                     // quoting?
18363                     var aname = currentElement.attributes.item(i).name;
18364                     if (!currentElement.attributes.item(i).value.length) {
18365                         continue;
18366                     }
18367                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18368                 }
18369                 
18370                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18371             } 
18372             else {
18373                 
18374                 // eack
18375             }
18376         } else {
18377             tagName = false;
18378         }
18379         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18380             return ret;
18381         }
18382         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18383             nopadtext = true;
18384         }
18385         
18386         
18387         // Traverse the tree
18388         i = 0;
18389         var currentElementChild = currentElement.childNodes.item(i);
18390         var allText = true;
18391         var innerHTML  = '';
18392         lastnode = '';
18393         while (currentElementChild) {
18394             // Formatting code (indent the tree so it looks nice on the screen)
18395             var nopad = nopadtext;
18396             if (lastnode == 'SPAN') {
18397                 nopad  = true;
18398             }
18399             // text
18400             if  (currentElementChild.nodeName == '#text') {
18401                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18402                 toadd = nopadtext ? toadd : toadd.trim();
18403                 if (!nopad && toadd.length > 80) {
18404                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18405                 }
18406                 innerHTML  += toadd;
18407                 
18408                 i++;
18409                 currentElementChild = currentElement.childNodes.item(i);
18410                 lastNode = '';
18411                 continue;
18412             }
18413             allText = false;
18414             
18415             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18416                 
18417             // Recursively traverse the tree structure of the child node
18418             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18419             lastnode = currentElementChild.nodeName;
18420             i++;
18421             currentElementChild=currentElement.childNodes.item(i);
18422         }
18423         
18424         ret += innerHTML;
18425         
18426         if (!allText) {
18427                 // The remaining code is mostly for formatting the tree
18428             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18429         }
18430         
18431         
18432         if (tagName) {
18433             ret+= "</"+tagName+">";
18434         }
18435         return ret;
18436         
18437     },
18438         
18439     applyBlacklists : function()
18440     {
18441         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18442         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18443         
18444         this.white = [];
18445         this.black = [];
18446         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18447             if (b.indexOf(tag) > -1) {
18448                 return;
18449             }
18450             this.white.push(tag);
18451             
18452         }, this);
18453         
18454         Roo.each(w, function(tag) {
18455             if (b.indexOf(tag) > -1) {
18456                 return;
18457             }
18458             if (this.white.indexOf(tag) > -1) {
18459                 return;
18460             }
18461             this.white.push(tag);
18462             
18463         }, this);
18464         
18465         
18466         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18467             if (w.indexOf(tag) > -1) {
18468                 return;
18469             }
18470             this.black.push(tag);
18471             
18472         }, this);
18473         
18474         Roo.each(b, function(tag) {
18475             if (w.indexOf(tag) > -1) {
18476                 return;
18477             }
18478             if (this.black.indexOf(tag) > -1) {
18479                 return;
18480             }
18481             this.black.push(tag);
18482             
18483         }, this);
18484         
18485         
18486         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18487         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18488         
18489         this.cwhite = [];
18490         this.cblack = [];
18491         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18492             if (b.indexOf(tag) > -1) {
18493                 return;
18494             }
18495             this.cwhite.push(tag);
18496             
18497         }, this);
18498         
18499         Roo.each(w, function(tag) {
18500             if (b.indexOf(tag) > -1) {
18501                 return;
18502             }
18503             if (this.cwhite.indexOf(tag) > -1) {
18504                 return;
18505             }
18506             this.cwhite.push(tag);
18507             
18508         }, this);
18509         
18510         
18511         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18512             if (w.indexOf(tag) > -1) {
18513                 return;
18514             }
18515             this.cblack.push(tag);
18516             
18517         }, this);
18518         
18519         Roo.each(b, function(tag) {
18520             if (w.indexOf(tag) > -1) {
18521                 return;
18522             }
18523             if (this.cblack.indexOf(tag) > -1) {
18524                 return;
18525             }
18526             this.cblack.push(tag);
18527             
18528         }, this);
18529     },
18530     
18531     setStylesheets : function(stylesheets)
18532     {
18533         if(typeof(stylesheets) == 'string'){
18534             Roo.get(this.iframe.contentDocument.head).createChild({
18535                 tag : 'link',
18536                 rel : 'stylesheet',
18537                 type : 'text/css',
18538                 href : stylesheets
18539             });
18540             
18541             return;
18542         }
18543         var _this = this;
18544      
18545         Roo.each(stylesheets, function(s) {
18546             if(!s.length){
18547                 return;
18548             }
18549             
18550             Roo.get(_this.iframe.contentDocument.head).createChild({
18551                 tag : 'link',
18552                 rel : 'stylesheet',
18553                 type : 'text/css',
18554                 href : s
18555             });
18556         });
18557
18558         
18559     },
18560     
18561     removeStylesheets : function()
18562     {
18563         var _this = this;
18564         
18565         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18566             s.remove();
18567         });
18568     }
18569     
18570     // hide stuff that is not compatible
18571     /**
18572      * @event blur
18573      * @hide
18574      */
18575     /**
18576      * @event change
18577      * @hide
18578      */
18579     /**
18580      * @event focus
18581      * @hide
18582      */
18583     /**
18584      * @event specialkey
18585      * @hide
18586      */
18587     /**
18588      * @cfg {String} fieldClass @hide
18589      */
18590     /**
18591      * @cfg {String} focusClass @hide
18592      */
18593     /**
18594      * @cfg {String} autoCreate @hide
18595      */
18596     /**
18597      * @cfg {String} inputType @hide
18598      */
18599     /**
18600      * @cfg {String} invalidClass @hide
18601      */
18602     /**
18603      * @cfg {String} invalidText @hide
18604      */
18605     /**
18606      * @cfg {String} msgFx @hide
18607      */
18608     /**
18609      * @cfg {String} validateOnBlur @hide
18610      */
18611 });
18612
18613 Roo.HtmlEditorCore.white = [
18614         'area', 'br', 'img', 'input', 'hr', 'wbr',
18615         
18616        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
18617        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
18618        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
18619        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
18620        'table',   'ul',         'xmp', 
18621        
18622        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
18623       'thead',   'tr', 
18624      
18625       'dir', 'menu', 'ol', 'ul', 'dl',
18626        
18627       'embed',  'object'
18628 ];
18629
18630
18631 Roo.HtmlEditorCore.black = [
18632     //    'embed',  'object', // enable - backend responsiblity to clean thiese
18633         'applet', // 
18634         'base',   'basefont', 'bgsound', 'blink',  'body', 
18635         'frame',  'frameset', 'head',    'html',   'ilayer', 
18636         'iframe', 'layer',  'link',     'meta',    'object',   
18637         'script', 'style' ,'title',  'xml' // clean later..
18638 ];
18639 Roo.HtmlEditorCore.clean = [
18640     'script', 'style', 'title', 'xml'
18641 ];
18642 Roo.HtmlEditorCore.remove = [
18643     'font'
18644 ];
18645 // attributes..
18646
18647 Roo.HtmlEditorCore.ablack = [
18648     'on'
18649 ];
18650     
18651 Roo.HtmlEditorCore.aclean = [ 
18652     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
18653 ];
18654
18655 // protocols..
18656 Roo.HtmlEditorCore.pwhite= [
18657         'http',  'https',  'mailto'
18658 ];
18659
18660 // white listed style attributes.
18661 Roo.HtmlEditorCore.cwhite= [
18662       //  'text-align', /// default is to allow most things..
18663       
18664          
18665 //        'font-size'//??
18666 ];
18667
18668 // black listed style attributes.
18669 Roo.HtmlEditorCore.cblack= [
18670       //  'font-size' -- this can be set by the project 
18671 ];
18672
18673
18674 Roo.HtmlEditorCore.swapCodes   =[ 
18675     [    8211, "--" ], 
18676     [    8212, "--" ], 
18677     [    8216,  "'" ],  
18678     [    8217, "'" ],  
18679     [    8220, '"' ],  
18680     [    8221, '"' ],  
18681     [    8226, "*" ],  
18682     [    8230, "..." ]
18683 ]; 
18684
18685     /*
18686  * - LGPL
18687  *
18688  * HtmlEditor
18689  * 
18690  */
18691
18692 /**
18693  * @class Roo.bootstrap.HtmlEditor
18694  * @extends Roo.bootstrap.TextArea
18695  * Bootstrap HtmlEditor class
18696
18697  * @constructor
18698  * Create a new HtmlEditor
18699  * @param {Object} config The config object
18700  */
18701
18702 Roo.bootstrap.HtmlEditor = function(config){
18703     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18704     if (!this.toolbars) {
18705         this.toolbars = [];
18706     }
18707     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18708     this.addEvents({
18709             /**
18710              * @event initialize
18711              * Fires when the editor is fully initialized (including the iframe)
18712              * @param {HtmlEditor} this
18713              */
18714             initialize: true,
18715             /**
18716              * @event activate
18717              * Fires when the editor is first receives the focus. Any insertion must wait
18718              * until after this event.
18719              * @param {HtmlEditor} this
18720              */
18721             activate: true,
18722              /**
18723              * @event beforesync
18724              * Fires before the textarea is updated with content from the editor iframe. Return false
18725              * to cancel the sync.
18726              * @param {HtmlEditor} this
18727              * @param {String} html
18728              */
18729             beforesync: true,
18730              /**
18731              * @event beforepush
18732              * Fires before the iframe editor is updated with content from the textarea. Return false
18733              * to cancel the push.
18734              * @param {HtmlEditor} this
18735              * @param {String} html
18736              */
18737             beforepush: true,
18738              /**
18739              * @event sync
18740              * Fires when the textarea is updated with content from the editor iframe.
18741              * @param {HtmlEditor} this
18742              * @param {String} html
18743              */
18744             sync: true,
18745              /**
18746              * @event push
18747              * Fires when the iframe editor is updated with content from the textarea.
18748              * @param {HtmlEditor} this
18749              * @param {String} html
18750              */
18751             push: true,
18752              /**
18753              * @event editmodechange
18754              * Fires when the editor switches edit modes
18755              * @param {HtmlEditor} this
18756              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18757              */
18758             editmodechange: true,
18759             /**
18760              * @event editorevent
18761              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18762              * @param {HtmlEditor} this
18763              */
18764             editorevent: true,
18765             /**
18766              * @event firstfocus
18767              * Fires when on first focus - needed by toolbars..
18768              * @param {HtmlEditor} this
18769              */
18770             firstfocus: true,
18771             /**
18772              * @event autosave
18773              * Auto save the htmlEditor value as a file into Events
18774              * @param {HtmlEditor} this
18775              */
18776             autosave: true,
18777             /**
18778              * @event savedpreview
18779              * preview the saved version of htmlEditor
18780              * @param {HtmlEditor} this
18781              */
18782             savedpreview: true
18783         });
18784 };
18785
18786
18787 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
18788     
18789     
18790       /**
18791      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18792      */
18793     toolbars : false,
18794    
18795      /**
18796      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
18797      *                        Roo.resizable.
18798      */
18799     resizable : false,
18800      /**
18801      * @cfg {Number} height (in pixels)
18802      */   
18803     height: 300,
18804    /**
18805      * @cfg {Number} width (in pixels)
18806      */   
18807     width: false,
18808     
18809     /**
18810      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18811      * 
18812      */
18813     stylesheets: false,
18814     
18815     // id of frame..
18816     frameId: false,
18817     
18818     // private properties
18819     validationEvent : false,
18820     deferHeight: true,
18821     initialized : false,
18822     activated : false,
18823     
18824     onFocus : Roo.emptyFn,
18825     iframePad:3,
18826     hideMode:'offsets',
18827     
18828     
18829     tbContainer : false,
18830     
18831     toolbarContainer :function() {
18832         return this.wrap.select('.x-html-editor-tb',true).first();
18833     },
18834
18835     /**
18836      * Protected method that will not generally be called directly. It
18837      * is called when the editor creates its toolbar. Override this method if you need to
18838      * add custom toolbar buttons.
18839      * @param {HtmlEditor} editor
18840      */
18841     createToolbar : function(){
18842         
18843         Roo.log("create toolbars");
18844         
18845         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18846         this.toolbars[0].render(this.toolbarContainer());
18847         
18848         return;
18849         
18850 //        if (!editor.toolbars || !editor.toolbars.length) {
18851 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18852 //        }
18853 //        
18854 //        for (var i =0 ; i < editor.toolbars.length;i++) {
18855 //            editor.toolbars[i] = Roo.factory(
18856 //                    typeof(editor.toolbars[i]) == 'string' ?
18857 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
18858 //                Roo.bootstrap.HtmlEditor);
18859 //            editor.toolbars[i].init(editor);
18860 //        }
18861     },
18862
18863      
18864     // private
18865     onRender : function(ct, position)
18866     {
18867        // Roo.log("Call onRender: " + this.xtype);
18868         var _t = this;
18869         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18870       
18871         this.wrap = this.inputEl().wrap({
18872             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18873         });
18874         
18875         this.editorcore.onRender(ct, position);
18876          
18877         if (this.resizable) {
18878             this.resizeEl = new Roo.Resizable(this.wrap, {
18879                 pinned : true,
18880                 wrap: true,
18881                 dynamic : true,
18882                 minHeight : this.height,
18883                 height: this.height,
18884                 handles : this.resizable,
18885                 width: this.width,
18886                 listeners : {
18887                     resize : function(r, w, h) {
18888                         _t.onResize(w,h); // -something
18889                     }
18890                 }
18891             });
18892             
18893         }
18894         this.createToolbar(this);
18895        
18896         
18897         if(!this.width && this.resizable){
18898             this.setSize(this.wrap.getSize());
18899         }
18900         if (this.resizeEl) {
18901             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18902             // should trigger onReize..
18903         }
18904         
18905     },
18906
18907     // private
18908     onResize : function(w, h)
18909     {
18910         Roo.log('resize: ' +w + ',' + h );
18911         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18912         var ew = false;
18913         var eh = false;
18914         
18915         if(this.inputEl() ){
18916             if(typeof w == 'number'){
18917                 var aw = w - this.wrap.getFrameWidth('lr');
18918                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18919                 ew = aw;
18920             }
18921             if(typeof h == 'number'){
18922                  var tbh = -11;  // fixme it needs to tool bar size!
18923                 for (var i =0; i < this.toolbars.length;i++) {
18924                     // fixme - ask toolbars for heights?
18925                     tbh += this.toolbars[i].el.getHeight();
18926                     //if (this.toolbars[i].footer) {
18927                     //    tbh += this.toolbars[i].footer.el.getHeight();
18928                     //}
18929                 }
18930               
18931                 
18932                 
18933                 
18934                 
18935                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18936                 ah -= 5; // knock a few pixes off for look..
18937                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18938                 var eh = ah;
18939             }
18940         }
18941         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18942         this.editorcore.onResize(ew,eh);
18943         
18944     },
18945
18946     /**
18947      * Toggles the editor between standard and source edit mode.
18948      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18949      */
18950     toggleSourceEdit : function(sourceEditMode)
18951     {
18952         this.editorcore.toggleSourceEdit(sourceEditMode);
18953         
18954         if(this.editorcore.sourceEditMode){
18955             Roo.log('editor - showing textarea');
18956             
18957 //            Roo.log('in');
18958 //            Roo.log(this.syncValue());
18959             this.syncValue();
18960             this.inputEl().removeClass(['hide', 'x-hidden']);
18961             this.inputEl().dom.removeAttribute('tabIndex');
18962             this.inputEl().focus();
18963         }else{
18964             Roo.log('editor - hiding textarea');
18965 //            Roo.log('out')
18966 //            Roo.log(this.pushValue()); 
18967             this.pushValue();
18968             
18969             this.inputEl().addClass(['hide', 'x-hidden']);
18970             this.inputEl().dom.setAttribute('tabIndex', -1);
18971             //this.deferFocus();
18972         }
18973          
18974         if(this.resizable){
18975             this.setSize(this.wrap.getSize());
18976         }
18977         
18978         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18979     },
18980  
18981     // private (for BoxComponent)
18982     adjustSize : Roo.BoxComponent.prototype.adjustSize,
18983
18984     // private (for BoxComponent)
18985     getResizeEl : function(){
18986         return this.wrap;
18987     },
18988
18989     // private (for BoxComponent)
18990     getPositionEl : function(){
18991         return this.wrap;
18992     },
18993
18994     // private
18995     initEvents : function(){
18996         this.originalValue = this.getValue();
18997     },
18998
18999 //    /**
19000 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19001 //     * @method
19002 //     */
19003 //    markInvalid : Roo.emptyFn,
19004 //    /**
19005 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19006 //     * @method
19007 //     */
19008 //    clearInvalid : Roo.emptyFn,
19009
19010     setValue : function(v){
19011         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19012         this.editorcore.pushValue();
19013     },
19014
19015      
19016     // private
19017     deferFocus : function(){
19018         this.focus.defer(10, this);
19019     },
19020
19021     // doc'ed in Field
19022     focus : function(){
19023         this.editorcore.focus();
19024         
19025     },
19026       
19027
19028     // private
19029     onDestroy : function(){
19030         
19031         
19032         
19033         if(this.rendered){
19034             
19035             for (var i =0; i < this.toolbars.length;i++) {
19036                 // fixme - ask toolbars for heights?
19037                 this.toolbars[i].onDestroy();
19038             }
19039             
19040             this.wrap.dom.innerHTML = '';
19041             this.wrap.remove();
19042         }
19043     },
19044
19045     // private
19046     onFirstFocus : function(){
19047         //Roo.log("onFirstFocus");
19048         this.editorcore.onFirstFocus();
19049          for (var i =0; i < this.toolbars.length;i++) {
19050             this.toolbars[i].onFirstFocus();
19051         }
19052         
19053     },
19054     
19055     // private
19056     syncValue : function()
19057     {   
19058         this.editorcore.syncValue();
19059     },
19060     
19061     pushValue : function()
19062     {   
19063         this.editorcore.pushValue();
19064     }
19065      
19066     
19067     // hide stuff that is not compatible
19068     /**
19069      * @event blur
19070      * @hide
19071      */
19072     /**
19073      * @event change
19074      * @hide
19075      */
19076     /**
19077      * @event focus
19078      * @hide
19079      */
19080     /**
19081      * @event specialkey
19082      * @hide
19083      */
19084     /**
19085      * @cfg {String} fieldClass @hide
19086      */
19087     /**
19088      * @cfg {String} focusClass @hide
19089      */
19090     /**
19091      * @cfg {String} autoCreate @hide
19092      */
19093     /**
19094      * @cfg {String} inputType @hide
19095      */
19096     /**
19097      * @cfg {String} invalidClass @hide
19098      */
19099     /**
19100      * @cfg {String} invalidText @hide
19101      */
19102     /**
19103      * @cfg {String} msgFx @hide
19104      */
19105     /**
19106      * @cfg {String} validateOnBlur @hide
19107      */
19108 });
19109  
19110     
19111    
19112    
19113    
19114       
19115 Roo.namespace('Roo.bootstrap.htmleditor');
19116 /**
19117  * @class Roo.bootstrap.HtmlEditorToolbar1
19118  * Basic Toolbar
19119  * 
19120  * Usage:
19121  *
19122  new Roo.bootstrap.HtmlEditor({
19123     ....
19124     toolbars : [
19125         new Roo.bootstrap.HtmlEditorToolbar1({
19126             disable : { fonts: 1 , format: 1, ..., ... , ...],
19127             btns : [ .... ]
19128         })
19129     }
19130      
19131  * 
19132  * @cfg {Object} disable List of elements to disable..
19133  * @cfg {Array} btns List of additional buttons.
19134  * 
19135  * 
19136  * NEEDS Extra CSS? 
19137  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19138  */
19139  
19140 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19141 {
19142     
19143     Roo.apply(this, config);
19144     
19145     // default disabled, based on 'good practice'..
19146     this.disable = this.disable || {};
19147     Roo.applyIf(this.disable, {
19148         fontSize : true,
19149         colors : true,
19150         specialElements : true
19151     });
19152     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19153     
19154     this.editor = config.editor;
19155     this.editorcore = config.editor.editorcore;
19156     
19157     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19158     
19159     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19160     // dont call parent... till later.
19161 }
19162 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19163      
19164     bar : true,
19165     
19166     editor : false,
19167     editorcore : false,
19168     
19169     
19170     formats : [
19171         "p" ,  
19172         "h1","h2","h3","h4","h5","h6", 
19173         "pre", "code", 
19174         "abbr", "acronym", "address", "cite", "samp", "var",
19175         'div','span'
19176     ],
19177     
19178     onRender : function(ct, position)
19179     {
19180        // Roo.log("Call onRender: " + this.xtype);
19181         
19182        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19183        Roo.log(this.el);
19184        this.el.dom.style.marginBottom = '0';
19185        var _this = this;
19186        var editorcore = this.editorcore;
19187        var editor= this.editor;
19188        
19189        var children = [];
19190        var btn = function(id,cmd , toggle, handler){
19191        
19192             var  event = toggle ? 'toggle' : 'click';
19193        
19194             var a = {
19195                 size : 'sm',
19196                 xtype: 'Button',
19197                 xns: Roo.bootstrap,
19198                 glyphicon : id,
19199                 cmd : id || cmd,
19200                 enableToggle:toggle !== false,
19201                 //html : 'submit'
19202                 pressed : toggle ? false : null,
19203                 listeners : {}
19204             }
19205             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19206                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19207             }
19208             children.push(a);
19209             return a;
19210        }
19211         
19212         var style = {
19213                 xtype: 'Button',
19214                 size : 'sm',
19215                 xns: Roo.bootstrap,
19216                 glyphicon : 'font',
19217                 //html : 'submit'
19218                 menu : {
19219                     xtype: 'Menu',
19220                     xns: Roo.bootstrap,
19221                     items:  []
19222                 }
19223         };
19224         Roo.each(this.formats, function(f) {
19225             style.menu.items.push({
19226                 xtype :'MenuItem',
19227                 xns: Roo.bootstrap,
19228                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19229                 tagname : f,
19230                 listeners : {
19231                     click : function()
19232                     {
19233                         editorcore.insertTag(this.tagname);
19234                         editor.focus();
19235                     }
19236                 }
19237                 
19238             });
19239         });
19240          children.push(style);   
19241             
19242             
19243         btn('bold',false,true);
19244         btn('italic',false,true);
19245         btn('align-left', 'justifyleft',true);
19246         btn('align-center', 'justifycenter',true);
19247         btn('align-right' , 'justifyright',true);
19248         btn('link', false, false, function(btn) {
19249             //Roo.log("create link?");
19250             var url = prompt(this.createLinkText, this.defaultLinkValue);
19251             if(url && url != 'http:/'+'/'){
19252                 this.editorcore.relayCmd('createlink', url);
19253             }
19254         }),
19255         btn('list','insertunorderedlist',true);
19256         btn('pencil', false,true, function(btn){
19257                 Roo.log(this);
19258                 
19259                 this.toggleSourceEdit(btn.pressed);
19260         });
19261         /*
19262         var cog = {
19263                 xtype: 'Button',
19264                 size : 'sm',
19265                 xns: Roo.bootstrap,
19266                 glyphicon : 'cog',
19267                 //html : 'submit'
19268                 menu : {
19269                     xtype: 'Menu',
19270                     xns: Roo.bootstrap,
19271                     items:  []
19272                 }
19273         };
19274         
19275         cog.menu.items.push({
19276             xtype :'MenuItem',
19277             xns: Roo.bootstrap,
19278             html : Clean styles,
19279             tagname : f,
19280             listeners : {
19281                 click : function()
19282                 {
19283                     editorcore.insertTag(this.tagname);
19284                     editor.focus();
19285                 }
19286             }
19287             
19288         });
19289        */
19290         
19291          
19292        this.xtype = 'NavSimplebar';
19293         
19294         for(var i=0;i< children.length;i++) {
19295             
19296             this.buttons.add(this.addxtypeChild(children[i]));
19297             
19298         }
19299         
19300         editor.on('editorevent', this.updateToolbar, this);
19301     },
19302     onBtnClick : function(id)
19303     {
19304        this.editorcore.relayCmd(id);
19305        this.editorcore.focus();
19306     },
19307     
19308     /**
19309      * Protected method that will not generally be called directly. It triggers
19310      * a toolbar update by reading the markup state of the current selection in the editor.
19311      */
19312     updateToolbar: function(){
19313
19314         if(!this.editorcore.activated){
19315             this.editor.onFirstFocus(); // is this neeed?
19316             return;
19317         }
19318
19319         var btns = this.buttons; 
19320         var doc = this.editorcore.doc;
19321         btns.get('bold').setActive(doc.queryCommandState('bold'));
19322         btns.get('italic').setActive(doc.queryCommandState('italic'));
19323         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19324         
19325         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19326         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19327         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19328         
19329         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19330         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19331          /*
19332         
19333         var ans = this.editorcore.getAllAncestors();
19334         if (this.formatCombo) {
19335             
19336             
19337             var store = this.formatCombo.store;
19338             this.formatCombo.setValue("");
19339             for (var i =0; i < ans.length;i++) {
19340                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19341                     // select it..
19342                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19343                     break;
19344                 }
19345             }
19346         }
19347         
19348         
19349         
19350         // hides menus... - so this cant be on a menu...
19351         Roo.bootstrap.MenuMgr.hideAll();
19352         */
19353         Roo.bootstrap.MenuMgr.hideAll();
19354         //this.editorsyncValue();
19355     },
19356     onFirstFocus: function() {
19357         this.buttons.each(function(item){
19358            item.enable();
19359         });
19360     },
19361     toggleSourceEdit : function(sourceEditMode){
19362         
19363           
19364         if(sourceEditMode){
19365             Roo.log("disabling buttons");
19366            this.buttons.each( function(item){
19367                 if(item.cmd != 'pencil'){
19368                     item.disable();
19369                 }
19370             });
19371           
19372         }else{
19373             Roo.log("enabling buttons");
19374             if(this.editorcore.initialized){
19375                 this.buttons.each( function(item){
19376                     item.enable();
19377                 });
19378             }
19379             
19380         }
19381         Roo.log("calling toggole on editor");
19382         // tell the editor that it's been pressed..
19383         this.editor.toggleSourceEdit(sourceEditMode);
19384        
19385     }
19386 });
19387
19388
19389
19390
19391
19392 /**
19393  * @class Roo.bootstrap.Table.AbstractSelectionModel
19394  * @extends Roo.util.Observable
19395  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19396  * implemented by descendant classes.  This class should not be directly instantiated.
19397  * @constructor
19398  */
19399 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19400     this.locked = false;
19401     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19402 };
19403
19404
19405 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19406     /** @ignore Called by the grid automatically. Do not call directly. */
19407     init : function(grid){
19408         this.grid = grid;
19409         this.initEvents();
19410     },
19411
19412     /**
19413      * Locks the selections.
19414      */
19415     lock : function(){
19416         this.locked = true;
19417     },
19418
19419     /**
19420      * Unlocks the selections.
19421      */
19422     unlock : function(){
19423         this.locked = false;
19424     },
19425
19426     /**
19427      * Returns true if the selections are locked.
19428      * @return {Boolean}
19429      */
19430     isLocked : function(){
19431         return this.locked;
19432     }
19433 });
19434 /**
19435  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19436  * @class Roo.bootstrap.Table.RowSelectionModel
19437  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19438  * It supports multiple selections and keyboard selection/navigation. 
19439  * @constructor
19440  * @param {Object} config
19441  */
19442
19443 Roo.bootstrap.Table.RowSelectionModel = function(config){
19444     Roo.apply(this, config);
19445     this.selections = new Roo.util.MixedCollection(false, function(o){
19446         return o.id;
19447     });
19448
19449     this.last = false;
19450     this.lastActive = false;
19451
19452     this.addEvents({
19453         /**
19454              * @event selectionchange
19455              * Fires when the selection changes
19456              * @param {SelectionModel} this
19457              */
19458             "selectionchange" : true,
19459         /**
19460              * @event afterselectionchange
19461              * Fires after the selection changes (eg. by key press or clicking)
19462              * @param {SelectionModel} this
19463              */
19464             "afterselectionchange" : true,
19465         /**
19466              * @event beforerowselect
19467              * Fires when a row is selected being selected, return false to cancel.
19468              * @param {SelectionModel} this
19469              * @param {Number} rowIndex The selected index
19470              * @param {Boolean} keepExisting False if other selections will be cleared
19471              */
19472             "beforerowselect" : true,
19473         /**
19474              * @event rowselect
19475              * Fires when a row is selected.
19476              * @param {SelectionModel} this
19477              * @param {Number} rowIndex The selected index
19478              * @param {Roo.data.Record} r The record
19479              */
19480             "rowselect" : true,
19481         /**
19482              * @event rowdeselect
19483              * Fires when a row is deselected.
19484              * @param {SelectionModel} this
19485              * @param {Number} rowIndex The selected index
19486              */
19487         "rowdeselect" : true
19488     });
19489     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19490     this.locked = false;
19491 };
19492
19493 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19494     /**
19495      * @cfg {Boolean} singleSelect
19496      * True to allow selection of only one row at a time (defaults to false)
19497      */
19498     singleSelect : false,
19499
19500     // private
19501     initEvents : function(){
19502
19503         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19504             this.grid.on("mousedown", this.handleMouseDown, this);
19505         }else{ // allow click to work like normal
19506             this.grid.on("rowclick", this.handleDragableRowClick, this);
19507         }
19508
19509         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19510             "up" : function(e){
19511                 if(!e.shiftKey){
19512                     this.selectPrevious(e.shiftKey);
19513                 }else if(this.last !== false && this.lastActive !== false){
19514                     var last = this.last;
19515                     this.selectRange(this.last,  this.lastActive-1);
19516                     this.grid.getView().focusRow(this.lastActive);
19517                     if(last !== false){
19518                         this.last = last;
19519                     }
19520                 }else{
19521                     this.selectFirstRow();
19522                 }
19523                 this.fireEvent("afterselectionchange", this);
19524             },
19525             "down" : function(e){
19526                 if(!e.shiftKey){
19527                     this.selectNext(e.shiftKey);
19528                 }else if(this.last !== false && this.lastActive !== false){
19529                     var last = this.last;
19530                     this.selectRange(this.last,  this.lastActive+1);
19531                     this.grid.getView().focusRow(this.lastActive);
19532                     if(last !== false){
19533                         this.last = last;
19534                     }
19535                 }else{
19536                     this.selectFirstRow();
19537                 }
19538                 this.fireEvent("afterselectionchange", this);
19539             },
19540             scope: this
19541         });
19542
19543         var view = this.grid.view;
19544         view.on("refresh", this.onRefresh, this);
19545         view.on("rowupdated", this.onRowUpdated, this);
19546         view.on("rowremoved", this.onRemove, this);
19547     },
19548
19549     // private
19550     onRefresh : function(){
19551         var ds = this.grid.dataSource, i, v = this.grid.view;
19552         var s = this.selections;
19553         s.each(function(r){
19554             if((i = ds.indexOfId(r.id)) != -1){
19555                 v.onRowSelect(i);
19556             }else{
19557                 s.remove(r);
19558             }
19559         });
19560     },
19561
19562     // private
19563     onRemove : function(v, index, r){
19564         this.selections.remove(r);
19565     },
19566
19567     // private
19568     onRowUpdated : function(v, index, r){
19569         if(this.isSelected(r)){
19570             v.onRowSelect(index);
19571         }
19572     },
19573
19574     /**
19575      * Select records.
19576      * @param {Array} records The records to select
19577      * @param {Boolean} keepExisting (optional) True to keep existing selections
19578      */
19579     selectRecords : function(records, keepExisting){
19580         if(!keepExisting){
19581             this.clearSelections();
19582         }
19583         var ds = this.grid.dataSource;
19584         for(var i = 0, len = records.length; i < len; i++){
19585             this.selectRow(ds.indexOf(records[i]), true);
19586         }
19587     },
19588
19589     /**
19590      * Gets the number of selected rows.
19591      * @return {Number}
19592      */
19593     getCount : function(){
19594         return this.selections.length;
19595     },
19596
19597     /**
19598      * Selects the first row in the grid.
19599      */
19600     selectFirstRow : function(){
19601         this.selectRow(0);
19602     },
19603
19604     /**
19605      * Select the last row.
19606      * @param {Boolean} keepExisting (optional) True to keep existing selections
19607      */
19608     selectLastRow : function(keepExisting){
19609         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19610     },
19611
19612     /**
19613      * Selects the row immediately following the last selected row.
19614      * @param {Boolean} keepExisting (optional) True to keep existing selections
19615      */
19616     selectNext : function(keepExisting){
19617         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19618             this.selectRow(this.last+1, keepExisting);
19619             this.grid.getView().focusRow(this.last);
19620         }
19621     },
19622
19623     /**
19624      * Selects the row that precedes the last selected row.
19625      * @param {Boolean} keepExisting (optional) True to keep existing selections
19626      */
19627     selectPrevious : function(keepExisting){
19628         if(this.last){
19629             this.selectRow(this.last-1, keepExisting);
19630             this.grid.getView().focusRow(this.last);
19631         }
19632     },
19633
19634     /**
19635      * Returns the selected records
19636      * @return {Array} Array of selected records
19637      */
19638     getSelections : function(){
19639         return [].concat(this.selections.items);
19640     },
19641
19642     /**
19643      * Returns the first selected record.
19644      * @return {Record}
19645      */
19646     getSelected : function(){
19647         return this.selections.itemAt(0);
19648     },
19649
19650
19651     /**
19652      * Clears all selections.
19653      */
19654     clearSelections : function(fast){
19655         if(this.locked) return;
19656         if(fast !== true){
19657             var ds = this.grid.dataSource;
19658             var s = this.selections;
19659             s.each(function(r){
19660                 this.deselectRow(ds.indexOfId(r.id));
19661             }, this);
19662             s.clear();
19663         }else{
19664             this.selections.clear();
19665         }
19666         this.last = false;
19667     },
19668
19669
19670     /**
19671      * Selects all rows.
19672      */
19673     selectAll : function(){
19674         if(this.locked) return;
19675         this.selections.clear();
19676         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19677             this.selectRow(i, true);
19678         }
19679     },
19680
19681     /**
19682      * Returns True if there is a selection.
19683      * @return {Boolean}
19684      */
19685     hasSelection : function(){
19686         return this.selections.length > 0;
19687     },
19688
19689     /**
19690      * Returns True if the specified row is selected.
19691      * @param {Number/Record} record The record or index of the record to check
19692      * @return {Boolean}
19693      */
19694     isSelected : function(index){
19695         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19696         return (r && this.selections.key(r.id) ? true : false);
19697     },
19698
19699     /**
19700      * Returns True if the specified record id is selected.
19701      * @param {String} id The id of record to check
19702      * @return {Boolean}
19703      */
19704     isIdSelected : function(id){
19705         return (this.selections.key(id) ? true : false);
19706     },
19707
19708     // private
19709     handleMouseDown : function(e, t){
19710         var view = this.grid.getView(), rowIndex;
19711         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19712             return;
19713         };
19714         if(e.shiftKey && this.last !== false){
19715             var last = this.last;
19716             this.selectRange(last, rowIndex, e.ctrlKey);
19717             this.last = last; // reset the last
19718             view.focusRow(rowIndex);
19719         }else{
19720             var isSelected = this.isSelected(rowIndex);
19721             if(e.button !== 0 && isSelected){
19722                 view.focusRow(rowIndex);
19723             }else if(e.ctrlKey && isSelected){
19724                 this.deselectRow(rowIndex);
19725             }else if(!isSelected){
19726                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19727                 view.focusRow(rowIndex);
19728             }
19729         }
19730         this.fireEvent("afterselectionchange", this);
19731     },
19732     // private
19733     handleDragableRowClick :  function(grid, rowIndex, e) 
19734     {
19735         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19736             this.selectRow(rowIndex, false);
19737             grid.view.focusRow(rowIndex);
19738              this.fireEvent("afterselectionchange", this);
19739         }
19740     },
19741     
19742     /**
19743      * Selects multiple rows.
19744      * @param {Array} rows Array of the indexes of the row to select
19745      * @param {Boolean} keepExisting (optional) True to keep existing selections
19746      */
19747     selectRows : function(rows, keepExisting){
19748         if(!keepExisting){
19749             this.clearSelections();
19750         }
19751         for(var i = 0, len = rows.length; i < len; i++){
19752             this.selectRow(rows[i], true);
19753         }
19754     },
19755
19756     /**
19757      * Selects a range of rows. All rows in between startRow and endRow are also selected.
19758      * @param {Number} startRow The index of the first row in the range
19759      * @param {Number} endRow The index of the last row in the range
19760      * @param {Boolean} keepExisting (optional) True to retain existing selections
19761      */
19762     selectRange : function(startRow, endRow, keepExisting){
19763         if(this.locked) return;
19764         if(!keepExisting){
19765             this.clearSelections();
19766         }
19767         if(startRow <= endRow){
19768             for(var i = startRow; i <= endRow; i++){
19769                 this.selectRow(i, true);
19770             }
19771         }else{
19772             for(var i = startRow; i >= endRow; i--){
19773                 this.selectRow(i, true);
19774             }
19775         }
19776     },
19777
19778     /**
19779      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19780      * @param {Number} startRow The index of the first row in the range
19781      * @param {Number} endRow The index of the last row in the range
19782      */
19783     deselectRange : function(startRow, endRow, preventViewNotify){
19784         if(this.locked) return;
19785         for(var i = startRow; i <= endRow; i++){
19786             this.deselectRow(i, preventViewNotify);
19787         }
19788     },
19789
19790     /**
19791      * Selects a row.
19792      * @param {Number} row The index of the row to select
19793      * @param {Boolean} keepExisting (optional) True to keep existing selections
19794      */
19795     selectRow : function(index, keepExisting, preventViewNotify){
19796         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19797         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19798             if(!keepExisting || this.singleSelect){
19799                 this.clearSelections();
19800             }
19801             var r = this.grid.dataSource.getAt(index);
19802             this.selections.add(r);
19803             this.last = this.lastActive = index;
19804             if(!preventViewNotify){
19805                 this.grid.getView().onRowSelect(index);
19806             }
19807             this.fireEvent("rowselect", this, index, r);
19808             this.fireEvent("selectionchange", this);
19809         }
19810     },
19811
19812     /**
19813      * Deselects a row.
19814      * @param {Number} row The index of the row to deselect
19815      */
19816     deselectRow : function(index, preventViewNotify){
19817         if(this.locked) return;
19818         if(this.last == index){
19819             this.last = false;
19820         }
19821         if(this.lastActive == index){
19822             this.lastActive = false;
19823         }
19824         var r = this.grid.dataSource.getAt(index);
19825         this.selections.remove(r);
19826         if(!preventViewNotify){
19827             this.grid.getView().onRowDeselect(index);
19828         }
19829         this.fireEvent("rowdeselect", this, index);
19830         this.fireEvent("selectionchange", this);
19831     },
19832
19833     // private
19834     restoreLast : function(){
19835         if(this._last){
19836             this.last = this._last;
19837         }
19838     },
19839
19840     // private
19841     acceptsNav : function(row, col, cm){
19842         return !cm.isHidden(col) && cm.isCellEditable(col, row);
19843     },
19844
19845     // private
19846     onEditorKey : function(field, e){
19847         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19848         if(k == e.TAB){
19849             e.stopEvent();
19850             ed.completeEdit();
19851             if(e.shiftKey){
19852                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19853             }else{
19854                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19855             }
19856         }else if(k == e.ENTER && !e.ctrlKey){
19857             e.stopEvent();
19858             ed.completeEdit();
19859             if(e.shiftKey){
19860                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19861             }else{
19862                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19863             }
19864         }else if(k == e.ESC){
19865             ed.cancelEdit();
19866         }
19867         if(newCell){
19868             g.startEditing(newCell[0], newCell[1]);
19869         }
19870     }
19871 });/*
19872  * Based on:
19873  * Ext JS Library 1.1.1
19874  * Copyright(c) 2006-2007, Ext JS, LLC.
19875  *
19876  * Originally Released Under LGPL - original licence link has changed is not relivant.
19877  *
19878  * Fork - LGPL
19879  * <script type="text/javascript">
19880  */
19881  
19882 /**
19883  * @class Roo.bootstrap.PagingToolbar
19884  * @extends Roo.Row
19885  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19886  * @constructor
19887  * Create a new PagingToolbar
19888  * @param {Object} config The config object
19889  */
19890 Roo.bootstrap.PagingToolbar = function(config)
19891 {
19892     // old args format still supported... - xtype is prefered..
19893         // created from xtype...
19894     var ds = config.dataSource;
19895     this.toolbarItems = [];
19896     if (config.items) {
19897         this.toolbarItems = config.items;
19898 //        config.items = [];
19899     }
19900     
19901     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19902     this.ds = ds;
19903     this.cursor = 0;
19904     if (ds) { 
19905         this.bind(ds);
19906     }
19907     
19908     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19909     
19910 };
19911
19912 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19913     /**
19914      * @cfg {Roo.data.Store} dataSource
19915      * The underlying data store providing the paged data
19916      */
19917     /**
19918      * @cfg {String/HTMLElement/Element} container
19919      * container The id or element that will contain the toolbar
19920      */
19921     /**
19922      * @cfg {Boolean} displayInfo
19923      * True to display the displayMsg (defaults to false)
19924      */
19925     /**
19926      * @cfg {Number} pageSize
19927      * The number of records to display per page (defaults to 20)
19928      */
19929     pageSize: 20,
19930     /**
19931      * @cfg {String} displayMsg
19932      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19933      */
19934     displayMsg : 'Displaying {0} - {1} of {2}',
19935     /**
19936      * @cfg {String} emptyMsg
19937      * The message to display when no records are found (defaults to "No data to display")
19938      */
19939     emptyMsg : 'No data to display',
19940     /**
19941      * Customizable piece of the default paging text (defaults to "Page")
19942      * @type String
19943      */
19944     beforePageText : "Page",
19945     /**
19946      * Customizable piece of the default paging text (defaults to "of %0")
19947      * @type String
19948      */
19949     afterPageText : "of {0}",
19950     /**
19951      * Customizable piece of the default paging text (defaults to "First Page")
19952      * @type String
19953      */
19954     firstText : "First Page",
19955     /**
19956      * Customizable piece of the default paging text (defaults to "Previous Page")
19957      * @type String
19958      */
19959     prevText : "Previous Page",
19960     /**
19961      * Customizable piece of the default paging text (defaults to "Next Page")
19962      * @type String
19963      */
19964     nextText : "Next Page",
19965     /**
19966      * Customizable piece of the default paging text (defaults to "Last Page")
19967      * @type String
19968      */
19969     lastText : "Last Page",
19970     /**
19971      * Customizable piece of the default paging text (defaults to "Refresh")
19972      * @type String
19973      */
19974     refreshText : "Refresh",
19975
19976     buttons : false,
19977     // private
19978     onRender : function(ct, position) 
19979     {
19980         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19981         this.navgroup.parentId = this.id;
19982         this.navgroup.onRender(this.el, null);
19983         // add the buttons to the navgroup
19984         
19985         if(this.displayInfo){
19986             Roo.log(this.el.select('ul.navbar-nav',true).first());
19987             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19988             this.displayEl = this.el.select('.x-paging-info', true).first();
19989 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19990 //            this.displayEl = navel.el.select('span',true).first();
19991         }
19992         
19993         var _this = this;
19994         
19995         if(this.buttons){
19996             Roo.each(_this.buttons, function(e){
19997                Roo.factory(e).onRender(_this.el, null);
19998             });
19999         }
20000             
20001         Roo.each(_this.toolbarItems, function(e) {
20002             _this.navgroup.addItem(e);
20003         });
20004         
20005         
20006         this.first = this.navgroup.addItem({
20007             tooltip: this.firstText,
20008             cls: "prev",
20009             icon : 'fa fa-backward',
20010             disabled: true,
20011             preventDefault: true,
20012             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20013         });
20014         
20015         this.prev =  this.navgroup.addItem({
20016             tooltip: this.prevText,
20017             cls: "prev",
20018             icon : 'fa fa-step-backward',
20019             disabled: true,
20020             preventDefault: true,
20021             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20022         });
20023     //this.addSeparator();
20024         
20025         
20026         var field = this.navgroup.addItem( {
20027             tagtype : 'span',
20028             cls : 'x-paging-position',
20029             
20030             html : this.beforePageText  +
20031                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20032                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20033          } ); //?? escaped?
20034         
20035         this.field = field.el.select('input', true).first();
20036         this.field.on("keydown", this.onPagingKeydown, this);
20037         this.field.on("focus", function(){this.dom.select();});
20038     
20039     
20040         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20041         //this.field.setHeight(18);
20042         //this.addSeparator();
20043         this.next = this.navgroup.addItem({
20044             tooltip: this.nextText,
20045             cls: "next",
20046             html : ' <i class="fa fa-step-forward">',
20047             disabled: true,
20048             preventDefault: true,
20049             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20050         });
20051         this.last = this.navgroup.addItem({
20052             tooltip: this.lastText,
20053             icon : 'fa fa-forward',
20054             cls: "next",
20055             disabled: true,
20056             preventDefault: true,
20057             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20058         });
20059     //this.addSeparator();
20060         this.loading = this.navgroup.addItem({
20061             tooltip: this.refreshText,
20062             icon: 'fa fa-refresh',
20063             preventDefault: true,
20064             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20065         });
20066
20067     },
20068
20069     // private
20070     updateInfo : function(){
20071         if(this.displayEl){
20072             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20073             var msg = count == 0 ?
20074                 this.emptyMsg :
20075                 String.format(
20076                     this.displayMsg,
20077                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20078                 );
20079             this.displayEl.update(msg);
20080         }
20081     },
20082
20083     // private
20084     onLoad : function(ds, r, o){
20085        this.cursor = o.params ? o.params.start : 0;
20086        var d = this.getPageData(),
20087             ap = d.activePage,
20088             ps = d.pages;
20089         
20090        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20091        this.field.dom.value = ap;
20092        this.first.setDisabled(ap == 1);
20093        this.prev.setDisabled(ap == 1);
20094        this.next.setDisabled(ap == ps);
20095        this.last.setDisabled(ap == ps);
20096        this.loading.enable();
20097        this.updateInfo();
20098     },
20099
20100     // private
20101     getPageData : function(){
20102         var total = this.ds.getTotalCount();
20103         return {
20104             total : total,
20105             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20106             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20107         };
20108     },
20109
20110     // private
20111     onLoadError : function(){
20112         this.loading.enable();
20113     },
20114
20115     // private
20116     onPagingKeydown : function(e){
20117         var k = e.getKey();
20118         var d = this.getPageData();
20119         if(k == e.RETURN){
20120             var v = this.field.dom.value, pageNum;
20121             if(!v || isNaN(pageNum = parseInt(v, 10))){
20122                 this.field.dom.value = d.activePage;
20123                 return;
20124             }
20125             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20126             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20127             e.stopEvent();
20128         }
20129         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))
20130         {
20131           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20132           this.field.dom.value = pageNum;
20133           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20134           e.stopEvent();
20135         }
20136         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20137         {
20138           var v = this.field.dom.value, pageNum; 
20139           var increment = (e.shiftKey) ? 10 : 1;
20140           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20141             increment *= -1;
20142           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20143             this.field.dom.value = d.activePage;
20144             return;
20145           }
20146           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20147           {
20148             this.field.dom.value = parseInt(v, 10) + increment;
20149             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20150             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20151           }
20152           e.stopEvent();
20153         }
20154     },
20155
20156     // private
20157     beforeLoad : function(){
20158         if(this.loading){
20159             this.loading.disable();
20160         }
20161     },
20162
20163     // private
20164     onClick : function(which){
20165         
20166         var ds = this.ds;
20167         if (!ds) {
20168             return;
20169         }
20170         
20171         switch(which){
20172             case "first":
20173                 ds.load({params:{start: 0, limit: this.pageSize}});
20174             break;
20175             case "prev":
20176                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20177             break;
20178             case "next":
20179                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20180             break;
20181             case "last":
20182                 var total = ds.getTotalCount();
20183                 var extra = total % this.pageSize;
20184                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20185                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20186             break;
20187             case "refresh":
20188                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20189             break;
20190         }
20191     },
20192
20193     /**
20194      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20195      * @param {Roo.data.Store} store The data store to unbind
20196      */
20197     unbind : function(ds){
20198         ds.un("beforeload", this.beforeLoad, this);
20199         ds.un("load", this.onLoad, this);
20200         ds.un("loadexception", this.onLoadError, this);
20201         ds.un("remove", this.updateInfo, this);
20202         ds.un("add", this.updateInfo, this);
20203         this.ds = undefined;
20204     },
20205
20206     /**
20207      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20208      * @param {Roo.data.Store} store The data store to bind
20209      */
20210     bind : function(ds){
20211         ds.on("beforeload", this.beforeLoad, this);
20212         ds.on("load", this.onLoad, this);
20213         ds.on("loadexception", this.onLoadError, this);
20214         ds.on("remove", this.updateInfo, this);
20215         ds.on("add", this.updateInfo, this);
20216         this.ds = ds;
20217     }
20218 });/*
20219  * - LGPL
20220  *
20221  * element
20222  * 
20223  */
20224
20225 /**
20226  * @class Roo.bootstrap.MessageBar
20227  * @extends Roo.bootstrap.Component
20228  * Bootstrap MessageBar class
20229  * @cfg {String} html contents of the MessageBar
20230  * @cfg {String} weight (info | success | warning | danger) default info
20231  * @cfg {String} beforeClass insert the bar before the given class
20232  * @cfg {Boolean} closable (true | false) default false
20233  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20234  * 
20235  * @constructor
20236  * Create a new Element
20237  * @param {Object} config The config object
20238  */
20239
20240 Roo.bootstrap.MessageBar = function(config){
20241     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20242 };
20243
20244 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20245     
20246     html: '',
20247     weight: 'info',
20248     closable: false,
20249     fixed: false,
20250     beforeClass: 'bootstrap-sticky-wrap',
20251     
20252     getAutoCreate : function(){
20253         
20254         var cfg = {
20255             tag: 'div',
20256             cls: 'alert alert-dismissable alert-' + this.weight,
20257             cn: [
20258                 {
20259                     tag: 'span',
20260                     cls: 'message',
20261                     html: this.html || ''
20262                 }
20263             ]
20264         }
20265         
20266         if(this.fixed){
20267             cfg.cls += ' alert-messages-fixed';
20268         }
20269         
20270         if(this.closable){
20271             cfg.cn.push({
20272                 tag: 'button',
20273                 cls: 'close',
20274                 html: 'x'
20275             });
20276         }
20277         
20278         return cfg;
20279     },
20280     
20281     onRender : function(ct, position)
20282     {
20283         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20284         
20285         if(!this.el){
20286             var cfg = Roo.apply({},  this.getAutoCreate());
20287             cfg.id = Roo.id();
20288             
20289             if (this.cls) {
20290                 cfg.cls += ' ' + this.cls;
20291             }
20292             if (this.style) {
20293                 cfg.style = this.style;
20294             }
20295             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20296             
20297             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20298         }
20299         
20300         this.el.select('>button.close').on('click', this.hide, this);
20301         
20302     },
20303     
20304     show : function()
20305     {
20306         if (!this.rendered) {
20307             this.render();
20308         }
20309         
20310         this.el.show();
20311         
20312         this.fireEvent('show', this);
20313         
20314     },
20315     
20316     hide : function()
20317     {
20318         if (!this.rendered) {
20319             this.render();
20320         }
20321         
20322         this.el.hide();
20323         
20324         this.fireEvent('hide', this);
20325     },
20326     
20327     update : function()
20328     {
20329 //        var e = this.el.dom.firstChild;
20330 //        
20331 //        if(this.closable){
20332 //            e = e.nextSibling;
20333 //        }
20334 //        
20335 //        e.data = this.html || '';
20336
20337         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20338     }
20339    
20340 });
20341
20342  
20343
20344      /*
20345  * - LGPL
20346  *
20347  * Graph
20348  * 
20349  */
20350
20351
20352 /**
20353  * @class Roo.bootstrap.Graph
20354  * @extends Roo.bootstrap.Component
20355  * Bootstrap Graph class
20356 > Prameters
20357  -sm {number} sm 4
20358  -md {number} md 5
20359  @cfg {String} graphtype  bar | vbar | pie
20360  @cfg {number} g_x coodinator | centre x (pie)
20361  @cfg {number} g_y coodinator | centre y (pie)
20362  @cfg {number} g_r radius (pie)
20363  @cfg {number} g_height height of the chart (respected by all elements in the set)
20364  @cfg {number} g_width width of the chart (respected by all elements in the set)
20365  @cfg {Object} title The title of the chart
20366     
20367  -{Array}  values
20368  -opts (object) options for the chart 
20369      o {
20370      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20371      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20372      o vgutter (number)
20373      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.
20374      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20375      o to
20376      o stretch (boolean)
20377      o }
20378  -opts (object) options for the pie
20379      o{
20380      o cut
20381      o startAngle (number)
20382      o endAngle (number)
20383      } 
20384  *
20385  * @constructor
20386  * Create a new Input
20387  * @param {Object} config The config object
20388  */
20389
20390 Roo.bootstrap.Graph = function(config){
20391     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20392     
20393     this.addEvents({
20394         // img events
20395         /**
20396          * @event click
20397          * The img click event for the img.
20398          * @param {Roo.EventObject} e
20399          */
20400         "click" : true
20401     });
20402 };
20403
20404 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20405     
20406     sm: 4,
20407     md: 5,
20408     graphtype: 'bar',
20409     g_height: 250,
20410     g_width: 400,
20411     g_x: 50,
20412     g_y: 50,
20413     g_r: 30,
20414     opts:{
20415         //g_colors: this.colors,
20416         g_type: 'soft',
20417         g_gutter: '20%'
20418
20419     },
20420     title : false,
20421
20422     getAutoCreate : function(){
20423         
20424         var cfg = {
20425             tag: 'div',
20426             html : null
20427         }
20428         
20429         
20430         return  cfg;
20431     },
20432
20433     onRender : function(ct,position){
20434         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20435         this.raphael = Raphael(this.el.dom);
20436         
20437                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20438                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20439                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20440                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20441                 /*
20442                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20443                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20444                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20445                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20446                 
20447                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20448                 r.barchart(330, 10, 300, 220, data1);
20449                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20450                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20451                 */
20452                 
20453                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20454                 // r.barchart(30, 30, 560, 250,  xdata, {
20455                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20456                 //     axis : "0 0 1 1",
20457                 //     axisxlabels :  xdata
20458                 //     //yvalues : cols,
20459                    
20460                 // });
20461 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20462 //        
20463 //        this.load(null,xdata,{
20464 //                axis : "0 0 1 1",
20465 //                axisxlabels :  xdata
20466 //                });
20467
20468     },
20469
20470     load : function(graphtype,xdata,opts){
20471         this.raphael.clear();
20472         if(!graphtype) {
20473             graphtype = this.graphtype;
20474         }
20475         if(!opts){
20476             opts = this.opts;
20477         }
20478         var r = this.raphael,
20479             fin = function () {
20480                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20481             },
20482             fout = function () {
20483                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20484             },
20485             pfin = function() {
20486                 this.sector.stop();
20487                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20488
20489                 if (this.label) {
20490                     this.label[0].stop();
20491                     this.label[0].attr({ r: 7.5 });
20492                     this.label[1].attr({ "font-weight": 800 });
20493                 }
20494             },
20495             pfout = function() {
20496                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20497
20498                 if (this.label) {
20499                     this.label[0].animate({ r: 5 }, 500, "bounce");
20500                     this.label[1].attr({ "font-weight": 400 });
20501                 }
20502             };
20503
20504         switch(graphtype){
20505             case 'bar':
20506                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20507                 break;
20508             case 'hbar':
20509                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20510                 break;
20511             case 'pie':
20512 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20513 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20514 //            
20515                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20516                 
20517                 break;
20518
20519         }
20520         
20521         if(this.title){
20522             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20523         }
20524         
20525     },
20526     
20527     setTitle: function(o)
20528     {
20529         this.title = o;
20530     },
20531     
20532     initEvents: function() {
20533         
20534         if(!this.href){
20535             this.el.on('click', this.onClick, this);
20536         }
20537     },
20538     
20539     onClick : function(e)
20540     {
20541         Roo.log('img onclick');
20542         this.fireEvent('click', this, e);
20543     }
20544    
20545 });
20546
20547  
20548 /*
20549  * - LGPL
20550  *
20551  * numberBox
20552  * 
20553  */
20554 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20555
20556 /**
20557  * @class Roo.bootstrap.dash.NumberBox
20558  * @extends Roo.bootstrap.Component
20559  * Bootstrap NumberBox class
20560  * @cfg {String} headline Box headline
20561  * @cfg {String} content Box content
20562  * @cfg {String} icon Box icon
20563  * @cfg {String} footer Footer text
20564  * @cfg {String} fhref Footer href
20565  * 
20566  * @constructor
20567  * Create a new NumberBox
20568  * @param {Object} config The config object
20569  */
20570
20571
20572 Roo.bootstrap.dash.NumberBox = function(config){
20573     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20574     
20575 };
20576
20577 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
20578     
20579     headline : '',
20580     content : '',
20581     icon : '',
20582     footer : '',
20583     fhref : '',
20584     ficon : '',
20585     
20586     getAutoCreate : function(){
20587         
20588         var cfg = {
20589             tag : 'div',
20590             cls : 'small-box ',
20591             cn : [
20592                 {
20593                     tag : 'div',
20594                     cls : 'inner',
20595                     cn :[
20596                         {
20597                             tag : 'h3',
20598                             cls : 'roo-headline',
20599                             html : this.headline
20600                         },
20601                         {
20602                             tag : 'p',
20603                             cls : 'roo-content',
20604                             html : this.content
20605                         }
20606                     ]
20607                 }
20608             ]
20609         }
20610         
20611         if(this.icon){
20612             cfg.cn.push({
20613                 tag : 'div',
20614                 cls : 'icon',
20615                 cn :[
20616                     {
20617                         tag : 'i',
20618                         cls : 'ion ' + this.icon
20619                     }
20620                 ]
20621             });
20622         }
20623         
20624         if(this.footer){
20625             var footer = {
20626                 tag : 'a',
20627                 cls : 'small-box-footer',
20628                 href : this.fhref || '#',
20629                 html : this.footer
20630             };
20631             
20632             cfg.cn.push(footer);
20633             
20634         }
20635         
20636         return  cfg;
20637     },
20638
20639     onRender : function(ct,position){
20640         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20641
20642
20643        
20644                 
20645     },
20646
20647     setHeadline: function (value)
20648     {
20649         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20650     },
20651     
20652     setFooter: function (value, href)
20653     {
20654         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20655         
20656         if(href){
20657             this.el.select('a.small-box-footer',true).first().attr('href', href);
20658         }
20659         
20660     },
20661
20662     setContent: function (value)
20663     {
20664         this.el.select('.roo-content',true).first().dom.innerHTML = value;
20665     },
20666
20667     initEvents: function() 
20668     {   
20669         
20670     }
20671     
20672 });
20673
20674  
20675 /*
20676  * - LGPL
20677  *
20678  * TabBox
20679  * 
20680  */
20681 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20682
20683 /**
20684  * @class Roo.bootstrap.dash.TabBox
20685  * @extends Roo.bootstrap.Component
20686  * Bootstrap TabBox class
20687  * @cfg {String} title Title of the TabBox
20688  * @cfg {String} icon Icon of the TabBox
20689  * @cfg {Boolean} showtabs (true|false) show the tabs default true
20690  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20691  * 
20692  * @constructor
20693  * Create a new TabBox
20694  * @param {Object} config The config object
20695  */
20696
20697
20698 Roo.bootstrap.dash.TabBox = function(config){
20699     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20700     this.addEvents({
20701         // raw events
20702         /**
20703          * @event addpane
20704          * When a pane is added
20705          * @param {Roo.bootstrap.dash.TabPane} pane
20706          */
20707         "addpane" : true,
20708         /**
20709          * @event activatepane
20710          * When a pane is activated
20711          * @param {Roo.bootstrap.dash.TabPane} pane
20712          */
20713         "activatepane" : true
20714         
20715          
20716     });
20717     
20718     this.panes = [];
20719 };
20720
20721 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
20722
20723     title : '',
20724     icon : false,
20725     showtabs : true,
20726     tabScrollable : false,
20727     
20728     getChildContainer : function()
20729     {
20730         return this.el.select('.tab-content', true).first();
20731     },
20732     
20733     getAutoCreate : function(){
20734         
20735         var header = {
20736             tag: 'li',
20737             cls: 'pull-left header',
20738             html: this.title,
20739             cn : []
20740         };
20741         
20742         if(this.icon){
20743             header.cn.push({
20744                 tag: 'i',
20745                 cls: 'fa ' + this.icon
20746             });
20747         }
20748         
20749         var h = {
20750             tag: 'ul',
20751             cls: 'nav nav-tabs pull-right',
20752             cn: [
20753                 header
20754             ]
20755         };
20756         
20757         if(this.tabScrollable){
20758             h = {
20759                 tag: 'div',
20760                 cls: 'tab-header',
20761                 cn: [
20762                     {
20763                         tag: 'ul',
20764                         cls: 'nav nav-tabs pull-right',
20765                         cn: [
20766                             header
20767                         ]
20768                     }
20769                 ]
20770             }
20771         }
20772         
20773         var cfg = {
20774             tag: 'div',
20775             cls: 'nav-tabs-custom',
20776             cn: [
20777                 h,
20778                 {
20779                     tag: 'div',
20780                     cls: 'tab-content no-padding',
20781                     cn: []
20782                 }
20783             ]
20784         }
20785
20786         return  cfg;
20787     },
20788     initEvents : function()
20789     {
20790         //Roo.log('add add pane handler');
20791         this.on('addpane', this.onAddPane, this);
20792     },
20793      /**
20794      * Updates the box title
20795      * @param {String} html to set the title to.
20796      */
20797     setTitle : function(value)
20798     {
20799         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20800     },
20801     onAddPane : function(pane)
20802     {
20803         this.panes.push(pane);
20804         //Roo.log('addpane');
20805         //Roo.log(pane);
20806         // tabs are rendere left to right..
20807         if(!this.showtabs){
20808             return;
20809         }
20810         
20811         var ctr = this.el.select('.nav-tabs', true).first();
20812          
20813          
20814         var existing = ctr.select('.nav-tab',true);
20815         var qty = existing.getCount();;
20816         
20817         
20818         var tab = ctr.createChild({
20819             tag : 'li',
20820             cls : 'nav-tab' + (qty ? '' : ' active'),
20821             cn : [
20822                 {
20823                     tag : 'a',
20824                     href:'#',
20825                     html : pane.title
20826                 }
20827             ]
20828         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20829         pane.tab = tab;
20830         
20831         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20832         if (!qty) {
20833             pane.el.addClass('active');
20834         }
20835         
20836                 
20837     },
20838     onTabClick : function(ev,un,ob,pane)
20839     {
20840         //Roo.log('tab - prev default');
20841         ev.preventDefault();
20842         
20843         
20844         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20845         pane.tab.addClass('active');
20846         //Roo.log(pane.title);
20847         this.getChildContainer().select('.tab-pane',true).removeClass('active');
20848         // technically we should have a deactivate event.. but maybe add later.
20849         // and it should not de-activate the selected tab...
20850         this.fireEvent('activatepane', pane);
20851         pane.el.addClass('active');
20852         pane.fireEvent('activate');
20853         
20854         
20855     },
20856     
20857     getActivePane : function()
20858     {
20859         var r = false;
20860         Roo.each(this.panes, function(p) {
20861             if(p.el.hasClass('active')){
20862                 r = p;
20863                 return false;
20864             }
20865             
20866             return;
20867         });
20868         
20869         return r;
20870     }
20871     
20872     
20873 });
20874
20875  
20876 /*
20877  * - LGPL
20878  *
20879  * Tab pane
20880  * 
20881  */
20882 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20883 /**
20884  * @class Roo.bootstrap.TabPane
20885  * @extends Roo.bootstrap.Component
20886  * Bootstrap TabPane class
20887  * @cfg {Boolean} active (false | true) Default false
20888  * @cfg {String} title title of panel
20889
20890  * 
20891  * @constructor
20892  * Create a new TabPane
20893  * @param {Object} config The config object
20894  */
20895
20896 Roo.bootstrap.dash.TabPane = function(config){
20897     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20898     
20899     this.addEvents({
20900         // raw events
20901         /**
20902          * @event activate
20903          * When a pane is activated
20904          * @param {Roo.bootstrap.dash.TabPane} pane
20905          */
20906         "activate" : true
20907          
20908     });
20909 };
20910
20911 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
20912     
20913     active : false,
20914     title : '',
20915     
20916     // the tabBox that this is attached to.
20917     tab : false,
20918      
20919     getAutoCreate : function() 
20920     {
20921         var cfg = {
20922             tag: 'div',
20923             cls: 'tab-pane'
20924         }
20925         
20926         if(this.active){
20927             cfg.cls += ' active';
20928         }
20929         
20930         return cfg;
20931     },
20932     initEvents  : function()
20933     {
20934         //Roo.log('trigger add pane handler');
20935         this.parent().fireEvent('addpane', this)
20936     },
20937     
20938      /**
20939      * Updates the tab title 
20940      * @param {String} html to set the title to.
20941      */
20942     setTitle: function(str)
20943     {
20944         if (!this.tab) {
20945             return;
20946         }
20947         this.title = str;
20948         this.tab.select('a', true).first().dom.innerHTML = str;
20949         
20950     }
20951     
20952     
20953     
20954 });
20955
20956  
20957
20958
20959  /*
20960  * - LGPL
20961  *
20962  * menu
20963  * 
20964  */
20965 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20966
20967 /**
20968  * @class Roo.bootstrap.menu.Menu
20969  * @extends Roo.bootstrap.Component
20970  * Bootstrap Menu class - container for Menu
20971  * @cfg {String} html Text of the menu
20972  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20973  * @cfg {String} icon Font awesome icon
20974  * @cfg {String} pos Menu align to (top | bottom) default bottom
20975  * 
20976  * 
20977  * @constructor
20978  * Create a new Menu
20979  * @param {Object} config The config object
20980  */
20981
20982
20983 Roo.bootstrap.menu.Menu = function(config){
20984     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20985     
20986     this.addEvents({
20987         /**
20988          * @event beforeshow
20989          * Fires before this menu is displayed
20990          * @param {Roo.bootstrap.menu.Menu} this
20991          */
20992         beforeshow : true,
20993         /**
20994          * @event beforehide
20995          * Fires before this menu is hidden
20996          * @param {Roo.bootstrap.menu.Menu} this
20997          */
20998         beforehide : true,
20999         /**
21000          * @event show
21001          * Fires after this menu is displayed
21002          * @param {Roo.bootstrap.menu.Menu} this
21003          */
21004         show : true,
21005         /**
21006          * @event hide
21007          * Fires after this menu is hidden
21008          * @param {Roo.bootstrap.menu.Menu} this
21009          */
21010         hide : true,
21011         /**
21012          * @event click
21013          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21014          * @param {Roo.bootstrap.menu.Menu} this
21015          * @param {Roo.EventObject} e
21016          */
21017         click : true
21018     });
21019     
21020 };
21021
21022 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21023     
21024     submenu : false,
21025     html : '',
21026     weight : 'default',
21027     icon : false,
21028     pos : 'bottom',
21029     
21030     
21031     getChildContainer : function() {
21032         if(this.isSubMenu){
21033             return this.el;
21034         }
21035         
21036         return this.el.select('ul.dropdown-menu', true).first();  
21037     },
21038     
21039     getAutoCreate : function()
21040     {
21041         var text = [
21042             {
21043                 tag : 'span',
21044                 cls : 'roo-menu-text',
21045                 html : this.html
21046             }
21047         ];
21048         
21049         if(this.icon){
21050             text.unshift({
21051                 tag : 'i',
21052                 cls : 'fa ' + this.icon
21053             })
21054         }
21055         
21056         
21057         var cfg = {
21058             tag : 'div',
21059             cls : 'btn-group',
21060             cn : [
21061                 {
21062                     tag : 'button',
21063                     cls : 'dropdown-button btn btn-' + this.weight,
21064                     cn : text
21065                 },
21066                 {
21067                     tag : 'button',
21068                     cls : 'dropdown-toggle btn btn-' + this.weight,
21069                     cn : [
21070                         {
21071                             tag : 'span',
21072                             cls : 'caret'
21073                         }
21074                     ]
21075                 },
21076                 {
21077                     tag : 'ul',
21078                     cls : 'dropdown-menu'
21079                 }
21080             ]
21081             
21082         };
21083         
21084         if(this.pos == 'top'){
21085             cfg.cls += ' dropup';
21086         }
21087         
21088         if(this.isSubMenu){
21089             cfg = {
21090                 tag : 'ul',
21091                 cls : 'dropdown-menu'
21092             }
21093         }
21094         
21095         return cfg;
21096     },
21097     
21098     onRender : function(ct, position)
21099     {
21100         this.isSubMenu = ct.hasClass('dropdown-submenu');
21101         
21102         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21103     },
21104     
21105     initEvents : function() 
21106     {
21107         if(this.isSubMenu){
21108             return;
21109         }
21110         
21111         this.hidden = true;
21112         
21113         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21114         this.triggerEl.on('click', this.onTriggerPress, this);
21115         
21116         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21117         this.buttonEl.on('click', this.onClick, this);
21118         
21119     },
21120     
21121     list : function()
21122     {
21123         if(this.isSubMenu){
21124             return this.el;
21125         }
21126         
21127         return this.el.select('ul.dropdown-menu', true).first();
21128     },
21129     
21130     onClick : function(e)
21131     {
21132         this.fireEvent("click", this, e);
21133     },
21134     
21135     onTriggerPress  : function(e)
21136     {   
21137         if (this.isVisible()) {
21138             this.hide();
21139         } else {
21140             this.show();
21141         }
21142     },
21143     
21144     isVisible : function(){
21145         return !this.hidden;
21146     },
21147     
21148     show : function()
21149     {
21150         this.fireEvent("beforeshow", this);
21151         
21152         this.hidden = false;
21153         this.el.addClass('open');
21154         
21155         Roo.get(document).on("mouseup", this.onMouseUp, this);
21156         
21157         this.fireEvent("show", this);
21158         
21159         
21160     },
21161     
21162     hide : function()
21163     {
21164         this.fireEvent("beforehide", this);
21165         
21166         this.hidden = true;
21167         this.el.removeClass('open');
21168         
21169         Roo.get(document).un("mouseup", this.onMouseUp);
21170         
21171         this.fireEvent("hide", this);
21172     },
21173     
21174     onMouseUp : function()
21175     {
21176         this.hide();
21177     }
21178     
21179 });
21180
21181  
21182  /*
21183  * - LGPL
21184  *
21185  * menu item
21186  * 
21187  */
21188 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21189
21190 /**
21191  * @class Roo.bootstrap.menu.Item
21192  * @extends Roo.bootstrap.Component
21193  * Bootstrap MenuItem class
21194  * @cfg {Boolean} submenu (true | false) default false
21195  * @cfg {String} html text of the item
21196  * @cfg {String} href the link
21197  * @cfg {Boolean} disable (true | false) default false
21198  * @cfg {Boolean} preventDefault (true | false) default true
21199  * @cfg {String} icon Font awesome icon
21200  * @cfg {String} pos Submenu align to (left | right) default right 
21201  * 
21202  * 
21203  * @constructor
21204  * Create a new Item
21205  * @param {Object} config The config object
21206  */
21207
21208
21209 Roo.bootstrap.menu.Item = function(config){
21210     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21211     this.addEvents({
21212         /**
21213          * @event mouseover
21214          * Fires when the mouse is hovering over this menu
21215          * @param {Roo.bootstrap.menu.Item} this
21216          * @param {Roo.EventObject} e
21217          */
21218         mouseover : true,
21219         /**
21220          * @event mouseout
21221          * Fires when the mouse exits this menu
21222          * @param {Roo.bootstrap.menu.Item} this
21223          * @param {Roo.EventObject} e
21224          */
21225         mouseout : true,
21226         // raw events
21227         /**
21228          * @event click
21229          * The raw click event for the entire grid.
21230          * @param {Roo.EventObject} e
21231          */
21232         click : true
21233     });
21234 };
21235
21236 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21237     
21238     submenu : false,
21239     href : '',
21240     html : '',
21241     preventDefault: true,
21242     disable : false,
21243     icon : false,
21244     pos : 'right',
21245     
21246     getAutoCreate : function()
21247     {
21248         var text = [
21249             {
21250                 tag : 'span',
21251                 cls : 'roo-menu-item-text',
21252                 html : this.html
21253             }
21254         ];
21255         
21256         if(this.icon){
21257             text.unshift({
21258                 tag : 'i',
21259                 cls : 'fa ' + this.icon
21260             })
21261         }
21262         
21263         var cfg = {
21264             tag : 'li',
21265             cn : [
21266                 {
21267                     tag : 'a',
21268                     href : this.href || '#',
21269                     cn : text
21270                 }
21271             ]
21272         };
21273         
21274         if(this.disable){
21275             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21276         }
21277         
21278         if(this.submenu){
21279             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21280             
21281             if(this.pos == 'left'){
21282                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21283             }
21284         }
21285         
21286         return cfg;
21287     },
21288     
21289     initEvents : function() 
21290     {
21291         this.el.on('mouseover', this.onMouseOver, this);
21292         this.el.on('mouseout', this.onMouseOut, this);
21293         
21294         this.el.select('a', true).first().on('click', this.onClick, this);
21295         
21296     },
21297     
21298     onClick : function(e)
21299     {
21300         if(this.preventDefault){
21301             e.preventDefault();
21302         }
21303         
21304         this.fireEvent("click", this, e);
21305     },
21306     
21307     onMouseOver : function(e)
21308     {
21309         if(this.submenu && this.pos == 'left'){
21310             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21311         }
21312         
21313         this.fireEvent("mouseover", this, e);
21314     },
21315     
21316     onMouseOut : function(e)
21317     {
21318         this.fireEvent("mouseout", this, e);
21319     }
21320 });
21321
21322  
21323
21324  /*
21325  * - LGPL
21326  *
21327  * menu separator
21328  * 
21329  */
21330 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21331
21332 /**
21333  * @class Roo.bootstrap.menu.Separator
21334  * @extends Roo.bootstrap.Component
21335  * Bootstrap Separator class
21336  * 
21337  * @constructor
21338  * Create a new Separator
21339  * @param {Object} config The config object
21340  */
21341
21342
21343 Roo.bootstrap.menu.Separator = function(config){
21344     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21345 };
21346
21347 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21348     
21349     getAutoCreate : function(){
21350         var cfg = {
21351             tag : 'li',
21352             cls: 'divider'
21353         };
21354         
21355         return cfg;
21356     }
21357    
21358 });
21359
21360  
21361
21362  /*
21363  * - LGPL
21364  *
21365  * Tooltip
21366  * 
21367  */
21368
21369 /**
21370  * @class Roo.bootstrap.Tooltip
21371  * Bootstrap Tooltip class
21372  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21373  * to determine which dom element triggers the tooltip.
21374  * 
21375  * It needs to add support for additional attributes like tooltip-position
21376  * 
21377  * @constructor
21378  * Create a new Toolti
21379  * @param {Object} config The config object
21380  */
21381
21382 Roo.bootstrap.Tooltip = function(config){
21383     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21384 };
21385
21386 Roo.apply(Roo.bootstrap.Tooltip, {
21387     /**
21388      * @function init initialize tooltip monitoring.
21389      * @static
21390      */
21391     currentEl : false,
21392     currentTip : false,
21393     currentRegion : false,
21394     
21395     //  init : delay?
21396     
21397     init : function()
21398     {
21399         Roo.get(document).on('mouseover', this.enter ,this);
21400         Roo.get(document).on('mouseout', this.leave, this);
21401          
21402         
21403         this.currentTip = new Roo.bootstrap.Tooltip();
21404     },
21405     
21406     enter : function(ev)
21407     {
21408         var dom = ev.getTarget();
21409         //Roo.log(['enter',dom]);
21410         var el = Roo.fly(dom);
21411         if (this.currentEl) {
21412             //Roo.log(dom);
21413             //Roo.log(this.currentEl);
21414             //Roo.log(this.currentEl.contains(dom));
21415             if (this.currentEl == el) {
21416                 return;
21417             }
21418             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21419                 return;
21420             }
21421
21422         }
21423         
21424         
21425         
21426         if (this.currentTip.el) {
21427             this.currentTip.el.hide(); // force hiding...
21428         }    
21429         //Roo.log(el);
21430         if (!el.attr('tooltip')) { // parents who have tip?
21431             return;
21432         }
21433         this.currentEl = el;
21434         this.currentTip.bind(el);
21435         this.currentRegion = Roo.lib.Region.getRegion(dom);
21436         this.currentTip.enter();
21437         
21438     },
21439     leave : function(ev)
21440     {
21441         var dom = ev.getTarget();
21442         //Roo.log(['leave',dom]);
21443         if (!this.currentEl) {
21444             return;
21445         }
21446         
21447         
21448         if (dom != this.currentEl.dom) {
21449             return;
21450         }
21451         var xy = ev.getXY();
21452         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21453             return;
21454         }
21455         // only activate leave if mouse cursor is outside... bounding box..
21456         
21457         
21458         
21459         
21460         if (this.currentTip) {
21461             this.currentTip.leave();
21462         }
21463         //Roo.log('clear currentEl');
21464         this.currentEl = false;
21465         
21466         
21467     },
21468     alignment : {
21469         'left' : ['r-l', [-2,0], 'right'],
21470         'right' : ['l-r', [2,0], 'left'],
21471         'bottom' : ['t-b', [0,2], 'top'],
21472         'top' : [ 'b-t', [0,-2], 'bottom']
21473     }
21474     
21475 });
21476
21477
21478 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21479     
21480     
21481     bindEl : false,
21482     
21483     delay : null, // can be { show : 300 , hide: 500}
21484     
21485     timeout : null,
21486     
21487     hoverState : null, //???
21488     
21489     placement : 'bottom', 
21490     
21491     getAutoCreate : function(){
21492     
21493         var cfg = {
21494            cls : 'tooltip',
21495            role : 'tooltip',
21496            cn : [
21497                 {
21498                     cls : 'tooltip-arrow'
21499                 },
21500                 {
21501                     cls : 'tooltip-inner'
21502                 }
21503            ]
21504         };
21505         
21506         return cfg;
21507     },
21508     bind : function(el)
21509     {
21510         this.bindEl = el;
21511     },
21512       
21513     
21514     enter : function () {
21515        
21516         if (this.timeout != null) {
21517             clearTimeout(this.timeout);
21518         }
21519         
21520         this.hoverState = 'in';
21521          //Roo.log("enter - show");
21522         if (!this.delay || !this.delay.show) {
21523             this.show();
21524             return;
21525         }
21526         var _t = this;
21527         this.timeout = setTimeout(function () {
21528             if (_t.hoverState == 'in') {
21529                 _t.show();
21530             }
21531         }, this.delay.show);
21532     },
21533     leave : function()
21534     {
21535         clearTimeout(this.timeout);
21536     
21537         this.hoverState = 'out';
21538          if (!this.delay || !this.delay.hide) {
21539             this.hide();
21540             return 
21541         }
21542        
21543         var _t = this;
21544         this.timeout = setTimeout(function () {
21545             //Roo.log("leave - timeout");
21546             
21547             if (_t.hoverState == 'out') {
21548                 _t.hide();
21549                 Roo.bootstrap.Tooltip.currentEl = false;
21550             }
21551         }, delay)
21552     },
21553     
21554     show : function ()
21555     {
21556         if (!this.el) {
21557             this.render(document.body);
21558         }
21559         // set content.
21560         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21561         this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21562         
21563         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21564         
21565         var placement = typeof this.placement == 'function' ?
21566             this.placement.call(this, this.el, on_el) :
21567             this.placement;
21568             
21569         var autoToken = /\s?auto?\s?/i;
21570         var autoPlace = autoToken.test(placement);
21571         if (autoPlace) {
21572             placement = placement.replace(autoToken, '') || 'top';
21573         }
21574         
21575         //this.el.detach()
21576         //this.el.setXY([0,0]);
21577         this.el.show();
21578         //this.el.dom.style.display='block';
21579         this.el.addClass(placement);
21580         
21581         //this.el.appendTo(on_el);
21582         
21583         var p = this.getPosition();
21584         var box = this.el.getBox();
21585         
21586         if (autoPlace) {
21587             // fixme..
21588         }
21589         var align = Roo.bootstrap.Tooltip.alignment[placement];
21590         this.el.alignTo(this.bindEl, align[0],align[1]);
21591         //var arrow = this.el.select('.arrow',true).first();
21592         //arrow.set(align[2], 
21593         
21594         this.el.addClass('in fade');
21595         this.hoverState = null;
21596         
21597         if (this.el.hasClass('fade')) {
21598             // fade it?
21599         }
21600         
21601     },
21602     hide : function()
21603     {
21604          
21605         if (!this.el) {
21606             return;
21607         }
21608         //this.el.setXY([0,0]);
21609         this.el.removeClass('in');
21610         //this.el.hide();
21611         
21612     }
21613     
21614 });
21615  
21616
21617  /*
21618  * - LGPL
21619  *
21620  * Location Picker
21621  * 
21622  */
21623
21624 /**
21625  * @class Roo.bootstrap.LocationPicker
21626  * @extends Roo.bootstrap.Component
21627  * Bootstrap LocationPicker class
21628  * @cfg {Number} latitude Position when init default 0
21629  * @cfg {Number} longitude Position when init default 0
21630  * @cfg {Number} zoom default 15
21631  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21632  * @cfg {Boolean} mapTypeControl default false
21633  * @cfg {Boolean} disableDoubleClickZoom default false
21634  * @cfg {Boolean} scrollwheel default true
21635  * @cfg {Boolean} streetViewControl default false
21636  * @cfg {Number} radius default 0
21637  * @cfg {String} locationName
21638  * @cfg {Boolean} draggable default true
21639  * @cfg {Boolean} enableAutocomplete default false
21640  * @cfg {Boolean} enableReverseGeocode default true
21641  * @cfg {String} markerTitle
21642  * 
21643  * @constructor
21644  * Create a new LocationPicker
21645  * @param {Object} config The config object
21646  */
21647
21648
21649 Roo.bootstrap.LocationPicker = function(config){
21650     
21651     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21652     
21653     this.addEvents({
21654         /**
21655          * @event initial
21656          * Fires when the picker initialized.
21657          * @param {Roo.bootstrap.LocationPicker} this
21658          * @param {Google Location} location
21659          */
21660         initial : true,
21661         /**
21662          * @event positionchanged
21663          * Fires when the picker position changed.
21664          * @param {Roo.bootstrap.LocationPicker} this
21665          * @param {Google Location} location
21666          */
21667         positionchanged : true,
21668         /**
21669          * @event resize
21670          * Fires when the map resize.
21671          * @param {Roo.bootstrap.LocationPicker} this
21672          */
21673         resize : true,
21674         /**
21675          * @event show
21676          * Fires when the map show.
21677          * @param {Roo.bootstrap.LocationPicker} this
21678          */
21679         show : true,
21680         /**
21681          * @event hide
21682          * Fires when the map hide.
21683          * @param {Roo.bootstrap.LocationPicker} this
21684          */
21685         hide : true,
21686         /**
21687          * @event mapClick
21688          * Fires when click the map.
21689          * @param {Roo.bootstrap.LocationPicker} this
21690          * @param {Map event} e
21691          */
21692         mapClick : true,
21693         /**
21694          * @event mapRightClick
21695          * Fires when right click the map.
21696          * @param {Roo.bootstrap.LocationPicker} this
21697          * @param {Map event} e
21698          */
21699         mapRightClick : true,
21700         /**
21701          * @event markerClick
21702          * Fires when click the marker.
21703          * @param {Roo.bootstrap.LocationPicker} this
21704          * @param {Map event} e
21705          */
21706         markerClick : true,
21707         /**
21708          * @event markerRightClick
21709          * Fires when right click the marker.
21710          * @param {Roo.bootstrap.LocationPicker} this
21711          * @param {Map event} e
21712          */
21713         markerRightClick : true,
21714         /**
21715          * @event OverlayViewDraw
21716          * Fires when OverlayView Draw
21717          * @param {Roo.bootstrap.LocationPicker} this
21718          */
21719         OverlayViewDraw : true,
21720         /**
21721          * @event OverlayViewOnAdd
21722          * Fires when OverlayView Draw
21723          * @param {Roo.bootstrap.LocationPicker} this
21724          */
21725         OverlayViewOnAdd : true,
21726         /**
21727          * @event OverlayViewOnRemove
21728          * Fires when OverlayView Draw
21729          * @param {Roo.bootstrap.LocationPicker} this
21730          */
21731         OverlayViewOnRemove : true,
21732         /**
21733          * @event OverlayViewShow
21734          * Fires when OverlayView Draw
21735          * @param {Roo.bootstrap.LocationPicker} this
21736          * @param {Pixel} cpx
21737          */
21738         OverlayViewShow : true,
21739         /**
21740          * @event OverlayViewHide
21741          * Fires when OverlayView Draw
21742          * @param {Roo.bootstrap.LocationPicker} this
21743          */
21744         OverlayViewHide : true
21745     });
21746         
21747 };
21748
21749 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
21750     
21751     gMapContext: false,
21752     
21753     latitude: 0,
21754     longitude: 0,
21755     zoom: 15,
21756     mapTypeId: false,
21757     mapTypeControl: false,
21758     disableDoubleClickZoom: false,
21759     scrollwheel: true,
21760     streetViewControl: false,
21761     radius: 0,
21762     locationName: '',
21763     draggable: true,
21764     enableAutocomplete: false,
21765     enableReverseGeocode: true,
21766     markerTitle: '',
21767     
21768     getAutoCreate: function()
21769     {
21770
21771         var cfg = {
21772             tag: 'div',
21773             cls: 'roo-location-picker'
21774         };
21775         
21776         return cfg
21777     },
21778     
21779     initEvents: function(ct, position)
21780     {       
21781         if(!this.el.getWidth() || this.isApplied()){
21782             return;
21783         }
21784         
21785         this.el.setVisibilityMode(Roo.Element.DISPLAY);
21786         
21787         this.initial();
21788     },
21789     
21790     initial: function()
21791     {
21792         if(!this.mapTypeId){
21793             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21794         }
21795         
21796         this.gMapContext = this.GMapContext();
21797         
21798         this.initOverlayView();
21799         
21800         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
21801         
21802         var _this = this;
21803                 
21804         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21805             _this.setPosition(_this.gMapContext.marker.position);
21806         });
21807         
21808         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
21809             Roo.log('mapClick');
21810             _this.fireEvent('mapClick', this, event);
21811             
21812         });
21813
21814         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
21815             Roo.log('mapRightClick');
21816             _this.fireEvent('mapRightClick', this, event);
21817             
21818         });
21819         
21820         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
21821             Roo.log('markerClick');
21822             _this.fireEvent('markerClick', this, event);
21823             
21824         });
21825
21826         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
21827             Roo.log('markerRightClick');
21828             _this.fireEvent('markerRightClick', this, event);
21829             
21830         });
21831         
21832         this.setPosition(this.gMapContext.location);
21833         
21834         this.fireEvent('initial', this, this.gMapContext.location);
21835     },
21836     
21837     initOverlayView: function()
21838     {
21839         var _this = this;
21840         
21841         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
21842             
21843             draw: function()
21844             {
21845                 Roo.log('OverlayView draw');
21846                 _this.fireEvent('OverlayViewDraw', _this);
21847             },
21848             
21849             onAdd: function()
21850             {
21851                 Roo.log('OverlayView onAdd');
21852                 _this.fireEvent('OverlayViewOnAdd', _this);
21853             },
21854             
21855             onRemove: function()
21856             {
21857                 Roo.log('OverlayView onRemove');
21858                 _this.fireEvent('OverlayViewOnRemove', _this);
21859             },
21860             
21861             show: function(cpx)
21862             {
21863                 Roo.log('OverlayView show');
21864                 _this.fireEvent('OverlayViewShow', _this, cpx);
21865             },
21866             
21867             hide: function()
21868             {
21869                 Roo.log('OverlayView hide');
21870                 _this.fireEvent('OverlayViewHide', _this);
21871             }
21872             
21873         });
21874     },
21875     
21876     fromLatLngToContainerPixel: function(event)
21877     {
21878         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
21879     },
21880     
21881     isApplied: function() 
21882     {
21883         return this.getGmapContext() == false ? false : true;
21884     },
21885     
21886     getGmapContext: function() 
21887     {
21888         return this.gMapContext
21889     },
21890     
21891     GMapContext: function() 
21892     {
21893         var _map = new google.maps.Map(this.el.dom, this);
21894         var _marker = new google.maps.Marker({
21895             position: new google.maps.LatLng(this.latitude, this.longitude),
21896             map: _map,
21897             title: this.markerTitle,
21898             draggable: this.draggable
21899         });
21900         
21901         return {
21902             map: _map,
21903             marker: _marker,
21904             circle: null,
21905             location: _marker.position,
21906             radius: this.radius,
21907             locationName: this.locationName,
21908             addressComponents: {
21909                 formatted_address: null,
21910                 addressLine1: null,
21911                 addressLine2: null,
21912                 streetName: null,
21913                 streetNumber: null,
21914                 city: null,
21915                 district: null,
21916                 state: null,
21917                 stateOrProvince: null
21918             },
21919             settings: this,
21920             domContainer: this.el.dom,
21921             geodecoder: new google.maps.Geocoder()
21922         };
21923     },
21924     
21925     drawCircle: function(center, radius, options) 
21926     {
21927         if (this.gMapContext.circle != null) {
21928             this.gMapContext.circle.setMap(null);
21929         }
21930         if (radius > 0) {
21931             radius *= 1;
21932             options = Roo.apply({}, options, {
21933                 strokeColor: "#0000FF",
21934                 strokeOpacity: .35,
21935                 strokeWeight: 2,
21936                 fillColor: "#0000FF",
21937                 fillOpacity: .2
21938             });
21939             
21940             options.map = this.gMapContext.map;
21941             options.radius = radius;
21942             options.center = center;
21943             this.gMapContext.circle = new google.maps.Circle(options);
21944             return this.gMapContext.circle;
21945         }
21946         
21947         return null;
21948     },
21949     
21950     setPosition: function(location) 
21951     {
21952         this.gMapContext.location = location;
21953         this.gMapContext.marker.setPosition(location);
21954         this.gMapContext.map.panTo(location);
21955         this.drawCircle(location, this.gMapContext.radius, {});
21956         
21957         var _this = this;
21958         
21959         if (this.gMapContext.settings.enableReverseGeocode) {
21960             this.gMapContext.geodecoder.geocode({
21961                 latLng: this.gMapContext.location
21962             }, function(results, status) {
21963                 
21964                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21965                     _this.gMapContext.locationName = results[0].formatted_address;
21966                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21967                     
21968                     _this.fireEvent('positionchanged', this, location);
21969                 }
21970             });
21971             
21972             return;
21973         }
21974         
21975         this.fireEvent('positionchanged', this, location);
21976     },
21977     
21978     resize: function()
21979     {
21980         google.maps.event.trigger(this.gMapContext.map, "resize");
21981         
21982         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21983         
21984         this.fireEvent('resize', this);
21985     },
21986     
21987     setPositionByLatLng: function(latitude, longitude)
21988     {
21989         this.setPosition(new google.maps.LatLng(latitude, longitude));
21990     },
21991     
21992     getCurrentPosition: function() 
21993     {
21994         return {
21995             latitude: this.gMapContext.location.lat(),
21996             longitude: this.gMapContext.location.lng()
21997         };
21998     },
21999     
22000     getAddressName: function() 
22001     {
22002         return this.gMapContext.locationName;
22003     },
22004     
22005     getAddressComponents: function() 
22006     {
22007         return this.gMapContext.addressComponents;
22008     },
22009     
22010     address_component_from_google_geocode: function(address_components) 
22011     {
22012         var result = {};
22013         
22014         for (var i = 0; i < address_components.length; i++) {
22015             var component = address_components[i];
22016             if (component.types.indexOf("postal_code") >= 0) {
22017                 result.postalCode = component.short_name;
22018             } else if (component.types.indexOf("street_number") >= 0) {
22019                 result.streetNumber = component.short_name;
22020             } else if (component.types.indexOf("route") >= 0) {
22021                 result.streetName = component.short_name;
22022             } else if (component.types.indexOf("neighborhood") >= 0) {
22023                 result.city = component.short_name;
22024             } else if (component.types.indexOf("locality") >= 0) {
22025                 result.city = component.short_name;
22026             } else if (component.types.indexOf("sublocality") >= 0) {
22027                 result.district = component.short_name;
22028             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22029                 result.stateOrProvince = component.short_name;
22030             } else if (component.types.indexOf("country") >= 0) {
22031                 result.country = component.short_name;
22032             }
22033         }
22034         
22035         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22036         result.addressLine2 = "";
22037         return result;
22038     },
22039     
22040     setZoomLevel: function(zoom)
22041     {
22042         this.gMapContext.map.setZoom(zoom);
22043     },
22044     
22045     show: function()
22046     {
22047         if(!this.el){
22048             return;
22049         }
22050         
22051         this.el.show();
22052         
22053         this.resize();
22054         
22055         this.fireEvent('show', this);
22056     },
22057     
22058     hide: function()
22059     {
22060         if(!this.el){
22061             return;
22062         }
22063         
22064         this.el.hide();
22065         
22066         this.fireEvent('hide', this);
22067     }
22068     
22069 });
22070
22071 Roo.apply(Roo.bootstrap.LocationPicker, {
22072     
22073     OverlayView : function(map, options)
22074     {
22075         options = options || {};
22076         
22077         this.setMap(map);
22078     }
22079     
22080     
22081 });/*
22082  * - LGPL
22083  *
22084  * Alert
22085  * 
22086  */
22087
22088 /**
22089  * @class Roo.bootstrap.Alert
22090  * @extends Roo.bootstrap.Component
22091  * Bootstrap Alert class
22092  * @cfg {String} title The title of alert
22093  * @cfg {String} html The content of alert
22094  * @cfg {String} weight (  success | info | warning | danger )
22095  * @cfg {String} faicon font-awesomeicon
22096  * 
22097  * @constructor
22098  * Create a new alert
22099  * @param {Object} config The config object
22100  */
22101
22102
22103 Roo.bootstrap.Alert = function(config){
22104     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22105     
22106 };
22107
22108 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22109     
22110     title: '',
22111     html: '',
22112     weight: false,
22113     faicon: false,
22114     
22115     getAutoCreate : function()
22116     {
22117         
22118         var cfg = {
22119             tag : 'div',
22120             cls : 'alert',
22121             cn : [
22122                 {
22123                     tag : 'i',
22124                     cls : 'roo-alert-icon'
22125                     
22126                 },
22127                 {
22128                     tag : 'b',
22129                     cls : 'roo-alert-title',
22130                     html : this.title
22131                 },
22132                 {
22133                     tag : 'span',
22134                     cls : 'roo-alert-text',
22135                     html : this.html
22136                 }
22137             ]
22138         };
22139         
22140         if(this.faicon){
22141             cfg.cn[0].cls += ' fa ' + this.faicon;
22142         }
22143         
22144         if(this.weight){
22145             cfg.cls += ' alert-' + this.weight;
22146         }
22147         
22148         return cfg;
22149     },
22150     
22151     initEvents: function() 
22152     {
22153         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22154     },
22155     
22156     setTitle : function(str)
22157     {
22158         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22159     },
22160     
22161     setText : function(str)
22162     {
22163         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22164     },
22165     
22166     setWeight : function(weight)
22167     {
22168         if(this.weight){
22169             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22170         }
22171         
22172         this.weight = weight;
22173         
22174         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22175     },
22176     
22177     setIcon : function(icon)
22178     {
22179         if(this.faicon){
22180             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22181         }
22182         
22183         this.faicon = icon
22184         
22185         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22186     },
22187     
22188     hide: function() 
22189     {
22190         this.el.hide();   
22191     },
22192     
22193     show: function() 
22194     {  
22195         this.el.show();   
22196     }
22197     
22198 });
22199
22200