fix
[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 * Licence: LGPL
2055 */
2056
2057 /**
2058  * @class Roo.bootstrap.Modal
2059  * @extends Roo.bootstrap.Component
2060  * Bootstrap Modal class
2061  * @cfg {String} title Title of dialog
2062  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2063  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn 
2064  * @cfg {Boolean} specificTitle default false
2065  * @cfg {Array} buttons Array of buttons or standard button set..
2066  * @cfg {String} buttonPosition (left|right|center) default right
2067  * @cfg {Boolean} animate default true
2068  * @cfg {Boolean} allow_close default true
2069  * 
2070  * @constructor
2071  * Create a new Modal Dialog
2072  * @param {Object} config The config object
2073  */
2074
2075 Roo.bootstrap.Modal = function(config){
2076     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2077     this.addEvents({
2078         // raw events
2079         /**
2080          * @event btnclick
2081          * The raw btnclick event for the button
2082          * @param {Roo.EventObject} e
2083          */
2084         "btnclick" : true
2085     });
2086     this.buttons = this.buttons || [];
2087      
2088     if (this.tmpl) {
2089         this.tmpl = Roo.factory(this.tmpl);
2090     }
2091     
2092 };
2093
2094 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2095     
2096     title : 'test dialog',
2097    
2098     buttons : false,
2099     
2100     // set on load...
2101      
2102     html: false,
2103     
2104     tmp: false,
2105     
2106     specificTitle: false,
2107     
2108     buttonPosition: 'right',
2109     
2110     allow_close : true,
2111     
2112     animate : true,
2113     
2114     
2115      // private
2116     bodyEl:  false,
2117     footerEl:  false,
2118     titleEl:  false,
2119     closeEl:  false,
2120     
2121     
2122     onRender : function(ct, position)
2123     {
2124         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2125      
2126         if(!this.el){
2127             var cfg = Roo.apply({},  this.getAutoCreate());
2128             cfg.id = Roo.id();
2129             //if(!cfg.name){
2130             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2131             //}
2132             //if (!cfg.name.length) {
2133             //    delete cfg.name;
2134            // }
2135             if (this.cls) {
2136                 cfg.cls += ' ' + this.cls;
2137             }
2138             if (this.style) {
2139                 cfg.style = this.style;
2140             }
2141             this.el = Roo.get(document.body).createChild(cfg, position);
2142         }
2143         //var type = this.el.dom.type;
2144         
2145         if(this.tabIndex !== undefined){
2146             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2147         }
2148         
2149         
2150         
2151         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2152         this.maskEl.enableDisplayMode("block");
2153         this.maskEl.hide();
2154         //this.el.addClass("x-dlg-modal");
2155     
2156         if (this.buttons.length) {
2157             Roo.each(this.buttons, function(bb) {
2158                 b = Roo.apply({}, bb);
2159                 b.xns = b.xns || Roo.bootstrap;
2160                 b.xtype = b.xtype || 'Button';
2161                 if (typeof(b.listeners) == 'undefined') {
2162                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2163                 }
2164                 
2165                 var btn = Roo.factory(b);
2166                 
2167                 btn.onRender(this.el.select('.modal-footer div').first());
2168                 
2169             },this);
2170         }
2171         // render the children.
2172         var nitems = [];
2173         
2174         if(typeof(this.items) != 'undefined'){
2175             var items = this.items;
2176             delete this.items;
2177
2178             for(var i =0;i < items.length;i++) {
2179                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2180             }
2181         }
2182         
2183         this.items = nitems;
2184         
2185         // where are these used - they used to be body/close/footer
2186         
2187         this.bodyEl = this.el.select('.modal-body',true).first();
2188         this.closeEl = this.el.select('.modal-header .close', true).first();
2189         this.footerEl = this.el.select('.modal-footer',true).first();
2190         this.titleEl = this.el.select('.modal-title',true).first();
2191         
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.bodyEl;
2271         
2272     },
2273     getButtonContainer : function() {
2274          return this.el.select('.modal-footer div',true).first();
2275         
2276     },
2277     initEvents : function()
2278     {
2279         if (this.allow_close) {
2280             this.closeEl.on('click', this.hide, this);
2281         }
2282
2283     },
2284     show : function() {
2285         
2286         if (!this.rendered) {
2287             this.render();
2288         }
2289         
2290         this.el.setStyle('display', 'block');
2291         
2292         if(this.animate){
2293             var _this = this;
2294             (function(){ _this.el.addClass('in'); }).defer(50);
2295         }else{
2296             this.el.addClass('in');
2297         }
2298         
2299         // not sure how we can show data in here.. 
2300         //if (this.tmpl) {
2301         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2302         //}
2303         
2304         Roo.get(document.body).addClass("x-body-masked");
2305         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2306         this.maskEl.show();
2307         this.el.setStyle('zIndex', '10001');
2308        
2309         this.fireEvent('show', this);
2310         
2311         
2312     },
2313     hide : function()
2314     {
2315         this.maskEl.hide();
2316         Roo.get(document.body).removeClass("x-body-masked");
2317         this.el.removeClass('in');
2318         
2319         if(this.animate){
2320             var _this = this;
2321             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2322         }else{
2323             this.el.setStyle('display', 'none');
2324         }
2325         
2326         this.fireEvent('hide', this);
2327     },
2328     
2329     addButton : function(str, cb)
2330     {
2331          
2332         
2333         var b = Roo.apply({}, { html : str } );
2334         b.xns = b.xns || Roo.bootstrap;
2335         b.xtype = b.xtype || 'Button';
2336         if (typeof(b.listeners) == 'undefined') {
2337             b.listeners = { click : cb.createDelegate(this)  };
2338         }
2339         
2340         var btn = Roo.factory(b);
2341            
2342         btn.onRender(this.el.select('.modal-footer div').first());
2343         
2344         return btn;   
2345        
2346     },
2347     
2348     setDefaultButton : function(btn)
2349     {
2350         //this.el.select('.modal-footer').()
2351     },
2352     resizeTo: function(w,h)
2353     {
2354         // skip..
2355     },
2356     setContentSize  : function(w, h)
2357     {
2358         
2359     },
2360     onButtonClick: function(btn,e)
2361     {
2362         //Roo.log([a,b,c]);
2363         this.fireEvent('btnclick', btn.name, e);
2364     },
2365      /**
2366      * Set the title of the Dialog
2367      * @param {String} str new Title
2368      */
2369     setTitle: function(str) {
2370         this.titleEl.dom.innerHTML = str;    
2371     },
2372     /**
2373      * Set the body of the Dialog
2374      * @param {String} str new Title
2375      */
2376     setBody: function(str) {
2377         this.bodyEl.dom.innerHTML = str;    
2378     },
2379     /**
2380      * Set the body of the Dialog using the template
2381      * @param {Obj} data - apply this data to the template and replace the body contents.
2382      */
2383     applyBody: function(obj)
2384     {
2385         if (!this.tmpl) {
2386             Roo.log("Error - using apply Body without a template");
2387             //code
2388         }
2389         this.tmpl.overwrite(this.bodyEl, obj);
2390     }
2391     
2392 });
2393
2394
2395 Roo.apply(Roo.bootstrap.Modal,  {
2396     /**
2397          * Button config that displays a single OK button
2398          * @type Object
2399          */
2400         OK :  [{
2401             name : 'ok',
2402             weight : 'primary',
2403             html : 'OK'
2404         }], 
2405         /**
2406          * Button config that displays Yes and No buttons
2407          * @type Object
2408          */
2409         YESNO : [
2410             {
2411                 name  : 'no',
2412                 html : 'No'
2413             },
2414             {
2415                 name  :'yes',
2416                 weight : 'primary',
2417                 html : 'Yes'
2418             }
2419         ],
2420         
2421         /**
2422          * Button config that displays OK and Cancel buttons
2423          * @type Object
2424          */
2425         OKCANCEL : [
2426             {
2427                name : 'cancel',
2428                 html : 'Cancel'
2429             },
2430             {
2431                 name : 'ok',
2432                 weight : 'primary',
2433                 html : 'OK'
2434             }
2435         ],
2436         /**
2437          * Button config that displays Yes, No and Cancel buttons
2438          * @type Object
2439          */
2440         YESNOCANCEL : [
2441             {
2442                 name : 'yes',
2443                 weight : 'primary',
2444                 html : 'Yes'
2445             },
2446             {
2447                 name : 'no',
2448                 html : 'No'
2449             },
2450             {
2451                 name : 'cancel',
2452                 html : 'Cancel'
2453             }
2454         ]
2455 });
2456  
2457  /*
2458  * - LGPL
2459  *
2460  * messagebox - can be used as a replace
2461  * 
2462  */
2463 /**
2464  * @class Roo.MessageBox
2465  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2466  * Example usage:
2467  *<pre><code>
2468 // Basic alert:
2469 Roo.Msg.alert('Status', 'Changes saved successfully.');
2470
2471 // Prompt for user data:
2472 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2473     if (btn == 'ok'){
2474         // process text value...
2475     }
2476 });
2477
2478 // Show a dialog using config options:
2479 Roo.Msg.show({
2480    title:'Save Changes?',
2481    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2482    buttons: Roo.Msg.YESNOCANCEL,
2483    fn: processResult,
2484    animEl: 'elId'
2485 });
2486 </code></pre>
2487  * @singleton
2488  */
2489 Roo.bootstrap.MessageBox = function(){
2490     var dlg, opt, mask, waitTimer;
2491     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2492     var buttons, activeTextEl, bwidth;
2493
2494     
2495     // private
2496     var handleButton = function(button){
2497         dlg.hide();
2498         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2499     };
2500
2501     // private
2502     var handleHide = function(){
2503         if(opt && opt.cls){
2504             dlg.el.removeClass(opt.cls);
2505         }
2506         //if(waitTimer){
2507         //    Roo.TaskMgr.stop(waitTimer);
2508         //    waitTimer = null;
2509         //}
2510     };
2511
2512     // private
2513     var updateButtons = function(b){
2514         var width = 0;
2515         if(!b){
2516             buttons["ok"].hide();
2517             buttons["cancel"].hide();
2518             buttons["yes"].hide();
2519             buttons["no"].hide();
2520             //dlg.footer.dom.style.display = 'none';
2521             return width;
2522         }
2523         dlg.footerEl.dom.style.display = '';
2524         for(var k in buttons){
2525             if(typeof buttons[k] != "function"){
2526                 if(b[k]){
2527                     buttons[k].show();
2528                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2529                     width += buttons[k].el.getWidth()+15;
2530                 }else{
2531                     buttons[k].hide();
2532                 }
2533             }
2534         }
2535         return width;
2536     };
2537
2538     // private
2539     var handleEsc = function(d, k, e){
2540         if(opt && opt.closable !== false){
2541             dlg.hide();
2542         }
2543         if(e){
2544             e.stopEvent();
2545         }
2546     };
2547
2548     return {
2549         /**
2550          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2551          * @return {Roo.BasicDialog} The BasicDialog element
2552          */
2553         getDialog : function(){
2554            if(!dlg){
2555                 dlg = new Roo.bootstrap.Modal( {
2556                     //draggable: true,
2557                     //resizable:false,
2558                     //constraintoviewport:false,
2559                     //fixedcenter:true,
2560                     //collapsible : false,
2561                     //shim:true,
2562                     //modal: true,
2563                   //  width:400,
2564                   //  height:100,
2565                     //buttonAlign:"center",
2566                     closeClick : function(){
2567                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2568                             handleButton("no");
2569                         }else{
2570                             handleButton("cancel");
2571                         }
2572                     }
2573                 });
2574                 dlg.render();
2575                 dlg.on("hide", handleHide);
2576                 mask = dlg.mask;
2577                 //dlg.addKeyListener(27, handleEsc);
2578                 buttons = {};
2579                 this.buttons = buttons;
2580                 var bt = this.buttonText;
2581                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2582                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2583                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2584                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2585                 Roo.log(buttons)
2586                 bodyEl = dlg.bodyEl.createChild({
2587
2588                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2589                         '<textarea class="roo-mb-textarea"></textarea>' +
2590                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2591                 });
2592                 msgEl = bodyEl.dom.firstChild;
2593                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2594                 textboxEl.enableDisplayMode();
2595                 textboxEl.addKeyListener([10,13], function(){
2596                     if(dlg.isVisible() && opt && opt.buttons){
2597                         if(opt.buttons.ok){
2598                             handleButton("ok");
2599                         }else if(opt.buttons.yes){
2600                             handleButton("yes");
2601                         }
2602                     }
2603                 });
2604                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2605                 textareaEl.enableDisplayMode();
2606                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2607                 progressEl.enableDisplayMode();
2608                 var pf = progressEl.dom.firstChild;
2609                 if (pf) {
2610                     pp = Roo.get(pf.firstChild);
2611                     pp.setHeight(pf.offsetHeight);
2612                 }
2613                 
2614             }
2615             return dlg;
2616         },
2617
2618         /**
2619          * Updates the message box body text
2620          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2621          * the XHTML-compliant non-breaking space character '&amp;#160;')
2622          * @return {Roo.MessageBox} This message box
2623          */
2624         updateText : function(text){
2625             if(!dlg.isVisible() && !opt.width){
2626                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2627             }
2628             msgEl.innerHTML = text || '&#160;';
2629       
2630             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2631             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2632             var w = Math.max(
2633                     Math.min(opt.width || cw , this.maxWidth), 
2634                     Math.max(opt.minWidth || this.minWidth, bwidth)
2635             );
2636             if(opt.prompt){
2637                 activeTextEl.setWidth(w);
2638             }
2639             if(dlg.isVisible()){
2640                 dlg.fixedcenter = false;
2641             }
2642             // to big, make it scroll. = But as usual stupid IE does not support
2643             // !important..
2644             
2645             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2646                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2647                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2648             } else {
2649                 bodyEl.dom.style.height = '';
2650                 bodyEl.dom.style.overflowY = '';
2651             }
2652             if (cw > w) {
2653                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2654             } else {
2655                 bodyEl.dom.style.overflowX = '';
2656             }
2657             
2658             dlg.setContentSize(w, bodyEl.getHeight());
2659             if(dlg.isVisible()){
2660                 dlg.fixedcenter = true;
2661             }
2662             return this;
2663         },
2664
2665         /**
2666          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2667          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2668          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2669          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2670          * @return {Roo.MessageBox} This message box
2671          */
2672         updateProgress : function(value, text){
2673             if(text){
2674                 this.updateText(text);
2675             }
2676             if (pp) { // weird bug on my firefox - for some reason this is not defined
2677                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2678             }
2679             return this;
2680         },        
2681
2682         /**
2683          * Returns true if the message box is currently displayed
2684          * @return {Boolean} True if the message box is visible, else false
2685          */
2686         isVisible : function(){
2687             return dlg && dlg.isVisible();  
2688         },
2689
2690         /**
2691          * Hides the message box if it is displayed
2692          */
2693         hide : function(){
2694             if(this.isVisible()){
2695                 dlg.hide();
2696             }  
2697         },
2698
2699         /**
2700          * Displays a new message box, or reinitializes an existing message box, based on the config options
2701          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2702          * The following config object properties are supported:
2703          * <pre>
2704 Property    Type             Description
2705 ----------  ---------------  ------------------------------------------------------------------------------------
2706 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2707                                    closes (defaults to undefined)
2708 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2709                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2710 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2711                                    progress and wait dialogs will ignore this property and always hide the
2712                                    close button as they can only be closed programmatically.
2713 cls               String           A custom CSS class to apply to the message box element
2714 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2715                                    displayed (defaults to 75)
2716 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2717                                    function will be btn (the name of the button that was clicked, if applicable,
2718                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2719                                    Progress and wait dialogs will ignore this option since they do not respond to
2720                                    user actions and can only be closed programmatically, so any required function
2721                                    should be called by the same code after it closes the dialog.
2722 icon              String           A CSS class that provides a background image to be used as an icon for
2723                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2724 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2725 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2726 modal             Boolean          False to allow user interaction with the page while the message box is
2727                                    displayed (defaults to true)
2728 msg               String           A string that will replace the existing message box body text (defaults
2729                                    to the XHTML-compliant non-breaking space character '&#160;')
2730 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2731 progress          Boolean          True to display a progress bar (defaults to false)
2732 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2733 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2734 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2735 title             String           The title text
2736 value             String           The string value to set into the active textbox element if displayed
2737 wait              Boolean          True to display a progress bar (defaults to false)
2738 width             Number           The width of the dialog in pixels
2739 </pre>
2740          *
2741          * Example usage:
2742          * <pre><code>
2743 Roo.Msg.show({
2744    title: 'Address',
2745    msg: 'Please enter your address:',
2746    width: 300,
2747    buttons: Roo.MessageBox.OKCANCEL,
2748    multiline: true,
2749    fn: saveAddress,
2750    animEl: 'addAddressBtn'
2751 });
2752 </code></pre>
2753          * @param {Object} config Configuration options
2754          * @return {Roo.MessageBox} This message box
2755          */
2756         show : function(options)
2757         {
2758             
2759             // this causes nightmares if you show one dialog after another
2760             // especially on callbacks..
2761              
2762             if(this.isVisible()){
2763                 
2764                 this.hide();
2765                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2766                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2767                 Roo.log("New Dialog Message:" +  options.msg )
2768                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2769                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2770                 
2771             }
2772             var d = this.getDialog();
2773             opt = options;
2774             d.setTitle(opt.title || "&#160;");
2775             d.closeEl.setDisplayed(opt.closable !== false);
2776             activeTextEl = textboxEl;
2777             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2778             if(opt.prompt){
2779                 if(opt.multiline){
2780                     textboxEl.hide();
2781                     textareaEl.show();
2782                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2783                         opt.multiline : this.defaultTextHeight);
2784                     activeTextEl = textareaEl;
2785                 }else{
2786                     textboxEl.show();
2787                     textareaEl.hide();
2788                 }
2789             }else{
2790                 textboxEl.hide();
2791                 textareaEl.hide();
2792             }
2793             progressEl.setDisplayed(opt.progress === true);
2794             this.updateProgress(0);
2795             activeTextEl.dom.value = opt.value || "";
2796             if(opt.prompt){
2797                 dlg.setDefaultButton(activeTextEl);
2798             }else{
2799                 var bs = opt.buttons;
2800                 var db = null;
2801                 if(bs && bs.ok){
2802                     db = buttons["ok"];
2803                 }else if(bs && bs.yes){
2804                     db = buttons["yes"];
2805                 }
2806                 dlg.setDefaultButton(db);
2807             }
2808             bwidth = updateButtons(opt.buttons);
2809             this.updateText(opt.msg);
2810             if(opt.cls){
2811                 d.el.addClass(opt.cls);
2812             }
2813             d.proxyDrag = opt.proxyDrag === true;
2814             d.modal = opt.modal !== false;
2815             d.mask = opt.modal !== false ? mask : false;
2816             if(!d.isVisible()){
2817                 // force it to the end of the z-index stack so it gets a cursor in FF
2818                 document.body.appendChild(dlg.el.dom);
2819                 d.animateTarget = null;
2820                 d.show(options.animEl);
2821             }
2822             return this;
2823         },
2824
2825         /**
2826          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2827          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2828          * and closing the message box when the process is complete.
2829          * @param {String} title The title bar text
2830          * @param {String} msg The message box body text
2831          * @return {Roo.MessageBox} This message box
2832          */
2833         progress : function(title, msg){
2834             this.show({
2835                 title : title,
2836                 msg : msg,
2837                 buttons: false,
2838                 progress:true,
2839                 closable:false,
2840                 minWidth: this.minProgressWidth,
2841                 modal : true
2842             });
2843             return this;
2844         },
2845
2846         /**
2847          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2848          * If a callback function is passed it will be called after the user clicks the button, and the
2849          * id of the button that was clicked will be passed as the only parameter to the callback
2850          * (could also be the top-right close button).
2851          * @param {String} title The title bar text
2852          * @param {String} msg The message box body text
2853          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2854          * @param {Object} scope (optional) The scope of the callback function
2855          * @return {Roo.MessageBox} This message box
2856          */
2857         alert : function(title, msg, fn, scope){
2858             this.show({
2859                 title : title,
2860                 msg : msg,
2861                 buttons: this.OK,
2862                 fn: fn,
2863                 scope : scope,
2864                 modal : true
2865             });
2866             return this;
2867         },
2868
2869         /**
2870          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2871          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2872          * You are responsible for closing the message box when the process is complete.
2873          * @param {String} msg The message box body text
2874          * @param {String} title (optional) The title bar text
2875          * @return {Roo.MessageBox} This message box
2876          */
2877         wait : function(msg, title){
2878             this.show({
2879                 title : title,
2880                 msg : msg,
2881                 buttons: false,
2882                 closable:false,
2883                 progress:true,
2884                 modal:true,
2885                 width:300,
2886                 wait:true
2887             });
2888             waitTimer = Roo.TaskMgr.start({
2889                 run: function(i){
2890                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2891                 },
2892                 interval: 1000
2893             });
2894             return this;
2895         },
2896
2897         /**
2898          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2899          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2900          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2901          * @param {String} title The title bar text
2902          * @param {String} msg The message box body text
2903          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2904          * @param {Object} scope (optional) The scope of the callback function
2905          * @return {Roo.MessageBox} This message box
2906          */
2907         confirm : function(title, msg, fn, scope){
2908             this.show({
2909                 title : title,
2910                 msg : msg,
2911                 buttons: this.YESNO,
2912                 fn: fn,
2913                 scope : scope,
2914                 modal : true
2915             });
2916             return this;
2917         },
2918
2919         /**
2920          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2921          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2922          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2923          * (could also be the top-right close button) and the text that was entered will be passed as the two
2924          * parameters to the callback.
2925          * @param {String} title The title bar text
2926          * @param {String} msg The message box body text
2927          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2928          * @param {Object} scope (optional) The scope of the callback function
2929          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2930          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2931          * @return {Roo.MessageBox} This message box
2932          */
2933         prompt : function(title, msg, fn, scope, multiline){
2934             this.show({
2935                 title : title,
2936                 msg : msg,
2937                 buttons: this.OKCANCEL,
2938                 fn: fn,
2939                 minWidth:250,
2940                 scope : scope,
2941                 prompt:true,
2942                 multiline: multiline,
2943                 modal : true
2944             });
2945             return this;
2946         },
2947
2948         /**
2949          * Button config that displays a single OK button
2950          * @type Object
2951          */
2952         OK : {ok:true},
2953         /**
2954          * Button config that displays Yes and No buttons
2955          * @type Object
2956          */
2957         YESNO : {yes:true, no:true},
2958         /**
2959          * Button config that displays OK and Cancel buttons
2960          * @type Object
2961          */
2962         OKCANCEL : {ok:true, cancel:true},
2963         /**
2964          * Button config that displays Yes, No and Cancel buttons
2965          * @type Object
2966          */
2967         YESNOCANCEL : {yes:true, no:true, cancel:true},
2968
2969         /**
2970          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2971          * @type Number
2972          */
2973         defaultTextHeight : 75,
2974         /**
2975          * The maximum width in pixels of the message box (defaults to 600)
2976          * @type Number
2977          */
2978         maxWidth : 600,
2979         /**
2980          * The minimum width in pixels of the message box (defaults to 100)
2981          * @type Number
2982          */
2983         minWidth : 100,
2984         /**
2985          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
2986          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2987          * @type Number
2988          */
2989         minProgressWidth : 250,
2990         /**
2991          * An object containing the default button text strings that can be overriden for localized language support.
2992          * Supported properties are: ok, cancel, yes and no.
2993          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2994          * @type Object
2995          */
2996         buttonText : {
2997             ok : "OK",
2998             cancel : "Cancel",
2999             yes : "Yes",
3000             no : "No"
3001         }
3002     };
3003 }();
3004
3005 /**
3006  * Shorthand for {@link Roo.MessageBox}
3007  */
3008 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3009 Roo.Msg = Roo.Msg || Roo.MessageBox;
3010 /*
3011  * - LGPL
3012  *
3013  * navbar
3014  * 
3015  */
3016
3017 /**
3018  * @class Roo.bootstrap.Navbar
3019  * @extends Roo.bootstrap.Component
3020  * Bootstrap Navbar class
3021
3022  * @constructor
3023  * Create a new Navbar
3024  * @param {Object} config The config object
3025  */
3026
3027
3028 Roo.bootstrap.Navbar = function(config){
3029     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3030     
3031 };
3032
3033 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3034     
3035     
3036    
3037     // private
3038     navItems : false,
3039     loadMask : false,
3040     
3041     
3042     getAutoCreate : function(){
3043         
3044         
3045         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3046         
3047     },
3048     
3049     initEvents :function ()
3050     {
3051         //Roo.log(this.el.select('.navbar-toggle',true));
3052         this.el.select('.navbar-toggle',true).on('click', function() {
3053            // Roo.log('click');
3054             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3055         }, this);
3056         
3057         var mark = {
3058             tag: "div",
3059             cls:"x-dlg-mask"
3060         }
3061         
3062         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3063         
3064         var size = this.el.getSize();
3065         this.maskEl.setSize(size.width, size.height);
3066         this.maskEl.enableDisplayMode("block");
3067         this.maskEl.hide();
3068         
3069         if(this.loadMask){
3070             this.maskEl.show();
3071         }
3072     },
3073     
3074     
3075     getChildContainer : function()
3076     {
3077         if (this.el.select('.collapse').getCount()) {
3078             return this.el.select('.collapse',true).first();
3079         }
3080         
3081         return this.el;
3082     },
3083     
3084     mask : function()
3085     {
3086         this.maskEl.show();
3087     },
3088     
3089     unmask : function()
3090     {
3091         this.maskEl.hide();
3092     } 
3093     
3094     
3095     
3096     
3097 });
3098
3099
3100
3101  
3102
3103  /*
3104  * - LGPL
3105  *
3106  * navbar
3107  * 
3108  */
3109
3110 /**
3111  * @class Roo.bootstrap.NavSimplebar
3112  * @extends Roo.bootstrap.Navbar
3113  * Bootstrap Sidebar class
3114  *
3115  * @cfg {Boolean} inverse is inverted color
3116  * 
3117  * @cfg {String} type (nav | pills | tabs)
3118  * @cfg {Boolean} arrangement stacked | justified
3119  * @cfg {String} align (left | right) alignment
3120  * 
3121  * @cfg {Boolean} main (true|false) main nav bar? default false
3122  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3123  * 
3124  * @cfg {String} tag (header|footer|nav|div) default is nav 
3125
3126  * 
3127  * 
3128  * 
3129  * @constructor
3130  * Create a new Sidebar
3131  * @param {Object} config The config object
3132  */
3133
3134
3135 Roo.bootstrap.NavSimplebar = function(config){
3136     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3137 };
3138
3139 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3140     
3141     inverse: false,
3142     
3143     type: false,
3144     arrangement: '',
3145     align : false,
3146     
3147     
3148     
3149     main : false,
3150     
3151     
3152     tag : false,
3153     
3154     
3155     getAutoCreate : function(){
3156         
3157         
3158         var cfg = {
3159             tag : this.tag || 'div',
3160             cls : 'navbar'
3161         };
3162           
3163         
3164         cfg.cn = [
3165             {
3166                 cls: 'nav',
3167                 tag : 'ul'
3168             }
3169         ];
3170         
3171          
3172         this.type = this.type || 'nav';
3173         if (['tabs','pills'].indexOf(this.type)!==-1) {
3174             cfg.cn[0].cls += ' nav-' + this.type
3175         
3176         
3177         } else {
3178             if (this.type!=='nav') {
3179                 Roo.log('nav type must be nav/tabs/pills')
3180             }
3181             cfg.cn[0].cls += ' navbar-nav'
3182         }
3183         
3184         
3185         
3186         
3187         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3188             cfg.cn[0].cls += ' nav-' + this.arrangement;
3189         }
3190         
3191         
3192         if (this.align === 'right') {
3193             cfg.cn[0].cls += ' navbar-right';
3194         }
3195         
3196         if (this.inverse) {
3197             cfg.cls += ' navbar-inverse';
3198             
3199         }
3200         
3201         
3202         return cfg;
3203     
3204         
3205     }
3206     
3207     
3208     
3209 });
3210
3211
3212
3213  
3214
3215  
3216        /*
3217  * - LGPL
3218  *
3219  * navbar
3220  * 
3221  */
3222
3223 /**
3224  * @class Roo.bootstrap.NavHeaderbar
3225  * @extends Roo.bootstrap.NavSimplebar
3226  * Bootstrap Sidebar class
3227  *
3228  * @cfg {String} brand what is brand
3229  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3230  * @cfg {String} brand_href href of the brand
3231  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3232  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3233  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3234  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3235  * 
3236  * @constructor
3237  * Create a new Sidebar
3238  * @param {Object} config The config object
3239  */
3240
3241
3242 Roo.bootstrap.NavHeaderbar = function(config){
3243     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3244       
3245 };
3246
3247 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3248     
3249     position: '',
3250     brand: '',
3251     brand_href: false,
3252     srButton : true,
3253     autohide : false,
3254     desktopCenter : false,
3255    
3256     
3257     getAutoCreate : function(){
3258         
3259         var   cfg = {
3260             tag: this.nav || 'nav',
3261             cls: 'navbar',
3262             role: 'navigation',
3263             cn: []
3264         };
3265         
3266         var cn = cfg.cn;
3267         if (this.desktopCenter) {
3268             cn.push({cls : 'container', cn : []});
3269             cn = cn[0].cn;
3270         }
3271         
3272         if(this.srButton){
3273             cn.push({
3274                 tag: 'div',
3275                 cls: 'navbar-header',
3276                 cn: [
3277                     {
3278                         tag: 'button',
3279                         type: 'button',
3280                         cls: 'navbar-toggle',
3281                         'data-toggle': 'collapse',
3282                         cn: [
3283                             {
3284                                 tag: 'span',
3285                                 cls: 'sr-only',
3286                                 html: 'Toggle navigation'
3287                             },
3288                             {
3289                                 tag: 'span',
3290                                 cls: 'icon-bar'
3291                             },
3292                             {
3293                                 tag: 'span',
3294                                 cls: 'icon-bar'
3295                             },
3296                             {
3297                                 tag: 'span',
3298                                 cls: 'icon-bar'
3299                             }
3300                         ]
3301                     }
3302                 ]
3303             });
3304         }
3305         
3306         cn.push({
3307             tag: 'div',
3308             cls: 'collapse navbar-collapse',
3309             cn : []
3310         });
3311         
3312         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3313         
3314         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3315             cfg.cls += ' navbar-' + this.position;
3316             
3317             // tag can override this..
3318             
3319             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3320         }
3321         
3322         if (this.brand !== '') {
3323             cn[0].cn.push({
3324                 tag: 'a',
3325                 href: this.brand_href ? this.brand_href : '#',
3326                 cls: 'navbar-brand',
3327                 cn: [
3328                 this.brand
3329                 ]
3330             });
3331         }
3332         
3333         if(this.main){
3334             cfg.cls += ' main-nav';
3335         }
3336         
3337         
3338         return cfg;
3339
3340         
3341     },
3342     getHeaderChildContainer : function()
3343     {
3344         if (this.el.select('.navbar-header').getCount()) {
3345             return this.el.select('.navbar-header',true).first();
3346         }
3347         
3348         return this.getChildContainer();
3349     },
3350     
3351     
3352     initEvents : function()
3353     {
3354         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3355         
3356         if (this.autohide) {
3357             
3358             var prevScroll = 0;
3359             var ft = this.el;
3360             
3361             Roo.get(document).on('scroll',function(e) {
3362                 var ns = Roo.get(document).getScroll().top;
3363                 var os = prevScroll;
3364                 prevScroll = ns;
3365                 
3366                 if(ns > os){
3367                     ft.removeClass('slideDown');
3368                     ft.addClass('slideUp');
3369                     return;
3370                 }
3371                 ft.removeClass('slideUp');
3372                 ft.addClass('slideDown');
3373                  
3374               
3375           },this);
3376         }
3377     }    
3378           
3379       
3380     
3381     
3382 });
3383
3384
3385
3386  
3387
3388  /*
3389  * - LGPL
3390  *
3391  * navbar
3392  * 
3393  */
3394
3395 /**
3396  * @class Roo.bootstrap.NavSidebar
3397  * @extends Roo.bootstrap.Navbar
3398  * Bootstrap Sidebar class
3399  * 
3400  * @constructor
3401  * Create a new Sidebar
3402  * @param {Object} config The config object
3403  */
3404
3405
3406 Roo.bootstrap.NavSidebar = function(config){
3407     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3408 };
3409
3410 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3411     
3412     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3413     
3414     getAutoCreate : function(){
3415         
3416         
3417         return  {
3418             tag: 'div',
3419             cls: 'sidebar sidebar-nav'
3420         };
3421     
3422         
3423     }
3424     
3425     
3426     
3427 });
3428
3429
3430
3431  
3432
3433  /*
3434  * - LGPL
3435  *
3436  * nav group
3437  * 
3438  */
3439
3440 /**
3441  * @class Roo.bootstrap.NavGroup
3442  * @extends Roo.bootstrap.Component
3443  * Bootstrap NavGroup class
3444  * @cfg {String} align left | right
3445  * @cfg {Boolean} inverse false | true
3446  * @cfg {String} type (nav|pills|tab) default nav
3447  * @cfg {String} navId - reference Id for navbar.
3448
3449  * 
3450  * @constructor
3451  * Create a new nav group
3452  * @param {Object} config The config object
3453  */
3454
3455 Roo.bootstrap.NavGroup = function(config){
3456     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3457     this.navItems = [];
3458    
3459     Roo.bootstrap.NavGroup.register(this);
3460      this.addEvents({
3461         /**
3462              * @event changed
3463              * Fires when the active item changes
3464              * @param {Roo.bootstrap.NavGroup} this
3465              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3466              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3467          */
3468         'changed': true
3469      });
3470     
3471 };
3472
3473 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3474     
3475     align: '',
3476     inverse: false,
3477     form: false,
3478     type: 'nav',
3479     navId : '',
3480     // private
3481     
3482     navItems : false, 
3483     
3484     getAutoCreate : function()
3485     {
3486         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3487         
3488         cfg = {
3489             tag : 'ul',
3490             cls: 'nav' 
3491         }
3492         
3493         if (['tabs','pills'].indexOf(this.type)!==-1) {
3494             cfg.cls += ' nav-' + this.type
3495         } else {
3496             if (this.type!=='nav') {
3497                 Roo.log('nav type must be nav/tabs/pills')
3498             }
3499             cfg.cls += ' navbar-nav'
3500         }
3501         
3502         if (this.parent().sidebar) {
3503             cfg = {
3504                 tag: 'ul',
3505                 cls: 'dashboard-menu sidebar-menu'
3506             }
3507             
3508             return cfg;
3509         }
3510         
3511         if (this.form === true) {
3512             cfg = {
3513                 tag: 'form',
3514                 cls: 'navbar-form'
3515             }
3516             
3517             if (this.align === 'right') {
3518                 cfg.cls += ' navbar-right';
3519             } else {
3520                 cfg.cls += ' navbar-left';
3521             }
3522         }
3523         
3524         if (this.align === 'right') {
3525             cfg.cls += ' navbar-right';
3526         }
3527         
3528         if (this.inverse) {
3529             cfg.cls += ' navbar-inverse';
3530             
3531         }
3532         
3533         
3534         return cfg;
3535     },
3536     /**
3537     * sets the active Navigation item
3538     * @param {Roo.bootstrap.NavItem} the new current navitem
3539     */
3540     setActiveItem : function(item)
3541     {
3542         var prev = false;
3543         Roo.each(this.navItems, function(v){
3544             if (v == item) {
3545                 return ;
3546             }
3547             if (v.isActive()) {
3548                 v.setActive(false, true);
3549                 prev = v;
3550                 
3551             }
3552             
3553         });
3554
3555         item.setActive(true, true);
3556         this.fireEvent('changed', this, item, prev);
3557         
3558         
3559     },
3560     /**
3561     * gets the active Navigation item
3562     * @return {Roo.bootstrap.NavItem} the current navitem
3563     */
3564     getActive : function()
3565     {
3566         
3567         var prev = false;
3568         Roo.each(this.navItems, function(v){
3569             
3570             if (v.isActive()) {
3571                 prev = v;
3572                 
3573             }
3574             
3575         });
3576         return prev;
3577     },
3578     
3579     indexOfNav : function()
3580     {
3581         
3582         var prev = false;
3583         Roo.each(this.navItems, function(v,i){
3584             
3585             if (v.isActive()) {
3586                 prev = i;
3587                 
3588             }
3589             
3590         });
3591         return prev;
3592     },
3593     /**
3594     * adds a Navigation item
3595     * @param {Roo.bootstrap.NavItem} the navitem to add
3596     */
3597     addItem : function(cfg)
3598     {
3599         var cn = new Roo.bootstrap.NavItem(cfg);
3600         this.register(cn);
3601         cn.parentId = this.id;
3602         cn.onRender(this.el, null);
3603         return cn;
3604     },
3605     /**
3606     * register a Navigation item
3607     * @param {Roo.bootstrap.NavItem} the navitem to add
3608     */
3609     register : function(item)
3610     {
3611         this.navItems.push( item);
3612         item.navId = this.navId;
3613     
3614     },
3615     
3616     /**
3617     * clear all the Navigation item
3618     */
3619    
3620     clearAll : function()
3621     {
3622         this.navItems = [];
3623         this.el.dom.innerHTML = '';
3624     },
3625     
3626     getNavItem: function(tabId)
3627     {
3628         var ret = false;
3629         Roo.each(this.navItems, function(e) {
3630             if (e.tabId == tabId) {
3631                ret =  e;
3632                return false;
3633             }
3634             return true;
3635             
3636         });
3637         return ret;
3638     },
3639     
3640     setActiveNext : function()
3641     {
3642         var i = this.indexOfNav(this.getActive());
3643         if (i > this.navItems.length) {
3644             return;
3645         }
3646         this.setActiveItem(this.navItems[i+1]);
3647     },
3648     setActivePrev : function()
3649     {
3650         var i = this.indexOfNav(this.getActive());
3651         if (i  < 1) {
3652             return;
3653         }
3654         this.setActiveItem(this.navItems[i-1]);
3655     },
3656     clearWasActive : function(except) {
3657         Roo.each(this.navItems, function(e) {
3658             if (e.tabId != except.tabId && e.was_active) {
3659                e.was_active = false;
3660                return false;
3661             }
3662             return true;
3663             
3664         });
3665     },
3666     getWasActive : function ()
3667     {
3668         var r = false;
3669         Roo.each(this.navItems, function(e) {
3670             if (e.was_active) {
3671                r = e;
3672                return false;
3673             }
3674             return true;
3675             
3676         });
3677         return r;
3678     }
3679     
3680     
3681 });
3682
3683  
3684 Roo.apply(Roo.bootstrap.NavGroup, {
3685     
3686     groups: {},
3687      /**
3688     * register a Navigation Group
3689     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3690     */
3691     register : function(navgrp)
3692     {
3693         this.groups[navgrp.navId] = navgrp;
3694         
3695     },
3696     /**
3697     * fetch a Navigation Group based on the navigation ID
3698     * @param {string} the navgroup to add
3699     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3700     */
3701     get: function(navId) {
3702         if (typeof(this.groups[navId]) == 'undefined') {
3703             return false;
3704             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3705         }
3706         return this.groups[navId] ;
3707     }
3708     
3709     
3710     
3711 });
3712
3713  /*
3714  * - LGPL
3715  *
3716  * row
3717  * 
3718  */
3719
3720 /**
3721  * @class Roo.bootstrap.NavItem
3722  * @extends Roo.bootstrap.Component
3723  * Bootstrap Navbar.NavItem class
3724  * @cfg {String} href  link to
3725  * @cfg {String} html content of button
3726  * @cfg {String} badge text inside badge
3727  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3728  * @cfg {String} glyphicon name of glyphicon
3729  * @cfg {String} icon name of font awesome icon
3730  * @cfg {Boolean} active Is item active
3731  * @cfg {Boolean} disabled Is item disabled
3732  
3733  * @cfg {Boolean} preventDefault (true | false) default false
3734  * @cfg {String} tabId the tab that this item activates.
3735  * @cfg {String} tagtype (a|span) render as a href or span?
3736   
3737  * @constructor
3738  * Create a new Navbar Item
3739  * @param {Object} config The config object
3740  */
3741 Roo.bootstrap.NavItem = function(config){
3742     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3743     this.addEvents({
3744         // raw events
3745         /**
3746          * @event click
3747          * The raw click event for the entire grid.
3748          * @param {Roo.EventObject} e
3749          */
3750         "click" : true,
3751          /**
3752             * @event changed
3753             * Fires when the active item active state changes
3754             * @param {Roo.bootstrap.NavItem} this
3755             * @param {boolean} state the new state
3756              
3757          */
3758         'changed': true
3759     });
3760    
3761 };
3762
3763 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3764     
3765     href: false,
3766     html: '',
3767     badge: '',
3768     icon: false,
3769     glyphicon: false,
3770     active: false,
3771     preventDefault : false,
3772     tabId : false,
3773     tagtype : 'a',
3774     disabled : false,
3775     
3776     was_active : false,
3777     
3778     getAutoCreate : function(){
3779          
3780         var cfg = {
3781             tag: 'li',
3782             cls: 'nav-item'
3783             
3784         }
3785         if (this.active) {
3786             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3787         }
3788         if (this.disabled) {
3789             cfg.cls += ' disabled';
3790         }
3791         
3792         if (this.href || this.html || this.glyphicon || this.icon) {
3793             cfg.cn = [
3794                 {
3795                     tag: this.tagtype,
3796                     href : this.href || "#",
3797                     html: this.html || ''
3798                 }
3799             ];
3800             
3801             if (this.icon) {
3802                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3803             }
3804
3805             if(this.glyphicon) {
3806                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3807             }
3808             
3809             if (this.menu) {
3810                 
3811                 cfg.cn[0].html += " <span class='caret'></span>";
3812              
3813             }
3814             
3815             if (this.badge !== '') {
3816                  
3817                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3818             }
3819         }
3820         
3821         
3822         
3823         return cfg;
3824     },
3825     initEvents: function() 
3826     {
3827         if (typeof (this.menu) != 'undefined') {
3828             this.menu.parentType = this.xtype;
3829             this.menu.triggerEl = this.el;
3830             this.menu = this.addxtype(Roo.apply({}, this.menu));
3831         }
3832         
3833         this.el.select('a',true).on('click', this.onClick, this);
3834         
3835         if(this.tagtype == 'span'){
3836             this.el.select('span',true).on('click', this.onClick, this);
3837         }
3838        
3839         // at this point parent should be available..
3840         this.parent().register(this);
3841     },
3842     
3843     onClick : function(e)
3844     {
3845         if(this.preventDefault || this.href == '#'){
3846             e.preventDefault();
3847         }
3848         
3849         if (this.disabled) {
3850             return;
3851         }
3852         
3853         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3854         if (tg && tg.transition) {
3855             Roo.log("waiting for the transitionend");
3856             return;
3857         }
3858         
3859         Roo.log("fire event clicked");
3860         if(this.fireEvent('click', this, e) === false){
3861             return;
3862         };
3863         
3864         if(this.tagtype == 'span'){
3865             return;
3866         }
3867         
3868         var p = this.parent();
3869         if (['tabs','pills'].indexOf(p.type)!==-1) {
3870             if (typeof(p.setActiveItem) !== 'undefined') {
3871                 p.setActiveItem(this);
3872             }
3873         }
3874         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3875         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3876             // remove the collapsed menu expand...
3877             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3878         }
3879         
3880     },
3881     
3882     isActive: function () {
3883         return this.active
3884     },
3885     setActive : function(state, fire, is_was_active)
3886     {
3887         if (this.active && !state & this.navId) {
3888             this.was_active = true;
3889             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3890             if (nv) {
3891                 nv.clearWasActive(this);
3892             }
3893             
3894         }
3895         this.active = state;
3896         
3897         if (!state ) {
3898             this.el.removeClass('active');
3899         } else if (!this.el.hasClass('active')) {
3900             this.el.addClass('active');
3901         }
3902         if (fire) {
3903             this.fireEvent('changed', this, state);
3904         }
3905         
3906         // show a panel if it's registered and related..
3907         
3908         if (!this.navId || !this.tabId || !state || is_was_active) {
3909             return;
3910         }
3911         
3912         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3913         if (!tg) {
3914             return;
3915         }
3916         var pan = tg.getPanelByName(this.tabId);
3917         if (!pan) {
3918             return;
3919         }
3920         // if we can not flip to new panel - go back to old nav highlight..
3921         if (false == tg.showPanel(pan)) {
3922             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3923             if (nv) {
3924                 var onav = nv.getWasActive();
3925                 if (onav) {
3926                     onav.setActive(true, false, true);
3927                 }
3928             }
3929             
3930         }
3931         
3932         
3933         
3934     },
3935      // this should not be here...
3936     setDisabled : function(state)
3937     {
3938         this.disabled = state;
3939         if (!state ) {
3940             this.el.removeClass('disabled');
3941         } else if (!this.el.hasClass('disabled')) {
3942             this.el.addClass('disabled');
3943         }
3944         
3945     },
3946     
3947     /**
3948      * Fetch the element to display the tooltip on.
3949      * @return {Roo.Element} defaults to this.el
3950      */
3951     tooltipEl : function()
3952     {
3953         return this.el.select('' + this.tagtype + '', true).first();
3954     }
3955 });
3956  
3957
3958  /*
3959  * - LGPL
3960  *
3961  * sidebar item
3962  *
3963  *  li
3964  *    <span> icon </span>
3965  *    <span> text </span>
3966  *    <span>badge </span>
3967  */
3968
3969 /**
3970  * @class Roo.bootstrap.NavSidebarItem
3971  * @extends Roo.bootstrap.NavItem
3972  * Bootstrap Navbar.NavSidebarItem class
3973  * @constructor
3974  * Create a new Navbar Button
3975  * @param {Object} config The config object
3976  */
3977 Roo.bootstrap.NavSidebarItem = function(config){
3978     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3979     this.addEvents({
3980         // raw events
3981         /**
3982          * @event click
3983          * The raw click event for the entire grid.
3984          * @param {Roo.EventObject} e
3985          */
3986         "click" : true,
3987          /**
3988             * @event changed
3989             * Fires when the active item active state changes
3990             * @param {Roo.bootstrap.NavSidebarItem} this
3991             * @param {boolean} state the new state
3992              
3993          */
3994         'changed': true
3995     });
3996    
3997 };
3998
3999 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4000     
4001     
4002     getAutoCreate : function(){
4003         
4004         
4005         var a = {
4006                 tag: 'a',
4007                 href : this.href || '#',
4008                 cls: '',
4009                 html : '',
4010                 cn : []
4011         };
4012         var cfg = {
4013             tag: 'li',
4014             cls: '',
4015             cn: [ a ]
4016         }
4017         var span = {
4018             tag: 'span',
4019             html : this.html || ''
4020         }
4021         
4022         
4023         if (this.active) {
4024             cfg.cls += ' active';
4025         }
4026         
4027         // left icon..
4028         if (this.glyphicon || this.icon) {
4029             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4030             a.cn.push({ tag : 'i', cls : c }) ;
4031         }
4032         // html..
4033         a.cn.push(span);
4034         // then badge..
4035         if (this.badge !== '') {
4036             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4037         }
4038         // fi
4039         if (this.menu) {
4040             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4041             a.cls += 'dropdown-toggle treeview' ;
4042             
4043         }
4044         
4045         
4046         
4047         return cfg;
4048          
4049            
4050     }
4051    
4052      
4053  
4054 });
4055  
4056
4057  /*
4058  * - LGPL
4059  *
4060  * row
4061  * 
4062  */
4063
4064 /**
4065  * @class Roo.bootstrap.Row
4066  * @extends Roo.bootstrap.Component
4067  * Bootstrap Row class (contains columns...)
4068  * 
4069  * @constructor
4070  * Create a new Row
4071  * @param {Object} config The config object
4072  */
4073
4074 Roo.bootstrap.Row = function(config){
4075     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4076 };
4077
4078 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4079     
4080     getAutoCreate : function(){
4081        return {
4082             cls: 'row clearfix'
4083        };
4084     }
4085     
4086     
4087 });
4088
4089  
4090
4091  /*
4092  * - LGPL
4093  *
4094  * element
4095  * 
4096  */
4097
4098 /**
4099  * @class Roo.bootstrap.Element
4100  * @extends Roo.bootstrap.Component
4101  * Bootstrap Element class
4102  * @cfg {String} html contents of the element
4103  * @cfg {String} tag tag of the element
4104  * @cfg {String} cls class of the element
4105  * 
4106  * @constructor
4107  * Create a new Element
4108  * @param {Object} config The config object
4109  */
4110
4111 Roo.bootstrap.Element = function(config){
4112     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4113 };
4114
4115 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4116     
4117     tag: 'div',
4118     cls: '',
4119     html: '',
4120      
4121     
4122     getAutoCreate : function(){
4123         
4124         var cfg = {
4125             tag: this.tag,
4126             cls: this.cls,
4127             html: this.html
4128         }
4129         
4130         
4131         
4132         return cfg;
4133     }
4134    
4135 });
4136
4137  
4138
4139  /*
4140  * - LGPL
4141  *
4142  * pagination
4143  * 
4144  */
4145
4146 /**
4147  * @class Roo.bootstrap.Pagination
4148  * @extends Roo.bootstrap.Component
4149  * Bootstrap Pagination class
4150  * @cfg {String} size xs | sm | md | lg
4151  * @cfg {Boolean} inverse false | true
4152  * 
4153  * @constructor
4154  * Create a new Pagination
4155  * @param {Object} config The config object
4156  */
4157
4158 Roo.bootstrap.Pagination = function(config){
4159     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4160 };
4161
4162 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4163     
4164     cls: false,
4165     size: false,
4166     inverse: false,
4167     
4168     getAutoCreate : function(){
4169         var cfg = {
4170             tag: 'ul',
4171                 cls: 'pagination'
4172         };
4173         if (this.inverse) {
4174             cfg.cls += ' inverse';
4175         }
4176         if (this.html) {
4177             cfg.html=this.html;
4178         }
4179         if (this.cls) {
4180             cfg.cls += " " + this.cls;
4181         }
4182         return cfg;
4183     }
4184    
4185 });
4186
4187  
4188
4189  /*
4190  * - LGPL
4191  *
4192  * Pagination item
4193  * 
4194  */
4195
4196
4197 /**
4198  * @class Roo.bootstrap.PaginationItem
4199  * @extends Roo.bootstrap.Component
4200  * Bootstrap PaginationItem class
4201  * @cfg {String} html text
4202  * @cfg {String} href the link
4203  * @cfg {Boolean} preventDefault (true | false) default true
4204  * @cfg {Boolean} active (true | false) default false
4205  * @cfg {Boolean} disabled default false
4206  * 
4207  * 
4208  * @constructor
4209  * Create a new PaginationItem
4210  * @param {Object} config The config object
4211  */
4212
4213
4214 Roo.bootstrap.PaginationItem = function(config){
4215     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4216     this.addEvents({
4217         // raw events
4218         /**
4219          * @event click
4220          * The raw click event for the entire grid.
4221          * @param {Roo.EventObject} e
4222          */
4223         "click" : true
4224     });
4225 };
4226
4227 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4228     
4229     href : false,
4230     html : false,
4231     preventDefault: true,
4232     active : false,
4233     cls : false,
4234     disabled: false,
4235     
4236     getAutoCreate : function(){
4237         var cfg= {
4238             tag: 'li',
4239             cn: [
4240                 {
4241                     tag : 'a',
4242                     href : this.href ? this.href : '#',
4243                     html : this.html ? this.html : ''
4244                 }
4245             ]
4246         };
4247         
4248         if(this.cls){
4249             cfg.cls = this.cls;
4250         }
4251         
4252         if(this.disabled){
4253             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4254         }
4255         
4256         if(this.active){
4257             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4258         }
4259         
4260         return cfg;
4261     },
4262     
4263     initEvents: function() {
4264         
4265         this.el.on('click', this.onClick, this);
4266         
4267     },
4268     onClick : function(e)
4269     {
4270         Roo.log('PaginationItem on click ');
4271         if(this.preventDefault){
4272             e.preventDefault();
4273         }
4274         
4275         if(this.disabled){
4276             return;
4277         }
4278         
4279         this.fireEvent('click', this, e);
4280     }
4281    
4282 });
4283
4284  
4285
4286  /*
4287  * - LGPL
4288  *
4289  * slider
4290  * 
4291  */
4292
4293
4294 /**
4295  * @class Roo.bootstrap.Slider
4296  * @extends Roo.bootstrap.Component
4297  * Bootstrap Slider class
4298  *    
4299  * @constructor
4300  * Create a new Slider
4301  * @param {Object} config The config object
4302  */
4303
4304 Roo.bootstrap.Slider = function(config){
4305     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4306 };
4307
4308 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4309     
4310     getAutoCreate : function(){
4311         
4312         var cfg = {
4313             tag: 'div',
4314             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4315             cn: [
4316                 {
4317                     tag: 'a',
4318                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4319                 }
4320             ]
4321         }
4322         
4323         return cfg;
4324     }
4325    
4326 });
4327
4328  /*
4329  * Based on:
4330  * Ext JS Library 1.1.1
4331  * Copyright(c) 2006-2007, Ext JS, LLC.
4332  *
4333  * Originally Released Under LGPL - original licence link has changed is not relivant.
4334  *
4335  * Fork - LGPL
4336  * <script type="text/javascript">
4337  */
4338  
4339
4340 /**
4341  * @class Roo.grid.ColumnModel
4342  * @extends Roo.util.Observable
4343  * This is the default implementation of a ColumnModel used by the Grid. It defines
4344  * the columns in the grid.
4345  * <br>Usage:<br>
4346  <pre><code>
4347  var colModel = new Roo.grid.ColumnModel([
4348         {header: "Ticker", width: 60, sortable: true, locked: true},
4349         {header: "Company Name", width: 150, sortable: true},
4350         {header: "Market Cap.", width: 100, sortable: true},
4351         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4352         {header: "Employees", width: 100, sortable: true, resizable: false}
4353  ]);
4354  </code></pre>
4355  * <p>
4356  
4357  * The config options listed for this class are options which may appear in each
4358  * individual column definition.
4359  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4360  * @constructor
4361  * @param {Object} config An Array of column config objects. See this class's
4362  * config objects for details.
4363 */
4364 Roo.grid.ColumnModel = function(config){
4365         /**
4366      * The config passed into the constructor
4367      */
4368     this.config = config;
4369     this.lookup = {};
4370
4371     // if no id, create one
4372     // if the column does not have a dataIndex mapping,
4373     // map it to the order it is in the config
4374     for(var i = 0, len = config.length; i < len; i++){
4375         var c = config[i];
4376         if(typeof c.dataIndex == "undefined"){
4377             c.dataIndex = i;
4378         }
4379         if(typeof c.renderer == "string"){
4380             c.renderer = Roo.util.Format[c.renderer];
4381         }
4382         if(typeof c.id == "undefined"){
4383             c.id = Roo.id();
4384         }
4385         if(c.editor && c.editor.xtype){
4386             c.editor  = Roo.factory(c.editor, Roo.grid);
4387         }
4388         if(c.editor && c.editor.isFormField){
4389             c.editor = new Roo.grid.GridEditor(c.editor);
4390         }
4391         this.lookup[c.id] = c;
4392     }
4393
4394     /**
4395      * The width of columns which have no width specified (defaults to 100)
4396      * @type Number
4397      */
4398     this.defaultWidth = 100;
4399
4400     /**
4401      * Default sortable of columns which have no sortable specified (defaults to false)
4402      * @type Boolean
4403      */
4404     this.defaultSortable = false;
4405
4406     this.addEvents({
4407         /**
4408              * @event widthchange
4409              * Fires when the width of a column changes.
4410              * @param {ColumnModel} this
4411              * @param {Number} columnIndex The column index
4412              * @param {Number} newWidth The new width
4413              */
4414             "widthchange": true,
4415         /**
4416              * @event headerchange
4417              * Fires when the text of a header changes.
4418              * @param {ColumnModel} this
4419              * @param {Number} columnIndex The column index
4420              * @param {Number} newText The new header text
4421              */
4422             "headerchange": true,
4423         /**
4424              * @event hiddenchange
4425              * Fires when a column is hidden or "unhidden".
4426              * @param {ColumnModel} this
4427              * @param {Number} columnIndex The column index
4428              * @param {Boolean} hidden true if hidden, false otherwise
4429              */
4430             "hiddenchange": true,
4431             /**
4432          * @event columnmoved
4433          * Fires when a column is moved.
4434          * @param {ColumnModel} this
4435          * @param {Number} oldIndex
4436          * @param {Number} newIndex
4437          */
4438         "columnmoved" : true,
4439         /**
4440          * @event columlockchange
4441          * Fires when a column's locked state is changed
4442          * @param {ColumnModel} this
4443          * @param {Number} colIndex
4444          * @param {Boolean} locked true if locked
4445          */
4446         "columnlockchange" : true
4447     });
4448     Roo.grid.ColumnModel.superclass.constructor.call(this);
4449 };
4450 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4451     /**
4452      * @cfg {String} header The header text to display in the Grid view.
4453      */
4454     /**
4455      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4456      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4457      * specified, the column's index is used as an index into the Record's data Array.
4458      */
4459     /**
4460      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4461      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4462      */
4463     /**
4464      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4465      * Defaults to the value of the {@link #defaultSortable} property.
4466      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4467      */
4468     /**
4469      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4470      */
4471     /**
4472      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4473      */
4474     /**
4475      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4476      */
4477     /**
4478      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4479      */
4480     /**
4481      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4482      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4483      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4484      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4485      */
4486        /**
4487      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4488      */
4489     /**
4490      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4491      */
4492     /**
4493      * @cfg {String} cursor (Optional)
4494      */
4495     /**
4496      * @cfg {String} tooltip (Optional)
4497      */
4498     /**
4499      * Returns the id of the column at the specified index.
4500      * @param {Number} index The column index
4501      * @return {String} the id
4502      */
4503     getColumnId : function(index){
4504         return this.config[index].id;
4505     },
4506
4507     /**
4508      * Returns the column for a specified id.
4509      * @param {String} id The column id
4510      * @return {Object} the column
4511      */
4512     getColumnById : function(id){
4513         return this.lookup[id];
4514     },
4515
4516     
4517     /**
4518      * Returns the column for a specified dataIndex.
4519      * @param {String} dataIndex The column dataIndex
4520      * @return {Object|Boolean} the column or false if not found
4521      */
4522     getColumnByDataIndex: function(dataIndex){
4523         var index = this.findColumnIndex(dataIndex);
4524         return index > -1 ? this.config[index] : false;
4525     },
4526     
4527     /**
4528      * Returns the index for a specified column id.
4529      * @param {String} id The column id
4530      * @return {Number} the index, or -1 if not found
4531      */
4532     getIndexById : function(id){
4533         for(var i = 0, len = this.config.length; i < len; i++){
4534             if(this.config[i].id == id){
4535                 return i;
4536             }
4537         }
4538         return -1;
4539     },
4540     
4541     /**
4542      * Returns the index for a specified column dataIndex.
4543      * @param {String} dataIndex The column dataIndex
4544      * @return {Number} the index, or -1 if not found
4545      */
4546     
4547     findColumnIndex : function(dataIndex){
4548         for(var i = 0, len = this.config.length; i < len; i++){
4549             if(this.config[i].dataIndex == dataIndex){
4550                 return i;
4551             }
4552         }
4553         return -1;
4554     },
4555     
4556     
4557     moveColumn : function(oldIndex, newIndex){
4558         var c = this.config[oldIndex];
4559         this.config.splice(oldIndex, 1);
4560         this.config.splice(newIndex, 0, c);
4561         this.dataMap = null;
4562         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4563     },
4564
4565     isLocked : function(colIndex){
4566         return this.config[colIndex].locked === true;
4567     },
4568
4569     setLocked : function(colIndex, value, suppressEvent){
4570         if(this.isLocked(colIndex) == value){
4571             return;
4572         }
4573         this.config[colIndex].locked = value;
4574         if(!suppressEvent){
4575             this.fireEvent("columnlockchange", this, colIndex, value);
4576         }
4577     },
4578
4579     getTotalLockedWidth : function(){
4580         var totalWidth = 0;
4581         for(var i = 0; i < this.config.length; i++){
4582             if(this.isLocked(i) && !this.isHidden(i)){
4583                 this.totalWidth += this.getColumnWidth(i);
4584             }
4585         }
4586         return totalWidth;
4587     },
4588
4589     getLockedCount : function(){
4590         for(var i = 0, len = this.config.length; i < len; i++){
4591             if(!this.isLocked(i)){
4592                 return i;
4593             }
4594         }
4595     },
4596
4597     /**
4598      * Returns the number of columns.
4599      * @return {Number}
4600      */
4601     getColumnCount : function(visibleOnly){
4602         if(visibleOnly === true){
4603             var c = 0;
4604             for(var i = 0, len = this.config.length; i < len; i++){
4605                 if(!this.isHidden(i)){
4606                     c++;
4607                 }
4608             }
4609             return c;
4610         }
4611         return this.config.length;
4612     },
4613
4614     /**
4615      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4616      * @param {Function} fn
4617      * @param {Object} scope (optional)
4618      * @return {Array} result
4619      */
4620     getColumnsBy : function(fn, scope){
4621         var r = [];
4622         for(var i = 0, len = this.config.length; i < len; i++){
4623             var c = this.config[i];
4624             if(fn.call(scope||this, c, i) === true){
4625                 r[r.length] = c;
4626             }
4627         }
4628         return r;
4629     },
4630
4631     /**
4632      * Returns true if the specified column is sortable.
4633      * @param {Number} col The column index
4634      * @return {Boolean}
4635      */
4636     isSortable : function(col){
4637         if(typeof this.config[col].sortable == "undefined"){
4638             return this.defaultSortable;
4639         }
4640         return this.config[col].sortable;
4641     },
4642
4643     /**
4644      * Returns the rendering (formatting) function defined for the column.
4645      * @param {Number} col The column index.
4646      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4647      */
4648     getRenderer : function(col){
4649         if(!this.config[col].renderer){
4650             return Roo.grid.ColumnModel.defaultRenderer;
4651         }
4652         return this.config[col].renderer;
4653     },
4654
4655     /**
4656      * Sets the rendering (formatting) function for a column.
4657      * @param {Number} col The column index
4658      * @param {Function} fn The function to use to process the cell's raw data
4659      * to return HTML markup for the grid view. The render function is called with
4660      * the following parameters:<ul>
4661      * <li>Data value.</li>
4662      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4663      * <li>css A CSS style string to apply to the table cell.</li>
4664      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4665      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4666      * <li>Row index</li>
4667      * <li>Column index</li>
4668      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4669      */
4670     setRenderer : function(col, fn){
4671         this.config[col].renderer = fn;
4672     },
4673
4674     /**
4675      * Returns the width for the specified column.
4676      * @param {Number} col The column index
4677      * @return {Number}
4678      */
4679     getColumnWidth : function(col){
4680         return this.config[col].width * 1 || this.defaultWidth;
4681     },
4682
4683     /**
4684      * Sets the width for a column.
4685      * @param {Number} col The column index
4686      * @param {Number} width The new width
4687      */
4688     setColumnWidth : function(col, width, suppressEvent){
4689         this.config[col].width = width;
4690         this.totalWidth = null;
4691         if(!suppressEvent){
4692              this.fireEvent("widthchange", this, col, width);
4693         }
4694     },
4695
4696     /**
4697      * Returns the total width of all columns.
4698      * @param {Boolean} includeHidden True to include hidden column widths
4699      * @return {Number}
4700      */
4701     getTotalWidth : function(includeHidden){
4702         if(!this.totalWidth){
4703             this.totalWidth = 0;
4704             for(var i = 0, len = this.config.length; i < len; i++){
4705                 if(includeHidden || !this.isHidden(i)){
4706                     this.totalWidth += this.getColumnWidth(i);
4707                 }
4708             }
4709         }
4710         return this.totalWidth;
4711     },
4712
4713     /**
4714      * Returns the header for the specified column.
4715      * @param {Number} col The column index
4716      * @return {String}
4717      */
4718     getColumnHeader : function(col){
4719         return this.config[col].header;
4720     },
4721
4722     /**
4723      * Sets the header for a column.
4724      * @param {Number} col The column index
4725      * @param {String} header The new header
4726      */
4727     setColumnHeader : function(col, header){
4728         this.config[col].header = header;
4729         this.fireEvent("headerchange", this, col, header);
4730     },
4731
4732     /**
4733      * Returns the tooltip for the specified column.
4734      * @param {Number} col The column index
4735      * @return {String}
4736      */
4737     getColumnTooltip : function(col){
4738             return this.config[col].tooltip;
4739     },
4740     /**
4741      * Sets the tooltip for a column.
4742      * @param {Number} col The column index
4743      * @param {String} tooltip The new tooltip
4744      */
4745     setColumnTooltip : function(col, tooltip){
4746             this.config[col].tooltip = tooltip;
4747     },
4748
4749     /**
4750      * Returns the dataIndex for the specified column.
4751      * @param {Number} col The column index
4752      * @return {Number}
4753      */
4754     getDataIndex : function(col){
4755         return this.config[col].dataIndex;
4756     },
4757
4758     /**
4759      * Sets the dataIndex for a column.
4760      * @param {Number} col The column index
4761      * @param {Number} dataIndex The new dataIndex
4762      */
4763     setDataIndex : function(col, dataIndex){
4764         this.config[col].dataIndex = dataIndex;
4765     },
4766
4767     
4768     
4769     /**
4770      * Returns true if the cell is editable.
4771      * @param {Number} colIndex The column index
4772      * @param {Number} rowIndex The row index
4773      * @return {Boolean}
4774      */
4775     isCellEditable : function(colIndex, rowIndex){
4776         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4777     },
4778
4779     /**
4780      * Returns the editor defined for the cell/column.
4781      * return false or null to disable editing.
4782      * @param {Number} colIndex The column index
4783      * @param {Number} rowIndex The row index
4784      * @return {Object}
4785      */
4786     getCellEditor : function(colIndex, rowIndex){
4787         return this.config[colIndex].editor;
4788     },
4789
4790     /**
4791      * Sets if a column is editable.
4792      * @param {Number} col The column index
4793      * @param {Boolean} editable True if the column is editable
4794      */
4795     setEditable : function(col, editable){
4796         this.config[col].editable = editable;
4797     },
4798
4799
4800     /**
4801      * Returns true if the column is hidden.
4802      * @param {Number} colIndex The column index
4803      * @return {Boolean}
4804      */
4805     isHidden : function(colIndex){
4806         return this.config[colIndex].hidden;
4807     },
4808
4809
4810     /**
4811      * Returns true if the column width cannot be changed
4812      */
4813     isFixed : function(colIndex){
4814         return this.config[colIndex].fixed;
4815     },
4816
4817     /**
4818      * Returns true if the column can be resized
4819      * @return {Boolean}
4820      */
4821     isResizable : function(colIndex){
4822         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4823     },
4824     /**
4825      * Sets if a column is hidden.
4826      * @param {Number} colIndex The column index
4827      * @param {Boolean} hidden True if the column is hidden
4828      */
4829     setHidden : function(colIndex, hidden){
4830         this.config[colIndex].hidden = hidden;
4831         this.totalWidth = null;
4832         this.fireEvent("hiddenchange", this, colIndex, hidden);
4833     },
4834
4835     /**
4836      * Sets the editor for a column.
4837      * @param {Number} col The column index
4838      * @param {Object} editor The editor object
4839      */
4840     setEditor : function(col, editor){
4841         this.config[col].editor = editor;
4842     }
4843 });
4844
4845 Roo.grid.ColumnModel.defaultRenderer = function(value){
4846         if(typeof value == "string" && value.length < 1){
4847             return "&#160;";
4848         }
4849         return value;
4850 };
4851
4852 // Alias for backwards compatibility
4853 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4854 /*
4855  * Based on:
4856  * Ext JS Library 1.1.1
4857  * Copyright(c) 2006-2007, Ext JS, LLC.
4858  *
4859  * Originally Released Under LGPL - original licence link has changed is not relivant.
4860  *
4861  * Fork - LGPL
4862  * <script type="text/javascript">
4863  */
4864  
4865 /**
4866  * @class Roo.LoadMask
4867  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4868  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4869  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4870  * element's UpdateManager load indicator and will be destroyed after the initial load.
4871  * @constructor
4872  * Create a new LoadMask
4873  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4874  * @param {Object} config The config object
4875  */
4876 Roo.LoadMask = function(el, config){
4877     this.el = Roo.get(el);
4878     Roo.apply(this, config);
4879     if(this.store){
4880         this.store.on('beforeload', this.onBeforeLoad, this);
4881         this.store.on('load', this.onLoad, this);
4882         this.store.on('loadexception', this.onLoadException, this);
4883         this.removeMask = false;
4884     }else{
4885         var um = this.el.getUpdateManager();
4886         um.showLoadIndicator = false; // disable the default indicator
4887         um.on('beforeupdate', this.onBeforeLoad, this);
4888         um.on('update', this.onLoad, this);
4889         um.on('failure', this.onLoad, this);
4890         this.removeMask = true;
4891     }
4892 };
4893
4894 Roo.LoadMask.prototype = {
4895     /**
4896      * @cfg {Boolean} removeMask
4897      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4898      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4899      */
4900     /**
4901      * @cfg {String} msg
4902      * The text to display in a centered loading message box (defaults to 'Loading...')
4903      */
4904     msg : 'Loading...',
4905     /**
4906      * @cfg {String} msgCls
4907      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4908      */
4909     msgCls : 'x-mask-loading',
4910
4911     /**
4912      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4913      * @type Boolean
4914      */
4915     disabled: false,
4916
4917     /**
4918      * Disables the mask to prevent it from being displayed
4919      */
4920     disable : function(){
4921        this.disabled = true;
4922     },
4923
4924     /**
4925      * Enables the mask so that it can be displayed
4926      */
4927     enable : function(){
4928         this.disabled = false;
4929     },
4930     
4931     onLoadException : function()
4932     {
4933         Roo.log(arguments);
4934         
4935         if (typeof(arguments[3]) != 'undefined') {
4936             Roo.MessageBox.alert("Error loading",arguments[3]);
4937         } 
4938         /*
4939         try {
4940             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4941                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4942             }   
4943         } catch(e) {
4944             
4945         }
4946         */
4947     
4948         
4949         
4950         this.el.unmask(this.removeMask);
4951     },
4952     // private
4953     onLoad : function()
4954     {
4955         this.el.unmask(this.removeMask);
4956     },
4957
4958     // private
4959     onBeforeLoad : function(){
4960         if(!this.disabled){
4961             this.el.mask(this.msg, this.msgCls);
4962         }
4963     },
4964
4965     // private
4966     destroy : function(){
4967         if(this.store){
4968             this.store.un('beforeload', this.onBeforeLoad, this);
4969             this.store.un('load', this.onLoad, this);
4970             this.store.un('loadexception', this.onLoadException, this);
4971         }else{
4972             var um = this.el.getUpdateManager();
4973             um.un('beforeupdate', this.onBeforeLoad, this);
4974             um.un('update', this.onLoad, this);
4975             um.un('failure', this.onLoad, this);
4976         }
4977     }
4978 };/*
4979  * - LGPL
4980  *
4981  * table
4982  * 
4983  */
4984
4985 /**
4986  * @class Roo.bootstrap.Table
4987  * @extends Roo.bootstrap.Component
4988  * Bootstrap Table class
4989  * @cfg {String} cls table class
4990  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4991  * @cfg {String} bgcolor Specifies the background color for a table
4992  * @cfg {Number} border Specifies whether the table cells should have borders or not
4993  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4994  * @cfg {Number} cellspacing Specifies the space between cells
4995  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4996  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4997  * @cfg {String} sortable Specifies that the table should be sortable
4998  * @cfg {String} summary Specifies a summary of the content of a table
4999  * @cfg {Number} width Specifies the width of a table
5000  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5001  * 
5002  * @cfg {boolean} striped Should the rows be alternative striped
5003  * @cfg {boolean} bordered Add borders to the table
5004  * @cfg {boolean} hover Add hover highlighting
5005  * @cfg {boolean} condensed Format condensed
5006  * @cfg {boolean} responsive Format condensed
5007  * @cfg {Boolean} loadMask (true|false) default false
5008  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5009  * @cfg {Boolean} thead (true|false) generate thead, default true
5010  * @cfg {Boolean} RowSelection (true|false) default false
5011  * @cfg {Boolean} CellSelection (true|false) default false
5012  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5013  
5014  * 
5015  * @constructor
5016  * Create a new Table
5017  * @param {Object} config The config object
5018  */
5019
5020 Roo.bootstrap.Table = function(config){
5021     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5022     
5023     if (this.sm) {
5024         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5025         this.sm = this.selModel;
5026         this.sm.xmodule = this.xmodule || false;
5027     }
5028     if (this.cm && typeof(this.cm.config) == 'undefined') {
5029         this.colModel = new Roo.grid.ColumnModel(this.cm);
5030         this.cm = this.colModel;
5031         this.cm.xmodule = this.xmodule || false;
5032     }
5033     if (this.store) {
5034         this.store= Roo.factory(this.store, Roo.data);
5035         this.ds = this.store;
5036         this.ds.xmodule = this.xmodule || false;
5037          
5038     }
5039     if (this.footer && this.store) {
5040         this.footer.dataSource = this.ds;
5041         this.footer = Roo.factory(this.footer);
5042     }
5043     
5044     /** @private */
5045     this.addEvents({
5046         /**
5047          * @event cellclick
5048          * Fires when a cell is clicked
5049          * @param {Roo.bootstrap.Table} this
5050          * @param {Roo.Element} el
5051          * @param {Number} rowIndex
5052          * @param {Number} columnIndex
5053          * @param {Roo.EventObject} e
5054          */
5055         "cellclick" : true,
5056         /**
5057          * @event celldblclick
5058          * Fires when a cell is double clicked
5059          * @param {Roo.bootstrap.Table} this
5060          * @param {Roo.Element} el
5061          * @param {Number} rowIndex
5062          * @param {Number} columnIndex
5063          * @param {Roo.EventObject} e
5064          */
5065         "celldblclick" : true,
5066         /**
5067          * @event rowclick
5068          * Fires when a row is clicked
5069          * @param {Roo.bootstrap.Table} this
5070          * @param {Roo.Element} el
5071          * @param {Number} rowIndex
5072          * @param {Roo.EventObject} e
5073          */
5074         "rowclick" : true,
5075         /**
5076          * @event rowdblclick
5077          * Fires when a row is double clicked
5078          * @param {Roo.bootstrap.Table} this
5079          * @param {Roo.Element} el
5080          * @param {Number} rowIndex
5081          * @param {Roo.EventObject} e
5082          */
5083         "rowdblclick" : true,
5084         /**
5085          * @event mouseover
5086          * Fires when a mouseover occur
5087          * @param {Roo.bootstrap.Table} this
5088          * @param {Roo.Element} el
5089          * @param {Number} rowIndex
5090          * @param {Number} columnIndex
5091          * @param {Roo.EventObject} e
5092          */
5093         "mouseover" : true,
5094         /**
5095          * @event mouseout
5096          * Fires when a mouseout occur
5097          * @param {Roo.bootstrap.Table} this
5098          * @param {Roo.Element} el
5099          * @param {Number} rowIndex
5100          * @param {Number} columnIndex
5101          * @param {Roo.EventObject} e
5102          */
5103         "mouseout" : true,
5104         /**
5105          * @event rowclass
5106          * Fires when a row is rendered, so you can change add a style to it.
5107          * @param {Roo.bootstrap.Table} this
5108          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5109          */
5110         'rowclass' : true,
5111           /**
5112          * @event rowsrendered
5113          * Fires when all the  rows have been rendered
5114          * @param {Roo.bootstrap.Table} this
5115          */
5116         'rowsrendered' : true
5117         
5118     });
5119 };
5120
5121 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5122     
5123     cls: false,
5124     align: false,
5125     bgcolor: false,
5126     border: false,
5127     cellpadding: false,
5128     cellspacing: false,
5129     frame: false,
5130     rules: false,
5131     sortable: false,
5132     summary: false,
5133     width: false,
5134     striped : false,
5135     bordered: false,
5136     hover:  false,
5137     condensed : false,
5138     responsive : false,
5139     sm : false,
5140     cm : false,
5141     store : false,
5142     loadMask : false,
5143     tfoot : true,
5144     thead : true,
5145     RowSelection : false,
5146     CellSelection : false,
5147     layout : false,
5148     
5149     // Roo.Element - the tbody
5150     mainBody: false, 
5151     
5152     getAutoCreate : function(){
5153         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5154         
5155         cfg = {
5156             tag: 'table',
5157             cls : 'table',
5158             cn : []
5159         }
5160             
5161         if (this.striped) {
5162             cfg.cls += ' table-striped';
5163         }
5164         
5165         if (this.hover) {
5166             cfg.cls += ' table-hover';
5167         }
5168         if (this.bordered) {
5169             cfg.cls += ' table-bordered';
5170         }
5171         if (this.condensed) {
5172             cfg.cls += ' table-condensed';
5173         }
5174         if (this.responsive) {
5175             cfg.cls += ' table-responsive';
5176         }
5177         
5178         if (this.cls) {
5179             cfg.cls+=  ' ' +this.cls;
5180         }
5181         
5182         // this lot should be simplifed...
5183         
5184         if (this.align) {
5185             cfg.align=this.align;
5186         }
5187         if (this.bgcolor) {
5188             cfg.bgcolor=this.bgcolor;
5189         }
5190         if (this.border) {
5191             cfg.border=this.border;
5192         }
5193         if (this.cellpadding) {
5194             cfg.cellpadding=this.cellpadding;
5195         }
5196         if (this.cellspacing) {
5197             cfg.cellspacing=this.cellspacing;
5198         }
5199         if (this.frame) {
5200             cfg.frame=this.frame;
5201         }
5202         if (this.rules) {
5203             cfg.rules=this.rules;
5204         }
5205         if (this.sortable) {
5206             cfg.sortable=this.sortable;
5207         }
5208         if (this.summary) {
5209             cfg.summary=this.summary;
5210         }
5211         if (this.width) {
5212             cfg.width=this.width;
5213         }
5214         if (this.layout) {
5215             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5216         }
5217         
5218         if(this.store || this.cm){
5219             if(this.thead){
5220                 cfg.cn.push(this.renderHeader());
5221             }
5222             
5223             cfg.cn.push(this.renderBody());
5224             
5225             if(this.tfoot){
5226                 cfg.cn.push(this.renderFooter());
5227             }
5228             
5229             cfg.cls+=  ' TableGrid';
5230         }
5231         
5232         return { cn : [ cfg ] };
5233     },
5234     
5235     initEvents : function()
5236     {   
5237         if(!this.store || !this.cm){
5238             return;
5239         }
5240         
5241         //Roo.log('initEvents with ds!!!!');
5242         
5243         this.mainBody = this.el.select('tbody', true).first();
5244         
5245         
5246         var _this = this;
5247         
5248         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5249             e.on('click', _this.sort, _this);
5250         });
5251         
5252         this.el.on("click", this.onClick, this);
5253         this.el.on("dblclick", this.onDblClick, this);
5254         
5255         // why is this done????? = it breaks dialogs??
5256         //this.parent().el.setStyle('position', 'relative');
5257         
5258         
5259         if (this.footer) {
5260             this.footer.parentId = this.id;
5261             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5262         }
5263         
5264         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5265         
5266         this.store.on('load', this.onLoad, this);
5267         this.store.on('beforeload', this.onBeforeLoad, this);
5268         this.store.on('update', this.onUpdate, this);
5269         this.store.on('add', this.onAdd, this);
5270         
5271     },
5272     
5273     onMouseover : function(e, el)
5274     {
5275         var cell = Roo.get(el);
5276         
5277         if(!cell){
5278             return;
5279         }
5280         
5281         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5282             cell = cell.findParent('td', false, true);
5283         }
5284         
5285         var row = cell.findParent('tr', false, true);
5286         var cellIndex = cell.dom.cellIndex;
5287         var rowIndex = row.dom.rowIndex - 1; // start from 0
5288         
5289         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5290         
5291     },
5292     
5293     onMouseout : function(e, el)
5294     {
5295         var cell = Roo.get(el);
5296         
5297         if(!cell){
5298             return;
5299         }
5300         
5301         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5302             cell = cell.findParent('td', false, true);
5303         }
5304         
5305         var row = cell.findParent('tr', false, true);
5306         var cellIndex = cell.dom.cellIndex;
5307         var rowIndex = row.dom.rowIndex - 1; // start from 0
5308         
5309         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5310         
5311     },
5312     
5313     onClick : function(e, el)
5314     {
5315         var cell = Roo.get(el);
5316         
5317         if(!cell || (!this.CellSelection && !this.RowSelection)){
5318             return;
5319         }
5320         
5321         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5322             cell = cell.findParent('td', false, true);
5323         }
5324         
5325         if(!cell || typeof(cell) == 'undefined'){
5326             return;
5327         }
5328         
5329         var row = cell.findParent('tr', false, true);
5330         
5331         if(!row || typeof(row) == 'undefined'){
5332             return;
5333         }
5334         
5335         var cellIndex = cell.dom.cellIndex;
5336         var rowIndex = this.getRowIndex(row);
5337         
5338         if(this.CellSelection){
5339             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5340         }
5341         
5342         if(this.RowSelection){
5343             this.fireEvent('rowclick', this, row, rowIndex, e);
5344         }
5345         
5346         
5347     },
5348     
5349     onDblClick : function(e,el)
5350     {
5351         var cell = Roo.get(el);
5352         
5353         if(!cell || (!this.CellSelection && !this.RowSelection)){
5354             return;
5355         }
5356         
5357         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5358             cell = cell.findParent('td', false, true);
5359         }
5360         
5361         if(!cell || typeof(cell) == 'undefined'){
5362             return;
5363         }
5364         
5365         var row = cell.findParent('tr', false, true);
5366         
5367         if(!row || typeof(row) == 'undefined'){
5368             return;
5369         }
5370         
5371         var cellIndex = cell.dom.cellIndex;
5372         var rowIndex = this.getRowIndex(row);
5373         
5374         if(this.CellSelection){
5375             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5376         }
5377         
5378         if(this.RowSelection){
5379             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5380         }
5381     },
5382     
5383     sort : function(e,el)
5384     {
5385         var col = Roo.get(el);
5386         
5387         if(!col.hasClass('sortable')){
5388             return;
5389         }
5390         
5391         var sort = col.attr('sort');
5392         var dir = 'ASC';
5393         
5394         if(col.hasClass('glyphicon-arrow-up')){
5395             dir = 'DESC';
5396         }
5397         
5398         this.store.sortInfo = {field : sort, direction : dir};
5399         
5400         if (this.footer) {
5401             Roo.log("calling footer first");
5402             this.footer.onClick('first');
5403         } else {
5404         
5405             this.store.load({ params : { start : 0 } });
5406         }
5407     },
5408     
5409     renderHeader : function()
5410     {
5411         var header = {
5412             tag: 'thead',
5413             cn : []
5414         };
5415         
5416         var cm = this.cm;
5417         
5418         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5419             
5420             var config = cm.config[i];
5421                     
5422             var c = {
5423                 tag: 'th',
5424                 style : '',
5425                 html: cm.getColumnHeader(i)
5426             };
5427             
5428             if(typeof(config.tooltip) != 'undefined'){
5429                 c.tooltip = config.tooltip;
5430             }
5431             
5432             if(typeof(config.hidden) != 'undefined' && config.hidden){
5433                 c.style += ' display:none;';
5434             }
5435             
5436             if(typeof(config.dataIndex) != 'undefined'){
5437                 c.sort = config.dataIndex;
5438             }
5439             
5440             if(typeof(config.sortable) != 'undefined' && config.sortable){
5441                 c.cls = 'sortable';
5442             }
5443             
5444             if(typeof(config.align) != 'undefined' && config.align.length){
5445                 c.style += ' text-align:' + config.align + ';';
5446             }
5447             
5448             if(typeof(config.width) != 'undefined'){
5449                 c.style += ' width:' + config.width + 'px;';
5450             }
5451             
5452             header.cn.push(c)
5453         }
5454         
5455         return header;
5456     },
5457     
5458     renderBody : function()
5459     {
5460         var body = {
5461             tag: 'tbody',
5462             cn : [
5463                 {
5464                     tag: 'tr',
5465                     cn : [
5466                         {
5467                             tag : 'td',
5468                             colspan :  this.cm.getColumnCount()
5469                         }
5470                     ]
5471                 }
5472             ]
5473         };
5474         
5475         return body;
5476     },
5477     
5478     renderFooter : function()
5479     {
5480         var footer = {
5481             tag: 'tfoot',
5482             cn : [
5483                 {
5484                     tag: 'tr',
5485                     cn : [
5486                         {
5487                             tag : 'td',
5488                             colspan :  this.cm.getColumnCount()
5489                         }
5490                     ]
5491                 }
5492             ]
5493         };
5494         
5495         return footer;
5496     },
5497     
5498     
5499     
5500     onLoad : function()
5501     {
5502         Roo.log('ds onload');
5503         this.clear();
5504         
5505         var _this = this;
5506         var cm = this.cm;
5507         var ds = this.store;
5508         
5509         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5510             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5511             
5512             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5513                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5514             }
5515             
5516             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5517                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5518             }
5519         });
5520         
5521         var tbody =  this.mainBody;
5522               
5523         if(ds.getCount() > 0){
5524             ds.data.each(function(d,rowIndex){
5525                 var row =  this.renderRow(cm, ds, rowIndex);
5526                 
5527                 tbody.createChild(row);
5528                 
5529                 var _this = this;
5530                 
5531                 if(row.cellObjects.length){
5532                     Roo.each(row.cellObjects, function(r){
5533                         _this.renderCellObject(r);
5534                     })
5535                 }
5536                 
5537             }, this);
5538         }
5539         
5540         Roo.each(this.el.select('tbody td', true).elements, function(e){
5541             e.on('mouseover', _this.onMouseover, _this);
5542         });
5543         
5544         Roo.each(this.el.select('tbody td', true).elements, function(e){
5545             e.on('mouseout', _this.onMouseout, _this);
5546         });
5547         this.fireEvent('rowsrendered', this);
5548         //if(this.loadMask){
5549         //    this.maskEl.hide();
5550         //}
5551     },
5552     
5553     
5554     onUpdate : function(ds,record)
5555     {
5556         this.refreshRow(record);
5557     },
5558     
5559     onRemove : function(ds, record, index, isUpdate){
5560         if(isUpdate !== true){
5561             this.fireEvent("beforerowremoved", this, index, record);
5562         }
5563         var bt = this.mainBody.dom;
5564         
5565         var rows = this.el.select('tbody > tr', true).elements;
5566         
5567         if(typeof(rows[index]) != 'undefined'){
5568             bt.removeChild(rows[index].dom);
5569         }
5570         
5571 //        if(bt.rows[index]){
5572 //            bt.removeChild(bt.rows[index]);
5573 //        }
5574         
5575         if(isUpdate !== true){
5576             //this.stripeRows(index);
5577             //this.syncRowHeights(index, index);
5578             //this.layout();
5579             this.fireEvent("rowremoved", this, index, record);
5580         }
5581     },
5582     
5583     onAdd : function(ds, records, rowIndex)
5584     {
5585         //Roo.log('on Add called');
5586         // - note this does not handle multiple adding very well..
5587         var bt = this.mainBody.dom;
5588         for (var i =0 ; i < records.length;i++) {
5589             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5590             //Roo.log(records[i]);
5591             //Roo.log(this.store.getAt(rowIndex+i));
5592             this.insertRow(this.store, rowIndex + i, false);
5593             return;
5594         }
5595         
5596     },
5597     
5598     
5599     refreshRow : function(record){
5600         var ds = this.store, index;
5601         if(typeof record == 'number'){
5602             index = record;
5603             record = ds.getAt(index);
5604         }else{
5605             index = ds.indexOf(record);
5606         }
5607         this.insertRow(ds, index, true);
5608         this.onRemove(ds, record, index+1, true);
5609         //this.syncRowHeights(index, index);
5610         //this.layout();
5611         this.fireEvent("rowupdated", this, index, record);
5612     },
5613     
5614     insertRow : function(dm, rowIndex, isUpdate){
5615         
5616         if(!isUpdate){
5617             this.fireEvent("beforerowsinserted", this, rowIndex);
5618         }
5619             //var s = this.getScrollState();
5620         var row = this.renderRow(this.cm, this.store, rowIndex);
5621         // insert before rowIndex..
5622         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5623         
5624         var _this = this;
5625                 
5626         if(row.cellObjects.length){
5627             Roo.each(row.cellObjects, function(r){
5628                 _this.renderCellObject(r);
5629             })
5630         }
5631             
5632         if(!isUpdate){
5633             this.fireEvent("rowsinserted", this, rowIndex);
5634             //this.syncRowHeights(firstRow, lastRow);
5635             //this.stripeRows(firstRow);
5636             //this.layout();
5637         }
5638         
5639     },
5640     
5641     
5642     getRowDom : function(rowIndex)
5643     {
5644         var rows = this.el.select('tbody > tr', true).elements;
5645         
5646         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5647         
5648     },
5649     // returns the object tree for a tr..
5650   
5651     
5652     renderRow : function(cm, ds, rowIndex) 
5653     {
5654         
5655         var d = ds.getAt(rowIndex);
5656         
5657         var row = {
5658             tag : 'tr',
5659             cn : []
5660         };
5661             
5662         var cellObjects = [];
5663         
5664         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5665             var config = cm.config[i];
5666             
5667             var renderer = cm.getRenderer(i);
5668             var value = '';
5669             var id = false;
5670             
5671             if(typeof(renderer) !== 'undefined'){
5672                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5673             }
5674             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5675             // and are rendered into the cells after the row is rendered - using the id for the element.
5676             
5677             if(typeof(value) === 'object'){
5678                 id = Roo.id();
5679                 cellObjects.push({
5680                     container : id,
5681                     cfg : value 
5682                 })
5683             }
5684             
5685             var rowcfg = {
5686                 record: d,
5687                 rowIndex : rowIndex,
5688                 colIndex : i,
5689                 rowClass : ''
5690             }
5691
5692             this.fireEvent('rowclass', this, rowcfg);
5693             
5694             var td = {
5695                 tag: 'td',
5696                 cls : rowcfg.rowClass,
5697                 style: '',
5698                 html: (typeof(value) === 'object') ? '' : value
5699             };
5700             
5701             if (id) {
5702                 td.id = id;
5703             }
5704             
5705             if(typeof(config.hidden) != 'undefined' && config.hidden){
5706                 td.style += ' display:none;';
5707             }
5708             
5709             if(typeof(config.align) != 'undefined' && config.align.length){
5710                 td.style += ' text-align:' + config.align + ';';
5711             }
5712             
5713             if(typeof(config.width) != 'undefined'){
5714                 td.style += ' width:' +  config.width + 'px;';
5715             }
5716             
5717             if(typeof(config.cursor) != 'undefined'){
5718                 td.style += ' cursor:' +  config.cursor + ';';
5719             }
5720              
5721             row.cn.push(td);
5722            
5723         }
5724         
5725         row.cellObjects = cellObjects;
5726         
5727         return row;
5728           
5729     },
5730     
5731     
5732     
5733     onBeforeLoad : function()
5734     {
5735         //Roo.log('ds onBeforeLoad');
5736         
5737         //this.clear();
5738         
5739         //if(this.loadMask){
5740         //    this.maskEl.show();
5741         //}
5742     },
5743      /**
5744      * Remove all rows
5745      */
5746     clear : function()
5747     {
5748         this.el.select('tbody', true).first().dom.innerHTML = '';
5749     },
5750     /**
5751      * Show or hide a row.
5752      * @param {Number} rowIndex to show or hide
5753      * @param {Boolean} state hide
5754      */
5755     setRowVisibility : function(rowIndex, state)
5756     {
5757         var bt = this.mainBody.dom;
5758         
5759         var rows = this.el.select('tbody > tr', true).elements;
5760         
5761         if(typeof(rows[rowIndex]) == 'undefined'){
5762             return;
5763         }
5764         rows[rowIndex].dom.style.display = state ? '' : 'none';
5765     },
5766     
5767     
5768     getSelectionModel : function(){
5769         if(!this.selModel){
5770             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5771         }
5772         return this.selModel;
5773     },
5774     /*
5775      * Render the Roo.bootstrap object from renderder
5776      */
5777     renderCellObject : function(r)
5778     {
5779         var _this = this;
5780         
5781         var t = r.cfg.render(r.container);
5782         
5783         if(r.cfg.cn){
5784             Roo.each(r.cfg.cn, function(c){
5785                 var child = {
5786                     container: t.getChildContainer(),
5787                     cfg: c
5788                 }
5789                 _this.renderCellObject(child);
5790             })
5791         }
5792     },
5793     
5794     getRowIndex : function(row)
5795     {
5796         var rowIndex = -1;
5797         
5798         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5799             if(el != row){
5800                 return;
5801             }
5802             
5803             rowIndex = index;
5804         });
5805         
5806         return rowIndex;
5807     }
5808    
5809 });
5810
5811  
5812
5813  /*
5814  * - LGPL
5815  *
5816  * table cell
5817  * 
5818  */
5819
5820 /**
5821  * @class Roo.bootstrap.TableCell
5822  * @extends Roo.bootstrap.Component
5823  * Bootstrap TableCell class
5824  * @cfg {String} html cell contain text
5825  * @cfg {String} cls cell class
5826  * @cfg {String} tag cell tag (td|th) default td
5827  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5828  * @cfg {String} align Aligns the content in a cell
5829  * @cfg {String} axis Categorizes cells
5830  * @cfg {String} bgcolor Specifies the background color of a cell
5831  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5832  * @cfg {Number} colspan Specifies the number of columns a cell should span
5833  * @cfg {String} headers Specifies one or more header cells a cell is related to
5834  * @cfg {Number} height Sets the height of a cell
5835  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5836  * @cfg {Number} rowspan Sets the number of rows a cell should span
5837  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5838  * @cfg {String} valign Vertical aligns the content in a cell
5839  * @cfg {Number} width Specifies the width of a cell
5840  * 
5841  * @constructor
5842  * Create a new TableCell
5843  * @param {Object} config The config object
5844  */
5845
5846 Roo.bootstrap.TableCell = function(config){
5847     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5848 };
5849
5850 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5851     
5852     html: false,
5853     cls: false,
5854     tag: false,
5855     abbr: false,
5856     align: false,
5857     axis: false,
5858     bgcolor: false,
5859     charoff: false,
5860     colspan: false,
5861     headers: false,
5862     height: false,
5863     nowrap: false,
5864     rowspan: false,
5865     scope: false,
5866     valign: false,
5867     width: false,
5868     
5869     
5870     getAutoCreate : function(){
5871         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5872         
5873         cfg = {
5874             tag: 'td'
5875         }
5876         
5877         if(this.tag){
5878             cfg.tag = this.tag;
5879         }
5880         
5881         if (this.html) {
5882             cfg.html=this.html
5883         }
5884         if (this.cls) {
5885             cfg.cls=this.cls
5886         }
5887         if (this.abbr) {
5888             cfg.abbr=this.abbr
5889         }
5890         if (this.align) {
5891             cfg.align=this.align
5892         }
5893         if (this.axis) {
5894             cfg.axis=this.axis
5895         }
5896         if (this.bgcolor) {
5897             cfg.bgcolor=this.bgcolor
5898         }
5899         if (this.charoff) {
5900             cfg.charoff=this.charoff
5901         }
5902         if (this.colspan) {
5903             cfg.colspan=this.colspan
5904         }
5905         if (this.headers) {
5906             cfg.headers=this.headers
5907         }
5908         if (this.height) {
5909             cfg.height=this.height
5910         }
5911         if (this.nowrap) {
5912             cfg.nowrap=this.nowrap
5913         }
5914         if (this.rowspan) {
5915             cfg.rowspan=this.rowspan
5916         }
5917         if (this.scope) {
5918             cfg.scope=this.scope
5919         }
5920         if (this.valign) {
5921             cfg.valign=this.valign
5922         }
5923         if (this.width) {
5924             cfg.width=this.width
5925         }
5926         
5927         
5928         return cfg;
5929     }
5930    
5931 });
5932
5933  
5934
5935  /*
5936  * - LGPL
5937  *
5938  * table row
5939  * 
5940  */
5941
5942 /**
5943  * @class Roo.bootstrap.TableRow
5944  * @extends Roo.bootstrap.Component
5945  * Bootstrap TableRow class
5946  * @cfg {String} cls row class
5947  * @cfg {String} align Aligns the content in a table row
5948  * @cfg {String} bgcolor Specifies a background color for a table row
5949  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5950  * @cfg {String} valign Vertical aligns the content in a table row
5951  * 
5952  * @constructor
5953  * Create a new TableRow
5954  * @param {Object} config The config object
5955  */
5956
5957 Roo.bootstrap.TableRow = function(config){
5958     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5959 };
5960
5961 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5962     
5963     cls: false,
5964     align: false,
5965     bgcolor: false,
5966     charoff: false,
5967     valign: false,
5968     
5969     getAutoCreate : function(){
5970         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5971         
5972         cfg = {
5973             tag: 'tr'
5974         }
5975             
5976         if(this.cls){
5977             cfg.cls = this.cls;
5978         }
5979         if(this.align){
5980             cfg.align = this.align;
5981         }
5982         if(this.bgcolor){
5983             cfg.bgcolor = this.bgcolor;
5984         }
5985         if(this.charoff){
5986             cfg.charoff = this.charoff;
5987         }
5988         if(this.valign){
5989             cfg.valign = this.valign;
5990         }
5991         
5992         return cfg;
5993     }
5994    
5995 });
5996
5997  
5998
5999  /*
6000  * - LGPL
6001  *
6002  * table body
6003  * 
6004  */
6005
6006 /**
6007  * @class Roo.bootstrap.TableBody
6008  * @extends Roo.bootstrap.Component
6009  * Bootstrap TableBody class
6010  * @cfg {String} cls element class
6011  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6012  * @cfg {String} align Aligns the content inside the element
6013  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6014  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6015  * 
6016  * @constructor
6017  * Create a new TableBody
6018  * @param {Object} config The config object
6019  */
6020
6021 Roo.bootstrap.TableBody = function(config){
6022     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6023 };
6024
6025 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
6026     
6027     cls: false,
6028     tag: false,
6029     align: false,
6030     charoff: false,
6031     valign: false,
6032     
6033     getAutoCreate : function(){
6034         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6035         
6036         cfg = {
6037             tag: 'tbody'
6038         }
6039             
6040         if (this.cls) {
6041             cfg.cls=this.cls
6042         }
6043         if(this.tag){
6044             cfg.tag = this.tag;
6045         }
6046         
6047         if(this.align){
6048             cfg.align = this.align;
6049         }
6050         if(this.charoff){
6051             cfg.charoff = this.charoff;
6052         }
6053         if(this.valign){
6054             cfg.valign = this.valign;
6055         }
6056         
6057         return cfg;
6058     }
6059     
6060     
6061 //    initEvents : function()
6062 //    {
6063 //        
6064 //        if(!this.store){
6065 //            return;
6066 //        }
6067 //        
6068 //        this.store = Roo.factory(this.store, Roo.data);
6069 //        this.store.on('load', this.onLoad, this);
6070 //        
6071 //        this.store.load();
6072 //        
6073 //    },
6074 //    
6075 //    onLoad: function () 
6076 //    {   
6077 //        this.fireEvent('load', this);
6078 //    }
6079 //    
6080 //   
6081 });
6082
6083  
6084
6085  /*
6086  * Based on:
6087  * Ext JS Library 1.1.1
6088  * Copyright(c) 2006-2007, Ext JS, LLC.
6089  *
6090  * Originally Released Under LGPL - original licence link has changed is not relivant.
6091  *
6092  * Fork - LGPL
6093  * <script type="text/javascript">
6094  */
6095
6096 // as we use this in bootstrap.
6097 Roo.namespace('Roo.form');
6098  /**
6099  * @class Roo.form.Action
6100  * Internal Class used to handle form actions
6101  * @constructor
6102  * @param {Roo.form.BasicForm} el The form element or its id
6103  * @param {Object} config Configuration options
6104  */
6105
6106  
6107  
6108 // define the action interface
6109 Roo.form.Action = function(form, options){
6110     this.form = form;
6111     this.options = options || {};
6112 };
6113 /**
6114  * Client Validation Failed
6115  * @const 
6116  */
6117 Roo.form.Action.CLIENT_INVALID = 'client';
6118 /**
6119  * Server Validation Failed
6120  * @const 
6121  */
6122 Roo.form.Action.SERVER_INVALID = 'server';
6123  /**
6124  * Connect to Server Failed
6125  * @const 
6126  */
6127 Roo.form.Action.CONNECT_FAILURE = 'connect';
6128 /**
6129  * Reading Data from Server Failed
6130  * @const 
6131  */
6132 Roo.form.Action.LOAD_FAILURE = 'load';
6133
6134 Roo.form.Action.prototype = {
6135     type : 'default',
6136     failureType : undefined,
6137     response : undefined,
6138     result : undefined,
6139
6140     // interface method
6141     run : function(options){
6142
6143     },
6144
6145     // interface method
6146     success : function(response){
6147
6148     },
6149
6150     // interface method
6151     handleResponse : function(response){
6152
6153     },
6154
6155     // default connection failure
6156     failure : function(response){
6157         
6158         this.response = response;
6159         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6160         this.form.afterAction(this, false);
6161     },
6162
6163     processResponse : function(response){
6164         this.response = response;
6165         if(!response.responseText){
6166             return true;
6167         }
6168         this.result = this.handleResponse(response);
6169         return this.result;
6170     },
6171
6172     // utility functions used internally
6173     getUrl : function(appendParams){
6174         var url = this.options.url || this.form.url || this.form.el.dom.action;
6175         if(appendParams){
6176             var p = this.getParams();
6177             if(p){
6178                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6179             }
6180         }
6181         return url;
6182     },
6183
6184     getMethod : function(){
6185         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6186     },
6187
6188     getParams : function(){
6189         var bp = this.form.baseParams;
6190         var p = this.options.params;
6191         if(p){
6192             if(typeof p == "object"){
6193                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6194             }else if(typeof p == 'string' && bp){
6195                 p += '&' + Roo.urlEncode(bp);
6196             }
6197         }else if(bp){
6198             p = Roo.urlEncode(bp);
6199         }
6200         return p;
6201     },
6202
6203     createCallback : function(){
6204         return {
6205             success: this.success,
6206             failure: this.failure,
6207             scope: this,
6208             timeout: (this.form.timeout*1000),
6209             upload: this.form.fileUpload ? this.success : undefined
6210         };
6211     }
6212 };
6213
6214 Roo.form.Action.Submit = function(form, options){
6215     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6216 };
6217
6218 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6219     type : 'submit',
6220
6221     haveProgress : false,
6222     uploadComplete : false,
6223     
6224     // uploadProgress indicator.
6225     uploadProgress : function()
6226     {
6227         if (!this.form.progressUrl) {
6228             return;
6229         }
6230         
6231         if (!this.haveProgress) {
6232             Roo.MessageBox.progress("Uploading", "Uploading");
6233         }
6234         if (this.uploadComplete) {
6235            Roo.MessageBox.hide();
6236            return;
6237         }
6238         
6239         this.haveProgress = true;
6240    
6241         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6242         
6243         var c = new Roo.data.Connection();
6244         c.request({
6245             url : this.form.progressUrl,
6246             params: {
6247                 id : uid
6248             },
6249             method: 'GET',
6250             success : function(req){
6251                //console.log(data);
6252                 var rdata = false;
6253                 var edata;
6254                 try  {
6255                    rdata = Roo.decode(req.responseText)
6256                 } catch (e) {
6257                     Roo.log("Invalid data from server..");
6258                     Roo.log(edata);
6259                     return;
6260                 }
6261                 if (!rdata || !rdata.success) {
6262                     Roo.log(rdata);
6263                     Roo.MessageBox.alert(Roo.encode(rdata));
6264                     return;
6265                 }
6266                 var data = rdata.data;
6267                 
6268                 if (this.uploadComplete) {
6269                    Roo.MessageBox.hide();
6270                    return;
6271                 }
6272                    
6273                 if (data){
6274                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6275                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6276                     );
6277                 }
6278                 this.uploadProgress.defer(2000,this);
6279             },
6280        
6281             failure: function(data) {
6282                 Roo.log('progress url failed ');
6283                 Roo.log(data);
6284             },
6285             scope : this
6286         });
6287            
6288     },
6289     
6290     
6291     run : function()
6292     {
6293         // run get Values on the form, so it syncs any secondary forms.
6294         this.form.getValues();
6295         
6296         var o = this.options;
6297         var method = this.getMethod();
6298         var isPost = method == 'POST';
6299         if(o.clientValidation === false || this.form.isValid()){
6300             
6301             if (this.form.progressUrl) {
6302                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6303                     (new Date() * 1) + '' + Math.random());
6304                     
6305             } 
6306             
6307             
6308             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6309                 form:this.form.el.dom,
6310                 url:this.getUrl(!isPost),
6311                 method: method,
6312                 params:isPost ? this.getParams() : null,
6313                 isUpload: this.form.fileUpload
6314             }));
6315             
6316             this.uploadProgress();
6317
6318         }else if (o.clientValidation !== false){ // client validation failed
6319             this.failureType = Roo.form.Action.CLIENT_INVALID;
6320             this.form.afterAction(this, false);
6321         }
6322     },
6323
6324     success : function(response)
6325     {
6326         this.uploadComplete= true;
6327         if (this.haveProgress) {
6328             Roo.MessageBox.hide();
6329         }
6330         
6331         
6332         var result = this.processResponse(response);
6333         if(result === true || result.success){
6334             this.form.afterAction(this, true);
6335             return;
6336         }
6337         if(result.errors){
6338             this.form.markInvalid(result.errors);
6339             this.failureType = Roo.form.Action.SERVER_INVALID;
6340         }
6341         this.form.afterAction(this, false);
6342     },
6343     failure : function(response)
6344     {
6345         this.uploadComplete= true;
6346         if (this.haveProgress) {
6347             Roo.MessageBox.hide();
6348         }
6349         
6350         this.response = response;
6351         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6352         this.form.afterAction(this, false);
6353     },
6354     
6355     handleResponse : function(response){
6356         if(this.form.errorReader){
6357             var rs = this.form.errorReader.read(response);
6358             var errors = [];
6359             if(rs.records){
6360                 for(var i = 0, len = rs.records.length; i < len; i++) {
6361                     var r = rs.records[i];
6362                     errors[i] = r.data;
6363                 }
6364             }
6365             if(errors.length < 1){
6366                 errors = null;
6367             }
6368             return {
6369                 success : rs.success,
6370                 errors : errors
6371             };
6372         }
6373         var ret = false;
6374         try {
6375             ret = Roo.decode(response.responseText);
6376         } catch (e) {
6377             ret = {
6378                 success: false,
6379                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6380                 errors : []
6381             };
6382         }
6383         return ret;
6384         
6385     }
6386 });
6387
6388
6389 Roo.form.Action.Load = function(form, options){
6390     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6391     this.reader = this.form.reader;
6392 };
6393
6394 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6395     type : 'load',
6396
6397     run : function(){
6398         
6399         Roo.Ajax.request(Roo.apply(
6400                 this.createCallback(), {
6401                     method:this.getMethod(),
6402                     url:this.getUrl(false),
6403                     params:this.getParams()
6404         }));
6405     },
6406
6407     success : function(response){
6408         
6409         var result = this.processResponse(response);
6410         if(result === true || !result.success || !result.data){
6411             this.failureType = Roo.form.Action.LOAD_FAILURE;
6412             this.form.afterAction(this, false);
6413             return;
6414         }
6415         this.form.clearInvalid();
6416         this.form.setValues(result.data);
6417         this.form.afterAction(this, true);
6418     },
6419
6420     handleResponse : function(response){
6421         if(this.form.reader){
6422             var rs = this.form.reader.read(response);
6423             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6424             return {
6425                 success : rs.success,
6426                 data : data
6427             };
6428         }
6429         return Roo.decode(response.responseText);
6430     }
6431 });
6432
6433 Roo.form.Action.ACTION_TYPES = {
6434     'load' : Roo.form.Action.Load,
6435     'submit' : Roo.form.Action.Submit
6436 };/*
6437  * - LGPL
6438  *
6439  * form
6440  * 
6441  */
6442
6443 /**
6444  * @class Roo.bootstrap.Form
6445  * @extends Roo.bootstrap.Component
6446  * Bootstrap Form class
6447  * @cfg {String} method  GET | POST (default POST)
6448  * @cfg {String} labelAlign top | left (default top)
6449  * @cfg {String} align left  | right - for navbars
6450  * @cfg {Boolean} loadMask load mask when submit (default true)
6451
6452  * 
6453  * @constructor
6454  * Create a new Form
6455  * @param {Object} config The config object
6456  */
6457
6458
6459 Roo.bootstrap.Form = function(config){
6460     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6461     this.addEvents({
6462         /**
6463          * @event clientvalidation
6464          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6465          * @param {Form} this
6466          * @param {Boolean} valid true if the form has passed client-side validation
6467          */
6468         clientvalidation: true,
6469         /**
6470          * @event beforeaction
6471          * Fires before any action is performed. Return false to cancel the action.
6472          * @param {Form} this
6473          * @param {Action} action The action to be performed
6474          */
6475         beforeaction: true,
6476         /**
6477          * @event actionfailed
6478          * Fires when an action fails.
6479          * @param {Form} this
6480          * @param {Action} action The action that failed
6481          */
6482         actionfailed : true,
6483         /**
6484          * @event actioncomplete
6485          * Fires when an action is completed.
6486          * @param {Form} this
6487          * @param {Action} action The action that completed
6488          */
6489         actioncomplete : true
6490     });
6491     
6492 };
6493
6494 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6495       
6496      /**
6497      * @cfg {String} method
6498      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6499      */
6500     method : 'POST',
6501     /**
6502      * @cfg {String} url
6503      * The URL to use for form actions if one isn't supplied in the action options.
6504      */
6505     /**
6506      * @cfg {Boolean} fileUpload
6507      * Set to true if this form is a file upload.
6508      */
6509      
6510     /**
6511      * @cfg {Object} baseParams
6512      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6513      */
6514       
6515     /**
6516      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6517      */
6518     timeout: 30,
6519     /**
6520      * @cfg {Sting} align (left|right) for navbar forms
6521      */
6522     align : 'left',
6523
6524     // private
6525     activeAction : null,
6526  
6527     /**
6528      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6529      * element by passing it or its id or mask the form itself by passing in true.
6530      * @type Mixed
6531      */
6532     waitMsgTarget : false,
6533     
6534     loadMask : true,
6535     
6536     getAutoCreate : function(){
6537         
6538         var cfg = {
6539             tag: 'form',
6540             method : this.method || 'POST',
6541             id : this.id || Roo.id(),
6542             cls : ''
6543         }
6544         if (this.parent().xtype.match(/^Nav/)) {
6545             cfg.cls = 'navbar-form navbar-' + this.align;
6546             
6547         }
6548         
6549         if (this.labelAlign == 'left' ) {
6550             cfg.cls += ' form-horizontal';
6551         }
6552         
6553         
6554         return cfg;
6555     },
6556     initEvents : function()
6557     {
6558         this.el.on('submit', this.onSubmit, this);
6559         // this was added as random key presses on the form where triggering form submit.
6560         this.el.on('keypress', function(e) {
6561             if (e.getCharCode() != 13) {
6562                 return true;
6563             }
6564             // we might need to allow it for textareas.. and some other items.
6565             // check e.getTarget().
6566             
6567             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6568                 return true;
6569             }
6570         
6571             Roo.log("keypress blocked");
6572             
6573             e.preventDefault();
6574             return false;
6575         });
6576         
6577     },
6578     // private
6579     onSubmit : function(e){
6580         e.stopEvent();
6581     },
6582     
6583      /**
6584      * Returns true if client-side validation on the form is successful.
6585      * @return Boolean
6586      */
6587     isValid : function(){
6588         var items = this.getItems();
6589         var valid = true;
6590         items.each(function(f){
6591            if(!f.validate()){
6592                valid = false;
6593                
6594            }
6595         });
6596         return valid;
6597     },
6598     /**
6599      * Returns true if any fields in this form have changed since their original load.
6600      * @return Boolean
6601      */
6602     isDirty : function(){
6603         var dirty = false;
6604         var items = this.getItems();
6605         items.each(function(f){
6606            if(f.isDirty()){
6607                dirty = true;
6608                return false;
6609            }
6610            return true;
6611         });
6612         return dirty;
6613     },
6614      /**
6615      * Performs a predefined action (submit or load) or custom actions you define on this form.
6616      * @param {String} actionName The name of the action type
6617      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6618      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6619      * accept other config options):
6620      * <pre>
6621 Property          Type             Description
6622 ----------------  ---------------  ----------------------------------------------------------------------------------
6623 url               String           The url for the action (defaults to the form's url)
6624 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6625 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6626 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6627                                    validate the form on the client (defaults to false)
6628      * </pre>
6629      * @return {BasicForm} this
6630      */
6631     doAction : function(action, options){
6632         if(typeof action == 'string'){
6633             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6634         }
6635         if(this.fireEvent('beforeaction', this, action) !== false){
6636             this.beforeAction(action);
6637             action.run.defer(100, action);
6638         }
6639         return this;
6640     },
6641     
6642     // private
6643     beforeAction : function(action){
6644         var o = action.options;
6645         
6646         if(this.loadMask){
6647             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6648         }
6649         // not really supported yet.. ??
6650         
6651         //if(this.waitMsgTarget === true){
6652         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6653         //}else if(this.waitMsgTarget){
6654         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6655         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6656         //}else {
6657         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6658        // }
6659          
6660     },
6661
6662     // private
6663     afterAction : function(action, success){
6664         this.activeAction = null;
6665         var o = action.options;
6666         
6667         //if(this.waitMsgTarget === true){
6668             this.el.unmask();
6669         //}else if(this.waitMsgTarget){
6670         //    this.waitMsgTarget.unmask();
6671         //}else{
6672         //    Roo.MessageBox.updateProgress(1);
6673         //    Roo.MessageBox.hide();
6674        // }
6675         // 
6676         if(success){
6677             if(o.reset){
6678                 this.reset();
6679             }
6680             Roo.callback(o.success, o.scope, [this, action]);
6681             this.fireEvent('actioncomplete', this, action);
6682             
6683         }else{
6684             
6685             // failure condition..
6686             // we have a scenario where updates need confirming.
6687             // eg. if a locking scenario exists..
6688             // we look for { errors : { needs_confirm : true }} in the response.
6689             if (
6690                 (typeof(action.result) != 'undefined')  &&
6691                 (typeof(action.result.errors) != 'undefined')  &&
6692                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6693            ){
6694                 var _t = this;
6695                 Roo.log("not supported yet");
6696                  /*
6697                 
6698                 Roo.MessageBox.confirm(
6699                     "Change requires confirmation",
6700                     action.result.errorMsg,
6701                     function(r) {
6702                         if (r != 'yes') {
6703                             return;
6704                         }
6705                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6706                     }
6707                     
6708                 );
6709                 */
6710                 
6711                 
6712                 return;
6713             }
6714             
6715             Roo.callback(o.failure, o.scope, [this, action]);
6716             // show an error message if no failed handler is set..
6717             if (!this.hasListener('actionfailed')) {
6718                 Roo.log("need to add dialog support");
6719                 /*
6720                 Roo.MessageBox.alert("Error",
6721                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6722                         action.result.errorMsg :
6723                         "Saving Failed, please check your entries or try again"
6724                 );
6725                 */
6726             }
6727             
6728             this.fireEvent('actionfailed', this, action);
6729         }
6730         
6731     },
6732     /**
6733      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6734      * @param {String} id The value to search for
6735      * @return Field
6736      */
6737     findField : function(id){
6738         var items = this.getItems();
6739         var field = items.get(id);
6740         if(!field){
6741              items.each(function(f){
6742                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6743                     field = f;
6744                     return false;
6745                 }
6746                 return true;
6747             });
6748         }
6749         return field || null;
6750     },
6751      /**
6752      * Mark fields in this form invalid in bulk.
6753      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6754      * @return {BasicForm} this
6755      */
6756     markInvalid : function(errors){
6757         if(errors instanceof Array){
6758             for(var i = 0, len = errors.length; i < len; i++){
6759                 var fieldError = errors[i];
6760                 var f = this.findField(fieldError.id);
6761                 if(f){
6762                     f.markInvalid(fieldError.msg);
6763                 }
6764             }
6765         }else{
6766             var field, id;
6767             for(id in errors){
6768                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6769                     field.markInvalid(errors[id]);
6770                 }
6771             }
6772         }
6773         //Roo.each(this.childForms || [], function (f) {
6774         //    f.markInvalid(errors);
6775         //});
6776         
6777         return this;
6778     },
6779
6780     /**
6781      * Set values for fields in this form in bulk.
6782      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6783      * @return {BasicForm} this
6784      */
6785     setValues : function(values){
6786         if(values instanceof Array){ // array of objects
6787             for(var i = 0, len = values.length; i < len; i++){
6788                 var v = values[i];
6789                 var f = this.findField(v.id);
6790                 if(f){
6791                     f.setValue(v.value);
6792                     if(this.trackResetOnLoad){
6793                         f.originalValue = f.getValue();
6794                     }
6795                 }
6796             }
6797         }else{ // object hash
6798             var field, id;
6799             for(id in values){
6800                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6801                     
6802                     if (field.setFromData && 
6803                         field.valueField && 
6804                         field.displayField &&
6805                         // combos' with local stores can 
6806                         // be queried via setValue()
6807                         // to set their value..
6808                         (field.store && !field.store.isLocal)
6809                         ) {
6810                         // it's a combo
6811                         var sd = { };
6812                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6813                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6814                         field.setFromData(sd);
6815                         
6816                     } else {
6817                         field.setValue(values[id]);
6818                     }
6819                     
6820                     
6821                     if(this.trackResetOnLoad){
6822                         field.originalValue = field.getValue();
6823                     }
6824                 }
6825             }
6826         }
6827          
6828         //Roo.each(this.childForms || [], function (f) {
6829         //    f.setValues(values);
6830         //});
6831                 
6832         return this;
6833     },
6834
6835     /**
6836      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6837      * they are returned as an array.
6838      * @param {Boolean} asString
6839      * @return {Object}
6840      */
6841     getValues : function(asString){
6842         //if (this.childForms) {
6843             // copy values from the child forms
6844         //    Roo.each(this.childForms, function (f) {
6845         //        this.setValues(f.getValues());
6846         //    }, this);
6847         //}
6848         
6849         
6850         
6851         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6852         if(asString === true){
6853             return fs;
6854         }
6855         return Roo.urlDecode(fs);
6856     },
6857     
6858     /**
6859      * Returns the fields in this form as an object with key/value pairs. 
6860      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6861      * @return {Object}
6862      */
6863     getFieldValues : function(with_hidden)
6864     {
6865         var items = this.getItems();
6866         var ret = {};
6867         items.each(function(f){
6868             if (!f.getName()) {
6869                 return;
6870             }
6871             var v = f.getValue();
6872             if (f.inputType =='radio') {
6873                 if (typeof(ret[f.getName()]) == 'undefined') {
6874                     ret[f.getName()] = ''; // empty..
6875                 }
6876                 
6877                 if (!f.el.dom.checked) {
6878                     return;
6879                     
6880                 }
6881                 v = f.el.dom.value;
6882                 
6883             }
6884             
6885             // not sure if this supported any more..
6886             if ((typeof(v) == 'object') && f.getRawValue) {
6887                 v = f.getRawValue() ; // dates..
6888             }
6889             // combo boxes where name != hiddenName...
6890             if (f.name != f.getName()) {
6891                 ret[f.name] = f.getRawValue();
6892             }
6893             ret[f.getName()] = v;
6894         });
6895         
6896         return ret;
6897     },
6898
6899     /**
6900      * Clears all invalid messages in this form.
6901      * @return {BasicForm} this
6902      */
6903     clearInvalid : function(){
6904         var items = this.getItems();
6905         
6906         items.each(function(f){
6907            f.clearInvalid();
6908         });
6909         
6910         
6911         
6912         return this;
6913     },
6914
6915     /**
6916      * Resets this form.
6917      * @return {BasicForm} this
6918      */
6919     reset : function(){
6920         var items = this.getItems();
6921         items.each(function(f){
6922             f.reset();
6923         });
6924         
6925         Roo.each(this.childForms || [], function (f) {
6926             f.reset();
6927         });
6928        
6929         
6930         return this;
6931     },
6932     getItems : function()
6933     {
6934         var r=new Roo.util.MixedCollection(false, function(o){
6935             return o.id || (o.id = Roo.id());
6936         });
6937         var iter = function(el) {
6938             if (el.inputEl) {
6939                 r.add(el);
6940             }
6941             if (!el.items) {
6942                 return;
6943             }
6944             Roo.each(el.items,function(e) {
6945                 iter(e);
6946             });
6947             
6948             
6949         };
6950         
6951         iter(this);
6952         return r;
6953         
6954         
6955         
6956         
6957     }
6958     
6959 });
6960
6961  
6962 /*
6963  * Based on:
6964  * Ext JS Library 1.1.1
6965  * Copyright(c) 2006-2007, Ext JS, LLC.
6966  *
6967  * Originally Released Under LGPL - original licence link has changed is not relivant.
6968  *
6969  * Fork - LGPL
6970  * <script type="text/javascript">
6971  */
6972 /**
6973  * @class Roo.form.VTypes
6974  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6975  * @singleton
6976  */
6977 Roo.form.VTypes = function(){
6978     // closure these in so they are only created once.
6979     var alpha = /^[a-zA-Z_]+$/;
6980     var alphanum = /^[a-zA-Z0-9_]+$/;
6981     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6982     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6983
6984     // All these messages and functions are configurable
6985     return {
6986         /**
6987          * The function used to validate email addresses
6988          * @param {String} value The email address
6989          */
6990         'email' : function(v){
6991             return email.test(v);
6992         },
6993         /**
6994          * The error text to display when the email validation function returns false
6995          * @type String
6996          */
6997         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6998         /**
6999          * The keystroke filter mask to be applied on email input
7000          * @type RegExp
7001          */
7002         'emailMask' : /[a-z0-9_\.\-@]/i,
7003
7004         /**
7005          * The function used to validate URLs
7006          * @param {String} value The URL
7007          */
7008         'url' : function(v){
7009             return url.test(v);
7010         },
7011         /**
7012          * The error text to display when the url validation function returns false
7013          * @type String
7014          */
7015         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7016         
7017         /**
7018          * The function used to validate alpha values
7019          * @param {String} value The value
7020          */
7021         'alpha' : function(v){
7022             return alpha.test(v);
7023         },
7024         /**
7025          * The error text to display when the alpha validation function returns false
7026          * @type String
7027          */
7028         'alphaText' : 'This field should only contain letters and _',
7029         /**
7030          * The keystroke filter mask to be applied on alpha input
7031          * @type RegExp
7032          */
7033         'alphaMask' : /[a-z_]/i,
7034
7035         /**
7036          * The function used to validate alphanumeric values
7037          * @param {String} value The value
7038          */
7039         'alphanum' : function(v){
7040             return alphanum.test(v);
7041         },
7042         /**
7043          * The error text to display when the alphanumeric validation function returns false
7044          * @type String
7045          */
7046         'alphanumText' : 'This field should only contain letters, numbers and _',
7047         /**
7048          * The keystroke filter mask to be applied on alphanumeric input
7049          * @type RegExp
7050          */
7051         'alphanumMask' : /[a-z0-9_]/i
7052     };
7053 }();/*
7054  * - LGPL
7055  *
7056  * Input
7057  * 
7058  */
7059
7060 /**
7061  * @class Roo.bootstrap.Input
7062  * @extends Roo.bootstrap.Component
7063  * Bootstrap Input class
7064  * @cfg {Boolean} disabled is it disabled
7065  * @cfg {String} fieldLabel - the label associated
7066  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7067  * @cfg {String} name name of the input
7068  * @cfg {string} fieldLabel - the label associated
7069  * @cfg {string}  inputType - input / file submit ...
7070  * @cfg {string} placeholder - placeholder to put in text.
7071  * @cfg {string}  before - input group add on before
7072  * @cfg {string} after - input group add on after
7073  * @cfg {string} size - (lg|sm) or leave empty..
7074  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7075  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7076  * @cfg {Number} md colspan out of 12 for computer-sized screens
7077  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7078  * @cfg {string} value default value of the input
7079  * @cfg {Number} labelWidth set the width of label (0-12)
7080  * @cfg {String} labelAlign (top|left)
7081  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7082  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7083
7084  * @cfg {String} align (left|center|right) Default left
7085  * 
7086  * 
7087  * 
7088  * @constructor
7089  * Create a new Input
7090  * @param {Object} config The config object
7091  */
7092
7093 Roo.bootstrap.Input = function(config){
7094     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7095    
7096         this.addEvents({
7097             /**
7098              * @event focus
7099              * Fires when this field receives input focus.
7100              * @param {Roo.form.Field} this
7101              */
7102             focus : true,
7103             /**
7104              * @event blur
7105              * Fires when this field loses input focus.
7106              * @param {Roo.form.Field} this
7107              */
7108             blur : true,
7109             /**
7110              * @event specialkey
7111              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7112              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7113              * @param {Roo.form.Field} this
7114              * @param {Roo.EventObject} e The event object
7115              */
7116             specialkey : true,
7117             /**
7118              * @event change
7119              * Fires just before the field blurs if the field value has changed.
7120              * @param {Roo.form.Field} this
7121              * @param {Mixed} newValue The new value
7122              * @param {Mixed} oldValue The original value
7123              */
7124             change : true,
7125             /**
7126              * @event invalid
7127              * Fires after the field has been marked as invalid.
7128              * @param {Roo.form.Field} this
7129              * @param {String} msg The validation message
7130              */
7131             invalid : true,
7132             /**
7133              * @event valid
7134              * Fires after the field has been validated with no errors.
7135              * @param {Roo.form.Field} this
7136              */
7137             valid : true,
7138              /**
7139              * @event keyup
7140              * Fires after the key up
7141              * @param {Roo.form.Field} this
7142              * @param {Roo.EventObject}  e The event Object
7143              */
7144             keyup : true
7145         });
7146 };
7147
7148 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7149      /**
7150      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7151       automatic validation (defaults to "keyup").
7152      */
7153     validationEvent : "keyup",
7154      /**
7155      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7156      */
7157     validateOnBlur : true,
7158     /**
7159      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7160      */
7161     validationDelay : 250,
7162      /**
7163      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7164      */
7165     focusClass : "x-form-focus",  // not needed???
7166     
7167        
7168     /**
7169      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7170      */
7171     invalidClass : "has-warning",
7172     
7173     /**
7174      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7175      */
7176     validClass : "has-success",
7177     
7178     /**
7179      * @cfg {Boolean} hasFeedback (true|false) default true
7180      */
7181     hasFeedback : true,
7182     
7183     /**
7184      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7185      */
7186     invalidFeedbackClass : "glyphicon-warning-sign",
7187     
7188     /**
7189      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7190      */
7191     validFeedbackClass : "glyphicon-ok",
7192     
7193     /**
7194      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7195      */
7196     selectOnFocus : false,
7197     
7198      /**
7199      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7200      */
7201     maskRe : null,
7202        /**
7203      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7204      */
7205     vtype : null,
7206     
7207       /**
7208      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7209      */
7210     disableKeyFilter : false,
7211     
7212        /**
7213      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7214      */
7215     disabled : false,
7216      /**
7217      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7218      */
7219     allowBlank : true,
7220     /**
7221      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7222      */
7223     blankText : "This field is required",
7224     
7225      /**
7226      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7227      */
7228     minLength : 0,
7229     /**
7230      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7231      */
7232     maxLength : Number.MAX_VALUE,
7233     /**
7234      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7235      */
7236     minLengthText : "The minimum length for this field is {0}",
7237     /**
7238      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7239      */
7240     maxLengthText : "The maximum length for this field is {0}",
7241   
7242     
7243     /**
7244      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7245      * If available, this function will be called only after the basic validators all return true, and will be passed the
7246      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7247      */
7248     validator : null,
7249     /**
7250      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7251      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7252      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7253      */
7254     regex : null,
7255     /**
7256      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7257      */
7258     regexText : "",
7259     
7260     autocomplete: false,
7261     
7262     
7263     fieldLabel : '',
7264     inputType : 'text',
7265     
7266     name : false,
7267     placeholder: false,
7268     before : false,
7269     after : false,
7270     size : false,
7271     hasFocus : false,
7272     preventMark: false,
7273     isFormField : true,
7274     value : '',
7275     labelWidth : 2,
7276     labelAlign : false,
7277     readOnly : false,
7278     align : false,
7279     formatedValue : false,
7280     
7281     parentLabelAlign : function()
7282     {
7283         var parent = this;
7284         while (parent.parent()) {
7285             parent = parent.parent();
7286             if (typeof(parent.labelAlign) !='undefined') {
7287                 return parent.labelAlign;
7288             }
7289         }
7290         return 'left';
7291         
7292     },
7293     
7294     getAutoCreate : function(){
7295         
7296         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7297         
7298         var id = Roo.id();
7299         
7300         var cfg = {};
7301         
7302         if(this.inputType != 'hidden'){
7303             cfg.cls = 'form-group' //input-group
7304         }
7305         
7306         var input =  {
7307             tag: 'input',
7308             id : id,
7309             type : this.inputType,
7310             value : this.value,
7311             cls : 'form-control',
7312             placeholder : this.placeholder || '',
7313             autocomplete : this.autocomplete || 'new-password'
7314         };
7315         
7316         
7317         if(this.align){
7318             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7319         }
7320         
7321         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7322             input.maxLength = this.maxLength;
7323         }
7324         
7325         if (this.disabled) {
7326             input.disabled=true;
7327         }
7328         
7329         if (this.readOnly) {
7330             input.readonly=true;
7331         }
7332         
7333         if (this.name) {
7334             input.name = this.name;
7335         }
7336         if (this.size) {
7337             input.cls += ' input-' + this.size;
7338         }
7339         var settings=this;
7340         ['xs','sm','md','lg'].map(function(size){
7341             if (settings[size]) {
7342                 cfg.cls += ' col-' + size + '-' + settings[size];
7343             }
7344         });
7345         
7346         var inputblock = input;
7347         
7348         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7349             
7350             var feedback = {
7351                 tag: 'span',
7352                 cls: 'glyphicon form-control-feedback'
7353             };
7354
7355             inputblock = {
7356                 cls : 'has-feedback',
7357                 cn :  [
7358                     input,
7359                     feedback
7360                 ] 
7361             };  
7362         }
7363          
7364 //        var inputblock = input;
7365         
7366         if (this.before || this.after) {
7367             
7368             inputblock = {
7369                 cls : 'input-group',
7370                 cn :  [] 
7371             };
7372             
7373             if (this.before && typeof(this.before) == 'string') {
7374                 
7375                 inputblock.cn.push({
7376                     tag :'span',
7377                     cls : 'roo-input-before input-group-addon',
7378                     html : this.before
7379                 });
7380             }
7381             if (this.before && typeof(this.before) == 'object') {
7382                 this.before = Roo.factory(this.before);
7383                 Roo.log(this.before);
7384                 inputblock.cn.push({
7385                     tag :'span',
7386                     cls : 'roo-input-before input-group-' +
7387                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7388                 });
7389             }
7390             
7391             inputblock.cn.push(input);
7392             
7393             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7394                 inputblock.cls += ' has-feedback';
7395                 inputblock.cn.push(feedback);
7396             }
7397             
7398             if (this.after && typeof(this.after) == 'string') {
7399                 inputblock.cn.push({
7400                     tag :'span',
7401                     cls : 'roo-input-after input-group-addon',
7402                     html : this.after
7403                 });
7404             }
7405             if (this.after && typeof(this.after) == 'object') {
7406                 this.after = Roo.factory(this.after);
7407                 Roo.log(this.after);
7408                 inputblock.cn.push({
7409                     tag :'span',
7410                     cls : 'roo-input-after input-group-' +
7411                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7412                 });
7413             }
7414         };
7415         
7416         if (align ==='left' && this.fieldLabel.length) {
7417                 Roo.log("left and has label");
7418                 cfg.cn = [
7419                     
7420                     {
7421                         tag: 'label',
7422                         'for' :  id,
7423                         cls : 'control-label col-sm-' + this.labelWidth,
7424                         html : this.fieldLabel
7425                         
7426                     },
7427                     {
7428                         cls : "col-sm-" + (12 - this.labelWidth), 
7429                         cn: [
7430                             inputblock
7431                         ]
7432                     }
7433                     
7434                 ];
7435         } else if ( this.fieldLabel.length) {
7436                 Roo.log(" label");
7437                  cfg.cn = [
7438                    
7439                     {
7440                         tag: 'label',
7441                         //cls : 'input-group-addon',
7442                         html : this.fieldLabel
7443                         
7444                     },
7445                     
7446                     inputblock
7447                     
7448                 ];
7449
7450         } else {
7451             
7452                 Roo.log(" no label && no align");
7453                 cfg.cn = [
7454                     
7455                         inputblock
7456                     
7457                 ];
7458                 
7459                 
7460         };
7461         Roo.log('input-parentType: ' + this.parentType);
7462         
7463         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7464            cfg.cls += ' navbar-form';
7465            Roo.log(cfg);
7466         }
7467         
7468         return cfg;
7469         
7470     },
7471     /**
7472      * return the real input element.
7473      */
7474     inputEl: function ()
7475     {
7476         return this.el.select('input.form-control',true).first();
7477     },
7478     
7479     tooltipEl : function()
7480     {
7481         return this.inputEl();
7482     },
7483     
7484     setDisabled : function(v)
7485     {
7486         var i  = this.inputEl().dom;
7487         if (!v) {
7488             i.removeAttribute('disabled');
7489             return;
7490             
7491         }
7492         i.setAttribute('disabled','true');
7493     },
7494     initEvents : function()
7495     {
7496           
7497         this.inputEl().on("keydown" , this.fireKey,  this);
7498         this.inputEl().on("focus", this.onFocus,  this);
7499         this.inputEl().on("blur", this.onBlur,  this);
7500         
7501         this.inputEl().relayEvent('keyup', this);
7502
7503         // reference to original value for reset
7504         this.originalValue = this.getValue();
7505         //Roo.form.TextField.superclass.initEvents.call(this);
7506         if(this.validationEvent == 'keyup'){
7507             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7508             this.inputEl().on('keyup', this.filterValidation, this);
7509         }
7510         else if(this.validationEvent !== false){
7511             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7512         }
7513         
7514         if(this.selectOnFocus){
7515             this.on("focus", this.preFocus, this);
7516             
7517         }
7518         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7519             this.inputEl().on("keypress", this.filterKeys, this);
7520         }
7521        /* if(this.grow){
7522             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7523             this.el.on("click", this.autoSize,  this);
7524         }
7525         */
7526         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7527             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7528         }
7529         
7530         if (typeof(this.before) == 'object') {
7531             this.before.render(this.el.select('.roo-input-before',true).first());
7532         }
7533         if (typeof(this.after) == 'object') {
7534             this.after.render(this.el.select('.roo-input-after',true).first());
7535         }
7536         
7537         
7538     },
7539     filterValidation : function(e){
7540         if(!e.isNavKeyPress()){
7541             this.validationTask.delay(this.validationDelay);
7542         }
7543     },
7544      /**
7545      * Validates the field value
7546      * @return {Boolean} True if the value is valid, else false
7547      */
7548     validate : function(){
7549         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7550         if(this.disabled || this.validateValue(this.getRawValue())){
7551             this.markValid();
7552             return true;
7553         }
7554         
7555         this.markInvalid();
7556         return false;
7557     },
7558     
7559     
7560     /**
7561      * Validates a value according to the field's validation rules and marks the field as invalid
7562      * if the validation fails
7563      * @param {Mixed} value The value to validate
7564      * @return {Boolean} True if the value is valid, else false
7565      */
7566     validateValue : function(value){
7567         if(value.length < 1)  { // if it's blank
7568             if(this.allowBlank){
7569                 return true;
7570             }
7571             return false;
7572         }
7573         
7574         if(value.length < this.minLength){
7575             return false;
7576         }
7577         if(value.length > this.maxLength){
7578             return false;
7579         }
7580         if(this.vtype){
7581             var vt = Roo.form.VTypes;
7582             if(!vt[this.vtype](value, this)){
7583                 return false;
7584             }
7585         }
7586         if(typeof this.validator == "function"){
7587             var msg = this.validator(value);
7588             if(msg !== true){
7589                 return false;
7590             }
7591         }
7592         
7593         if(this.regex && !this.regex.test(value)){
7594             return false;
7595         }
7596         
7597         return true;
7598     },
7599
7600     
7601     
7602      // private
7603     fireKey : function(e){
7604         //Roo.log('field ' + e.getKey());
7605         if(e.isNavKeyPress()){
7606             this.fireEvent("specialkey", this, e);
7607         }
7608     },
7609     focus : function (selectText){
7610         if(this.rendered){
7611             this.inputEl().focus();
7612             if(selectText === true){
7613                 this.inputEl().dom.select();
7614             }
7615         }
7616         return this;
7617     } ,
7618     
7619     onFocus : function(){
7620         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7621            // this.el.addClass(this.focusClass);
7622         }
7623         if(!this.hasFocus){
7624             this.hasFocus = true;
7625             this.startValue = this.getValue();
7626             this.fireEvent("focus", this);
7627         }
7628     },
7629     
7630     beforeBlur : Roo.emptyFn,
7631
7632     
7633     // private
7634     onBlur : function(){
7635         this.beforeBlur();
7636         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7637             //this.el.removeClass(this.focusClass);
7638         }
7639         this.hasFocus = false;
7640         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7641             this.validate();
7642         }
7643         var v = this.getValue();
7644         if(String(v) !== String(this.startValue)){
7645             this.fireEvent('change', this, v, this.startValue);
7646         }
7647         this.fireEvent("blur", this);
7648     },
7649     
7650     /**
7651      * Resets the current field value to the originally loaded value and clears any validation messages
7652      */
7653     reset : function(){
7654         this.setValue(this.originalValue);
7655         this.validate();
7656     },
7657      /**
7658      * Returns the name of the field
7659      * @return {Mixed} name The name field
7660      */
7661     getName: function(){
7662         return this.name;
7663     },
7664      /**
7665      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7666      * @return {Mixed} value The field value
7667      */
7668     getValue : function(){
7669         
7670         var v = this.inputEl().getValue();
7671         
7672         return v;
7673     },
7674     /**
7675      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7676      * @return {Mixed} value The field value
7677      */
7678     getRawValue : function(){
7679         var v = this.inputEl().getValue();
7680         
7681         return v;
7682     },
7683     
7684     /**
7685      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7686      * @param {Mixed} value The value to set
7687      */
7688     setRawValue : function(v){
7689         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7690     },
7691     
7692     selectText : function(start, end){
7693         var v = this.getRawValue();
7694         if(v.length > 0){
7695             start = start === undefined ? 0 : start;
7696             end = end === undefined ? v.length : end;
7697             var d = this.inputEl().dom;
7698             if(d.setSelectionRange){
7699                 d.setSelectionRange(start, end);
7700             }else if(d.createTextRange){
7701                 var range = d.createTextRange();
7702                 range.moveStart("character", start);
7703                 range.moveEnd("character", v.length-end);
7704                 range.select();
7705             }
7706         }
7707     },
7708     
7709     /**
7710      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7711      * @param {Mixed} value The value to set
7712      */
7713     setValue : function(v){
7714         this.value = v;
7715         if(this.rendered){
7716             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7717             this.validate();
7718         }
7719     },
7720     
7721     /*
7722     processValue : function(value){
7723         if(this.stripCharsRe){
7724             var newValue = value.replace(this.stripCharsRe, '');
7725             if(newValue !== value){
7726                 this.setRawValue(newValue);
7727                 return newValue;
7728             }
7729         }
7730         return value;
7731     },
7732   */
7733     preFocus : function(){
7734         
7735         if(this.selectOnFocus){
7736             this.inputEl().dom.select();
7737         }
7738     },
7739     filterKeys : function(e){
7740         var k = e.getKey();
7741         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7742             return;
7743         }
7744         var c = e.getCharCode(), cc = String.fromCharCode(c);
7745         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7746             return;
7747         }
7748         if(!this.maskRe.test(cc)){
7749             e.stopEvent();
7750         }
7751     },
7752      /**
7753      * Clear any invalid styles/messages for this field
7754      */
7755     clearInvalid : function(){
7756         
7757         if(!this.el || this.preventMark){ // not rendered
7758             return;
7759         }
7760         this.el.removeClass(this.invalidClass);
7761         
7762         this.fireEvent('valid', this);
7763     },
7764     
7765      /**
7766      * Mark this field as valid
7767      */
7768     markValid : function(){
7769         if(!this.el  || this.preventMark){ // not rendered
7770             return;
7771         }
7772         
7773         this.el.removeClass([this.invalidClass, this.validClass]);
7774         
7775         if(this.disabled || this.allowBlank){
7776             return;
7777         }
7778         
7779         this.el.addClass(this.validClass);
7780         
7781         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7782             
7783             var feedback = this.el.select('.form-control-feedback', true).first();
7784             
7785             if(feedback){
7786                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7787                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7788             }
7789             
7790         }
7791         
7792         this.fireEvent('valid', this);
7793     },
7794     
7795      /**
7796      * Mark this field as invalid
7797      * @param {String} msg The validation message
7798      */
7799     markInvalid : function(msg){
7800         if(!this.el  || this.preventMark){ // not rendered
7801             return;
7802         }
7803         
7804         this.el.removeClass([this.invalidClass, this.validClass]);
7805         
7806         if(this.disabled || this.allowBlank){
7807             return;
7808         }
7809         
7810         this.el.addClass(this.invalidClass);
7811         
7812         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7813             
7814             var feedback = this.el.select('.form-control-feedback', true).first();
7815             
7816             if(feedback){
7817                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7818                 
7819                 if(this.getValue().length){
7820                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7821                 }
7822                 
7823             }
7824             
7825         }
7826         
7827         this.fireEvent('invalid', this, msg);
7828     },
7829     // private
7830     SafariOnKeyDown : function(event)
7831     {
7832         // this is a workaround for a password hang bug on chrome/ webkit.
7833         
7834         var isSelectAll = false;
7835         
7836         if(this.inputEl().dom.selectionEnd > 0){
7837             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7838         }
7839         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7840             event.preventDefault();
7841             this.setValue('');
7842             return;
7843         }
7844         
7845         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7846             
7847             event.preventDefault();
7848             // this is very hacky as keydown always get's upper case.
7849             //
7850             var cc = String.fromCharCode(event.getCharCode());
7851             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7852             
7853         }
7854     },
7855     adjustWidth : function(tag, w){
7856         tag = tag.toLowerCase();
7857         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7858             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7859                 if(tag == 'input'){
7860                     return w + 2;
7861                 }
7862                 if(tag == 'textarea'){
7863                     return w-2;
7864                 }
7865             }else if(Roo.isOpera){
7866                 if(tag == 'input'){
7867                     return w + 2;
7868                 }
7869                 if(tag == 'textarea'){
7870                     return w-2;
7871                 }
7872             }
7873         }
7874         return w;
7875     }
7876     
7877 });
7878
7879  
7880 /*
7881  * - LGPL
7882  *
7883  * Input
7884  * 
7885  */
7886
7887 /**
7888  * @class Roo.bootstrap.TextArea
7889  * @extends Roo.bootstrap.Input
7890  * Bootstrap TextArea class
7891  * @cfg {Number} cols Specifies the visible width of a text area
7892  * @cfg {Number} rows Specifies the visible number of lines in a text area
7893  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7894  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7895  * @cfg {string} html text
7896  * 
7897  * @constructor
7898  * Create a new TextArea
7899  * @param {Object} config The config object
7900  */
7901
7902 Roo.bootstrap.TextArea = function(config){
7903     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7904    
7905 };
7906
7907 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7908      
7909     cols : false,
7910     rows : 5,
7911     readOnly : false,
7912     warp : 'soft',
7913     resize : false,
7914     value: false,
7915     html: false,
7916     
7917     getAutoCreate : function(){
7918         
7919         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7920         
7921         var id = Roo.id();
7922         
7923         var cfg = {};
7924         
7925         var input =  {
7926             tag: 'textarea',
7927             id : id,
7928             warp : this.warp,
7929             rows : this.rows,
7930             value : this.value || '',
7931             html: this.html || '',
7932             cls : 'form-control',
7933             placeholder : this.placeholder || '' 
7934             
7935         };
7936         
7937         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7938             input.maxLength = this.maxLength;
7939         }
7940         
7941         if(this.resize){
7942             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7943         }
7944         
7945         if(this.cols){
7946             input.cols = this.cols;
7947         }
7948         
7949         if (this.readOnly) {
7950             input.readonly = true;
7951         }
7952         
7953         if (this.name) {
7954             input.name = this.name;
7955         }
7956         
7957         if (this.size) {
7958             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7959         }
7960         
7961         var settings=this;
7962         ['xs','sm','md','lg'].map(function(size){
7963             if (settings[size]) {
7964                 cfg.cls += ' col-' + size + '-' + settings[size];
7965             }
7966         });
7967         
7968         var inputblock = input;
7969         
7970         if(this.hasFeedback && !this.allowBlank){
7971             
7972             var feedback = {
7973                 tag: 'span',
7974                 cls: 'glyphicon form-control-feedback'
7975             };
7976
7977             inputblock = {
7978                 cls : 'has-feedback',
7979                 cn :  [
7980                     input,
7981                     feedback
7982                 ] 
7983             };  
7984         }
7985         
7986         
7987         if (this.before || this.after) {
7988             
7989             inputblock = {
7990                 cls : 'input-group',
7991                 cn :  [] 
7992             };
7993             if (this.before) {
7994                 inputblock.cn.push({
7995                     tag :'span',
7996                     cls : 'input-group-addon',
7997                     html : this.before
7998                 });
7999             }
8000             
8001             inputblock.cn.push(input);
8002             
8003             if(this.hasFeedback && !this.allowBlank){
8004                 inputblock.cls += ' has-feedback';
8005                 inputblock.cn.push(feedback);
8006             }
8007             
8008             if (this.after) {
8009                 inputblock.cn.push({
8010                     tag :'span',
8011                     cls : 'input-group-addon',
8012                     html : this.after
8013                 });
8014             }
8015             
8016         }
8017         
8018         if (align ==='left' && this.fieldLabel.length) {
8019                 Roo.log("left and has label");
8020                 cfg.cn = [
8021                     
8022                     {
8023                         tag: 'label',
8024                         'for' :  id,
8025                         cls : 'control-label col-sm-' + this.labelWidth,
8026                         html : this.fieldLabel
8027                         
8028                     },
8029                     {
8030                         cls : "col-sm-" + (12 - this.labelWidth), 
8031                         cn: [
8032                             inputblock
8033                         ]
8034                     }
8035                     
8036                 ];
8037         } else if ( this.fieldLabel.length) {
8038                 Roo.log(" label");
8039                  cfg.cn = [
8040                    
8041                     {
8042                         tag: 'label',
8043                         //cls : 'input-group-addon',
8044                         html : this.fieldLabel
8045                         
8046                     },
8047                     
8048                     inputblock
8049                     
8050                 ];
8051
8052         } else {
8053             
8054                    Roo.log(" no label && no align");
8055                 cfg.cn = [
8056                     
8057                         inputblock
8058                     
8059                 ];
8060                 
8061                 
8062         }
8063         
8064         if (this.disabled) {
8065             input.disabled=true;
8066         }
8067         
8068         return cfg;
8069         
8070     },
8071     /**
8072      * return the real textarea element.
8073      */
8074     inputEl: function ()
8075     {
8076         return this.el.select('textarea.form-control',true).first();
8077     }
8078 });
8079
8080  
8081 /*
8082  * - LGPL
8083  *
8084  * trigger field - base class for combo..
8085  * 
8086  */
8087  
8088 /**
8089  * @class Roo.bootstrap.TriggerField
8090  * @extends Roo.bootstrap.Input
8091  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8092  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8093  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8094  * for which you can provide a custom implementation.  For example:
8095  * <pre><code>
8096 var trigger = new Roo.bootstrap.TriggerField();
8097 trigger.onTriggerClick = myTriggerFn;
8098 trigger.applyTo('my-field');
8099 </code></pre>
8100  *
8101  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8102  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8103  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8104  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8105  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8106
8107  * @constructor
8108  * Create a new TriggerField.
8109  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8110  * to the base TextField)
8111  */
8112 Roo.bootstrap.TriggerField = function(config){
8113     this.mimicing = false;
8114     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8115 };
8116
8117 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8118     /**
8119      * @cfg {String} triggerClass A CSS class to apply to the trigger
8120      */
8121      /**
8122      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8123      */
8124     hideTrigger:false,
8125
8126     /** @cfg {Boolean} grow @hide */
8127     /** @cfg {Number} growMin @hide */
8128     /** @cfg {Number} growMax @hide */
8129
8130     /**
8131      * @hide 
8132      * @method
8133      */
8134     autoSize: Roo.emptyFn,
8135     // private
8136     monitorTab : true,
8137     // private
8138     deferHeight : true,
8139
8140     
8141     actionMode : 'wrap',
8142     
8143     caret : false,
8144     
8145     
8146     getAutoCreate : function(){
8147        
8148         var align = this.labelAlign || this.parentLabelAlign();
8149         
8150         var id = Roo.id();
8151         
8152         var cfg = {
8153             cls: 'form-group' //input-group
8154         };
8155         
8156         
8157         var input =  {
8158             tag: 'input',
8159             id : id,
8160             type : this.inputType,
8161             cls : 'form-control',
8162             autocomplete: 'new-password',
8163             placeholder : this.placeholder || '' 
8164             
8165         };
8166         if (this.name) {
8167             input.name = this.name;
8168         }
8169         if (this.size) {
8170             input.cls += ' input-' + this.size;
8171         }
8172         
8173         if (this.disabled) {
8174             input.disabled=true;
8175         }
8176         
8177         var inputblock = input;
8178         
8179         if(this.hasFeedback && !this.allowBlank){
8180             
8181             var feedback = {
8182                 tag: 'span',
8183                 cls: 'glyphicon form-control-feedback'
8184             };
8185
8186             inputblock = {
8187                 cls : 'has-feedback',
8188                 cn :  [
8189                     input,
8190                     feedback
8191                 ] 
8192             };  
8193         }
8194         
8195         if (this.before || this.after) {
8196             
8197             inputblock = {
8198                 cls : 'input-group',
8199                 cn :  [] 
8200             };
8201             if (this.before) {
8202                 inputblock.cn.push({
8203                     tag :'span',
8204                     cls : 'input-group-addon',
8205                     html : this.before
8206                 });
8207             }
8208             
8209             inputblock.cn.push(input);
8210             
8211             if(this.hasFeedback && !this.allowBlank){
8212                 inputblock.cls += ' has-feedback';
8213                 inputblock.cn.push(feedback);
8214             }
8215             
8216             if (this.after) {
8217                 inputblock.cn.push({
8218                     tag :'span',
8219                     cls : 'input-group-addon',
8220                     html : this.after
8221                 });
8222             }
8223             
8224         };
8225         
8226         var box = {
8227             tag: 'div',
8228             cn: [
8229                 {
8230                     tag: 'input',
8231                     type : 'hidden',
8232                     cls: 'form-hidden-field'
8233                 },
8234                 inputblock
8235             ]
8236             
8237         };
8238         
8239         if(this.multiple){
8240             Roo.log('multiple');
8241             
8242             box = {
8243                 tag: 'div',
8244                 cn: [
8245                     {
8246                         tag: 'input',
8247                         type : 'hidden',
8248                         cls: 'form-hidden-field'
8249                     },
8250                     {
8251                         tag: 'ul',
8252                         cls: 'select2-choices',
8253                         cn:[
8254                             {
8255                                 tag: 'li',
8256                                 cls: 'select2-search-field',
8257                                 cn: [
8258
8259                                     inputblock
8260                                 ]
8261                             }
8262                         ]
8263                     }
8264                 ]
8265             }
8266         };
8267         
8268         var combobox = {
8269             cls: 'select2-container input-group',
8270             cn: [
8271                 box
8272 //                {
8273 //                    tag: 'ul',
8274 //                    cls: 'typeahead typeahead-long dropdown-menu',
8275 //                    style: 'display:none'
8276 //                }
8277             ]
8278         };
8279         
8280         if(!this.multiple && this.showToggleBtn){
8281             
8282             var caret = {
8283                         tag: 'span',
8284                         cls: 'caret'
8285              };
8286             if (this.caret != false) {
8287                 caret = {
8288                      tag: 'i',
8289                      cls: 'fa fa-' + this.caret
8290                 };
8291                 
8292             }
8293             
8294             combobox.cn.push({
8295                 tag :'span',
8296                 cls : 'input-group-addon btn dropdown-toggle',
8297                 cn : [
8298                     caret,
8299                     {
8300                         tag: 'span',
8301                         cls: 'combobox-clear',
8302                         cn  : [
8303                             {
8304                                 tag : 'i',
8305                                 cls: 'icon-remove'
8306                             }
8307                         ]
8308                     }
8309                 ]
8310
8311             })
8312         }
8313         
8314         if(this.multiple){
8315             combobox.cls += ' select2-container-multi';
8316         }
8317         
8318         if (align ==='left' && this.fieldLabel.length) {
8319             
8320                 Roo.log("left and has label");
8321                 cfg.cn = [
8322                     
8323                     {
8324                         tag: 'label',
8325                         'for' :  id,
8326                         cls : 'control-label col-sm-' + this.labelWidth,
8327                         html : this.fieldLabel
8328                         
8329                     },
8330                     {
8331                         cls : "col-sm-" + (12 - this.labelWidth), 
8332                         cn: [
8333                             combobox
8334                         ]
8335                     }
8336                     
8337                 ];
8338         } else if ( this.fieldLabel.length) {
8339                 Roo.log(" label");
8340                  cfg.cn = [
8341                    
8342                     {
8343                         tag: 'label',
8344                         //cls : 'input-group-addon',
8345                         html : this.fieldLabel
8346                         
8347                     },
8348                     
8349                     combobox
8350                     
8351                 ];
8352
8353         } else {
8354             
8355                 Roo.log(" no label && no align");
8356                 cfg = combobox
8357                      
8358                 
8359         }
8360          
8361         var settings=this;
8362         ['xs','sm','md','lg'].map(function(size){
8363             if (settings[size]) {
8364                 cfg.cls += ' col-' + size + '-' + settings[size];
8365             }
8366         });
8367         
8368         return cfg;
8369         
8370     },
8371     
8372     
8373     
8374     // private
8375     onResize : function(w, h){
8376 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8377 //        if(typeof w == 'number'){
8378 //            var x = w - this.trigger.getWidth();
8379 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8380 //            this.trigger.setStyle('left', x+'px');
8381 //        }
8382     },
8383
8384     // private
8385     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8386
8387     // private
8388     getResizeEl : function(){
8389         return this.inputEl();
8390     },
8391
8392     // private
8393     getPositionEl : function(){
8394         return this.inputEl();
8395     },
8396
8397     // private
8398     alignErrorIcon : function(){
8399         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8400     },
8401
8402     // private
8403     initEvents : function(){
8404         
8405         this.createList();
8406         
8407         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8408         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8409         if(!this.multiple && this.showToggleBtn){
8410             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8411             if(this.hideTrigger){
8412                 this.trigger.setDisplayed(false);
8413             }
8414             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8415         }
8416         
8417         if(this.multiple){
8418             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8419         }
8420         
8421         //this.trigger.addClassOnOver('x-form-trigger-over');
8422         //this.trigger.addClassOnClick('x-form-trigger-click');
8423         
8424         //if(!this.width){
8425         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8426         //}
8427     },
8428     
8429     createList : function()
8430     {
8431         this.list = Roo.get(document.body).createChild({
8432             tag: 'ul',
8433             cls: 'typeahead typeahead-long dropdown-menu',
8434             style: 'display:none'
8435         });
8436         
8437         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8438         
8439     },
8440
8441     // private
8442     initTrigger : function(){
8443        
8444     },
8445
8446     // private
8447     onDestroy : function(){
8448         if(this.trigger){
8449             this.trigger.removeAllListeners();
8450           //  this.trigger.remove();
8451         }
8452         //if(this.wrap){
8453         //    this.wrap.remove();
8454         //}
8455         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8456     },
8457
8458     // private
8459     onFocus : function(){
8460         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8461         /*
8462         if(!this.mimicing){
8463             this.wrap.addClass('x-trigger-wrap-focus');
8464             this.mimicing = true;
8465             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8466             if(this.monitorTab){
8467                 this.el.on("keydown", this.checkTab, this);
8468             }
8469         }
8470         */
8471     },
8472
8473     // private
8474     checkTab : function(e){
8475         if(e.getKey() == e.TAB){
8476             this.triggerBlur();
8477         }
8478     },
8479
8480     // private
8481     onBlur : function(){
8482         // do nothing
8483     },
8484
8485     // private
8486     mimicBlur : function(e, t){
8487         /*
8488         if(!this.wrap.contains(t) && this.validateBlur()){
8489             this.triggerBlur();
8490         }
8491         */
8492     },
8493
8494     // private
8495     triggerBlur : function(){
8496         this.mimicing = false;
8497         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8498         if(this.monitorTab){
8499             this.el.un("keydown", this.checkTab, this);
8500         }
8501         //this.wrap.removeClass('x-trigger-wrap-focus');
8502         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8503     },
8504
8505     // private
8506     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8507     validateBlur : function(e, t){
8508         return true;
8509     },
8510
8511     // private
8512     onDisable : function(){
8513         this.inputEl().dom.disabled = true;
8514         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8515         //if(this.wrap){
8516         //    this.wrap.addClass('x-item-disabled');
8517         //}
8518     },
8519
8520     // private
8521     onEnable : function(){
8522         this.inputEl().dom.disabled = false;
8523         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8524         //if(this.wrap){
8525         //    this.el.removeClass('x-item-disabled');
8526         //}
8527     },
8528
8529     // private
8530     onShow : function(){
8531         var ae = this.getActionEl();
8532         
8533         if(ae){
8534             ae.dom.style.display = '';
8535             ae.dom.style.visibility = 'visible';
8536         }
8537     },
8538
8539     // private
8540     
8541     onHide : function(){
8542         var ae = this.getActionEl();
8543         ae.dom.style.display = 'none';
8544     },
8545
8546     /**
8547      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8548      * by an implementing function.
8549      * @method
8550      * @param {EventObject} e
8551      */
8552     onTriggerClick : Roo.emptyFn
8553 });
8554  /*
8555  * Based on:
8556  * Ext JS Library 1.1.1
8557  * Copyright(c) 2006-2007, Ext JS, LLC.
8558  *
8559  * Originally Released Under LGPL - original licence link has changed is not relivant.
8560  *
8561  * Fork - LGPL
8562  * <script type="text/javascript">
8563  */
8564
8565
8566 /**
8567  * @class Roo.data.SortTypes
8568  * @singleton
8569  * Defines the default sorting (casting?) comparison functions used when sorting data.
8570  */
8571 Roo.data.SortTypes = {
8572     /**
8573      * Default sort that does nothing
8574      * @param {Mixed} s The value being converted
8575      * @return {Mixed} The comparison value
8576      */
8577     none : function(s){
8578         return s;
8579     },
8580     
8581     /**
8582      * The regular expression used to strip tags
8583      * @type {RegExp}
8584      * @property
8585      */
8586     stripTagsRE : /<\/?[^>]+>/gi,
8587     
8588     /**
8589      * Strips all HTML tags to sort on text only
8590      * @param {Mixed} s The value being converted
8591      * @return {String} The comparison value
8592      */
8593     asText : function(s){
8594         return String(s).replace(this.stripTagsRE, "");
8595     },
8596     
8597     /**
8598      * Strips all HTML tags to sort on text only - Case insensitive
8599      * @param {Mixed} s The value being converted
8600      * @return {String} The comparison value
8601      */
8602     asUCText : function(s){
8603         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8604     },
8605     
8606     /**
8607      * Case insensitive string
8608      * @param {Mixed} s The value being converted
8609      * @return {String} The comparison value
8610      */
8611     asUCString : function(s) {
8612         return String(s).toUpperCase();
8613     },
8614     
8615     /**
8616      * Date sorting
8617      * @param {Mixed} s The value being converted
8618      * @return {Number} The comparison value
8619      */
8620     asDate : function(s) {
8621         if(!s){
8622             return 0;
8623         }
8624         if(s instanceof Date){
8625             return s.getTime();
8626         }
8627         return Date.parse(String(s));
8628     },
8629     
8630     /**
8631      * Float sorting
8632      * @param {Mixed} s The value being converted
8633      * @return {Float} The comparison value
8634      */
8635     asFloat : function(s) {
8636         var val = parseFloat(String(s).replace(/,/g, ""));
8637         if(isNaN(val)) val = 0;
8638         return val;
8639     },
8640     
8641     /**
8642      * Integer sorting
8643      * @param {Mixed} s The value being converted
8644      * @return {Number} The comparison value
8645      */
8646     asInt : function(s) {
8647         var val = parseInt(String(s).replace(/,/g, ""));
8648         if(isNaN(val)) val = 0;
8649         return val;
8650     }
8651 };/*
8652  * Based on:
8653  * Ext JS Library 1.1.1
8654  * Copyright(c) 2006-2007, Ext JS, LLC.
8655  *
8656  * Originally Released Under LGPL - original licence link has changed is not relivant.
8657  *
8658  * Fork - LGPL
8659  * <script type="text/javascript">
8660  */
8661
8662 /**
8663 * @class Roo.data.Record
8664  * Instances of this class encapsulate both record <em>definition</em> information, and record
8665  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8666  * to access Records cached in an {@link Roo.data.Store} object.<br>
8667  * <p>
8668  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8669  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8670  * objects.<br>
8671  * <p>
8672  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8673  * @constructor
8674  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8675  * {@link #create}. The parameters are the same.
8676  * @param {Array} data An associative Array of data values keyed by the field name.
8677  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8678  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8679  * not specified an integer id is generated.
8680  */
8681 Roo.data.Record = function(data, id){
8682     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8683     this.data = data;
8684 };
8685
8686 /**
8687  * Generate a constructor for a specific record layout.
8688  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8689  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8690  * Each field definition object may contain the following properties: <ul>
8691  * <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,
8692  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8693  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8694  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8695  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8696  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8697  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8698  * this may be omitted.</p></li>
8699  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8700  * <ul><li>auto (Default, implies no conversion)</li>
8701  * <li>string</li>
8702  * <li>int</li>
8703  * <li>float</li>
8704  * <li>boolean</li>
8705  * <li>date</li></ul></p></li>
8706  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8707  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8708  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8709  * by the Reader into an object that will be stored in the Record. It is passed the
8710  * following parameters:<ul>
8711  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8712  * </ul></p></li>
8713  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8714  * </ul>
8715  * <br>usage:<br><pre><code>
8716 var TopicRecord = Roo.data.Record.create(
8717     {name: 'title', mapping: 'topic_title'},
8718     {name: 'author', mapping: 'username'},
8719     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8720     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8721     {name: 'lastPoster', mapping: 'user2'},
8722     {name: 'excerpt', mapping: 'post_text'}
8723 );
8724
8725 var myNewRecord = new TopicRecord({
8726     title: 'Do my job please',
8727     author: 'noobie',
8728     totalPosts: 1,
8729     lastPost: new Date(),
8730     lastPoster: 'Animal',
8731     excerpt: 'No way dude!'
8732 });
8733 myStore.add(myNewRecord);
8734 </code></pre>
8735  * @method create
8736  * @static
8737  */
8738 Roo.data.Record.create = function(o){
8739     var f = function(){
8740         f.superclass.constructor.apply(this, arguments);
8741     };
8742     Roo.extend(f, Roo.data.Record);
8743     var p = f.prototype;
8744     p.fields = new Roo.util.MixedCollection(false, function(field){
8745         return field.name;
8746     });
8747     for(var i = 0, len = o.length; i < len; i++){
8748         p.fields.add(new Roo.data.Field(o[i]));
8749     }
8750     f.getField = function(name){
8751         return p.fields.get(name);  
8752     };
8753     return f;
8754 };
8755
8756 Roo.data.Record.AUTO_ID = 1000;
8757 Roo.data.Record.EDIT = 'edit';
8758 Roo.data.Record.REJECT = 'reject';
8759 Roo.data.Record.COMMIT = 'commit';
8760
8761 Roo.data.Record.prototype = {
8762     /**
8763      * Readonly flag - true if this record has been modified.
8764      * @type Boolean
8765      */
8766     dirty : false,
8767     editing : false,
8768     error: null,
8769     modified: null,
8770
8771     // private
8772     join : function(store){
8773         this.store = store;
8774     },
8775
8776     /**
8777      * Set the named field to the specified value.
8778      * @param {String} name The name of the field to set.
8779      * @param {Object} value The value to set the field to.
8780      */
8781     set : function(name, value){
8782         if(this.data[name] == value){
8783             return;
8784         }
8785         this.dirty = true;
8786         if(!this.modified){
8787             this.modified = {};
8788         }
8789         if(typeof this.modified[name] == 'undefined'){
8790             this.modified[name] = this.data[name];
8791         }
8792         this.data[name] = value;
8793         if(!this.editing && this.store){
8794             this.store.afterEdit(this);
8795         }       
8796     },
8797
8798     /**
8799      * Get the value of the named field.
8800      * @param {String} name The name of the field to get the value of.
8801      * @return {Object} The value of the field.
8802      */
8803     get : function(name){
8804         return this.data[name]; 
8805     },
8806
8807     // private
8808     beginEdit : function(){
8809         this.editing = true;
8810         this.modified = {}; 
8811     },
8812
8813     // private
8814     cancelEdit : function(){
8815         this.editing = false;
8816         delete this.modified;
8817     },
8818
8819     // private
8820     endEdit : function(){
8821         this.editing = false;
8822         if(this.dirty && this.store){
8823             this.store.afterEdit(this);
8824         }
8825     },
8826
8827     /**
8828      * Usually called by the {@link Roo.data.Store} which owns the Record.
8829      * Rejects all changes made to the Record since either creation, or the last commit operation.
8830      * Modified fields are reverted to their original values.
8831      * <p>
8832      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8833      * of reject operations.
8834      */
8835     reject : function(){
8836         var m = this.modified;
8837         for(var n in m){
8838             if(typeof m[n] != "function"){
8839                 this.data[n] = m[n];
8840             }
8841         }
8842         this.dirty = false;
8843         delete this.modified;
8844         this.editing = false;
8845         if(this.store){
8846             this.store.afterReject(this);
8847         }
8848     },
8849
8850     /**
8851      * Usually called by the {@link Roo.data.Store} which owns the Record.
8852      * Commits all changes made to the Record since either creation, or the last commit operation.
8853      * <p>
8854      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8855      * of commit operations.
8856      */
8857     commit : function(){
8858         this.dirty = false;
8859         delete this.modified;
8860         this.editing = false;
8861         if(this.store){
8862             this.store.afterCommit(this);
8863         }
8864     },
8865
8866     // private
8867     hasError : function(){
8868         return this.error != null;
8869     },
8870
8871     // private
8872     clearError : function(){
8873         this.error = null;
8874     },
8875
8876     /**
8877      * Creates a copy of this record.
8878      * @param {String} id (optional) A new record id if you don't want to use this record's id
8879      * @return {Record}
8880      */
8881     copy : function(newId) {
8882         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8883     }
8884 };/*
8885  * Based on:
8886  * Ext JS Library 1.1.1
8887  * Copyright(c) 2006-2007, Ext JS, LLC.
8888  *
8889  * Originally Released Under LGPL - original licence link has changed is not relivant.
8890  *
8891  * Fork - LGPL
8892  * <script type="text/javascript">
8893  */
8894
8895
8896
8897 /**
8898  * @class Roo.data.Store
8899  * @extends Roo.util.Observable
8900  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8901  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8902  * <p>
8903  * 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
8904  * has no knowledge of the format of the data returned by the Proxy.<br>
8905  * <p>
8906  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8907  * instances from the data object. These records are cached and made available through accessor functions.
8908  * @constructor
8909  * Creates a new Store.
8910  * @param {Object} config A config object containing the objects needed for the Store to access data,
8911  * and read the data into Records.
8912  */
8913 Roo.data.Store = function(config){
8914     this.data = new Roo.util.MixedCollection(false);
8915     this.data.getKey = function(o){
8916         return o.id;
8917     };
8918     this.baseParams = {};
8919     // private
8920     this.paramNames = {
8921         "start" : "start",
8922         "limit" : "limit",
8923         "sort" : "sort",
8924         "dir" : "dir",
8925         "multisort" : "_multisort"
8926     };
8927
8928     if(config && config.data){
8929         this.inlineData = config.data;
8930         delete config.data;
8931     }
8932
8933     Roo.apply(this, config);
8934     
8935     if(this.reader){ // reader passed
8936         this.reader = Roo.factory(this.reader, Roo.data);
8937         this.reader.xmodule = this.xmodule || false;
8938         if(!this.recordType){
8939             this.recordType = this.reader.recordType;
8940         }
8941         if(this.reader.onMetaChange){
8942             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8943         }
8944     }
8945
8946     if(this.recordType){
8947         this.fields = this.recordType.prototype.fields;
8948     }
8949     this.modified = [];
8950
8951     this.addEvents({
8952         /**
8953          * @event datachanged
8954          * Fires when the data cache has changed, and a widget which is using this Store
8955          * as a Record cache should refresh its view.
8956          * @param {Store} this
8957          */
8958         datachanged : true,
8959         /**
8960          * @event metachange
8961          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8962          * @param {Store} this
8963          * @param {Object} meta The JSON metadata
8964          */
8965         metachange : true,
8966         /**
8967          * @event add
8968          * Fires when Records have been added to the Store
8969          * @param {Store} this
8970          * @param {Roo.data.Record[]} records The array of Records added
8971          * @param {Number} index The index at which the record(s) were added
8972          */
8973         add : true,
8974         /**
8975          * @event remove
8976          * Fires when a Record has been removed from the Store
8977          * @param {Store} this
8978          * @param {Roo.data.Record} record The Record that was removed
8979          * @param {Number} index The index at which the record was removed
8980          */
8981         remove : true,
8982         /**
8983          * @event update
8984          * Fires when a Record has been updated
8985          * @param {Store} this
8986          * @param {Roo.data.Record} record The Record that was updated
8987          * @param {String} operation The update operation being performed.  Value may be one of:
8988          * <pre><code>
8989  Roo.data.Record.EDIT
8990  Roo.data.Record.REJECT
8991  Roo.data.Record.COMMIT
8992          * </code></pre>
8993          */
8994         update : true,
8995         /**
8996          * @event clear
8997          * Fires when the data cache has been cleared.
8998          * @param {Store} this
8999          */
9000         clear : true,
9001         /**
9002          * @event beforeload
9003          * Fires before a request is made for a new data object.  If the beforeload handler returns false
9004          * the load action will be canceled.
9005          * @param {Store} this
9006          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9007          */
9008         beforeload : true,
9009         /**
9010          * @event beforeloadadd
9011          * Fires after a new set of Records has been loaded.
9012          * @param {Store} this
9013          * @param {Roo.data.Record[]} records The Records that were loaded
9014          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9015          */
9016         beforeloadadd : true,
9017         /**
9018          * @event load
9019          * Fires after a new set of Records has been loaded, before they are added to the store.
9020          * @param {Store} this
9021          * @param {Roo.data.Record[]} records The Records that were loaded
9022          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9023          * @params {Object} return from reader
9024          */
9025         load : true,
9026         /**
9027          * @event loadexception
9028          * Fires if an exception occurs in the Proxy during loading.
9029          * Called with the signature of the Proxy's "loadexception" event.
9030          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9031          * 
9032          * @param {Proxy} 
9033          * @param {Object} return from JsonData.reader() - success, totalRecords, records
9034          * @param {Object} load options 
9035          * @param {Object} jsonData from your request (normally this contains the Exception)
9036          */
9037         loadexception : true
9038     });
9039     
9040     if(this.proxy){
9041         this.proxy = Roo.factory(this.proxy, Roo.data);
9042         this.proxy.xmodule = this.xmodule || false;
9043         this.relayEvents(this.proxy,  ["loadexception"]);
9044     }
9045     this.sortToggle = {};
9046     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9047
9048     Roo.data.Store.superclass.constructor.call(this);
9049
9050     if(this.inlineData){
9051         this.loadData(this.inlineData);
9052         delete this.inlineData;
9053     }
9054 };
9055
9056 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9057      /**
9058     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9059     * without a remote query - used by combo/forms at present.
9060     */
9061     
9062     /**
9063     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9064     */
9065     /**
9066     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9067     */
9068     /**
9069     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9070     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9071     */
9072     /**
9073     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9074     * on any HTTP request
9075     */
9076     /**
9077     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9078     */
9079     /**
9080     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9081     */
9082     multiSort: false,
9083     /**
9084     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9085     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9086     */
9087     remoteSort : false,
9088
9089     /**
9090     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9091      * loaded or when a record is removed. (defaults to false).
9092     */
9093     pruneModifiedRecords : false,
9094
9095     // private
9096     lastOptions : null,
9097
9098     /**
9099      * Add Records to the Store and fires the add event.
9100      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9101      */
9102     add : function(records){
9103         records = [].concat(records);
9104         for(var i = 0, len = records.length; i < len; i++){
9105             records[i].join(this);
9106         }
9107         var index = this.data.length;
9108         this.data.addAll(records);
9109         this.fireEvent("add", this, records, index);
9110     },
9111
9112     /**
9113      * Remove a Record from the Store and fires the remove event.
9114      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9115      */
9116     remove : function(record){
9117         var index = this.data.indexOf(record);
9118         this.data.removeAt(index);
9119         if(this.pruneModifiedRecords){
9120             this.modified.remove(record);
9121         }
9122         this.fireEvent("remove", this, record, index);
9123     },
9124
9125     /**
9126      * Remove all Records from the Store and fires the clear event.
9127      */
9128     removeAll : function(){
9129         this.data.clear();
9130         if(this.pruneModifiedRecords){
9131             this.modified = [];
9132         }
9133         this.fireEvent("clear", this);
9134     },
9135
9136     /**
9137      * Inserts Records to the Store at the given index and fires the add event.
9138      * @param {Number} index The start index at which to insert the passed Records.
9139      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9140      */
9141     insert : function(index, records){
9142         records = [].concat(records);
9143         for(var i = 0, len = records.length; i < len; i++){
9144             this.data.insert(index, records[i]);
9145             records[i].join(this);
9146         }
9147         this.fireEvent("add", this, records, index);
9148     },
9149
9150     /**
9151      * Get the index within the cache of the passed Record.
9152      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9153      * @return {Number} The index of the passed Record. Returns -1 if not found.
9154      */
9155     indexOf : function(record){
9156         return this.data.indexOf(record);
9157     },
9158
9159     /**
9160      * Get the index within the cache of the Record with the passed id.
9161      * @param {String} id The id of the Record to find.
9162      * @return {Number} The index of the Record. Returns -1 if not found.
9163      */
9164     indexOfId : function(id){
9165         return this.data.indexOfKey(id);
9166     },
9167
9168     /**
9169      * Get the Record with the specified id.
9170      * @param {String} id The id of the Record to find.
9171      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9172      */
9173     getById : function(id){
9174         return this.data.key(id);
9175     },
9176
9177     /**
9178      * Get the Record at the specified index.
9179      * @param {Number} index The index of the Record to find.
9180      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9181      */
9182     getAt : function(index){
9183         return this.data.itemAt(index);
9184     },
9185
9186     /**
9187      * Returns a range of Records between specified indices.
9188      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9189      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9190      * @return {Roo.data.Record[]} An array of Records
9191      */
9192     getRange : function(start, end){
9193         return this.data.getRange(start, end);
9194     },
9195
9196     // private
9197     storeOptions : function(o){
9198         o = Roo.apply({}, o);
9199         delete o.callback;
9200         delete o.scope;
9201         this.lastOptions = o;
9202     },
9203
9204     /**
9205      * Loads the Record cache from the configured Proxy using the configured Reader.
9206      * <p>
9207      * If using remote paging, then the first load call must specify the <em>start</em>
9208      * and <em>limit</em> properties in the options.params property to establish the initial
9209      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9210      * <p>
9211      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9212      * and this call will return before the new data has been loaded. Perform any post-processing
9213      * in a callback function, or in a "load" event handler.</strong>
9214      * <p>
9215      * @param {Object} options An object containing properties which control loading options:<ul>
9216      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9217      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9218      * passed the following arguments:<ul>
9219      * <li>r : Roo.data.Record[]</li>
9220      * <li>options: Options object from the load call</li>
9221      * <li>success: Boolean success indicator</li></ul></li>
9222      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9223      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9224      * </ul>
9225      */
9226     load : function(options){
9227         options = options || {};
9228         if(this.fireEvent("beforeload", this, options) !== false){
9229             this.storeOptions(options);
9230             var p = Roo.apply(options.params || {}, this.baseParams);
9231             // if meta was not loaded from remote source.. try requesting it.
9232             if (!this.reader.metaFromRemote) {
9233                 p._requestMeta = 1;
9234             }
9235             if(this.sortInfo && this.remoteSort){
9236                 var pn = this.paramNames;
9237                 p[pn["sort"]] = this.sortInfo.field;
9238                 p[pn["dir"]] = this.sortInfo.direction;
9239             }
9240             if (this.multiSort) {
9241                 var pn = this.paramNames;
9242                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9243             }
9244             
9245             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9246         }
9247     },
9248
9249     /**
9250      * Reloads the Record cache from the configured Proxy using the configured Reader and
9251      * the options from the last load operation performed.
9252      * @param {Object} options (optional) An object containing properties which may override the options
9253      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9254      * the most recently used options are reused).
9255      */
9256     reload : function(options){
9257         this.load(Roo.applyIf(options||{}, this.lastOptions));
9258     },
9259
9260     // private
9261     // Called as a callback by the Reader during a load operation.
9262     loadRecords : function(o, options, success){
9263         if(!o || success === false){
9264             if(success !== false){
9265                 this.fireEvent("load", this, [], options, o);
9266             }
9267             if(options.callback){
9268                 options.callback.call(options.scope || this, [], options, false);
9269             }
9270             return;
9271         }
9272         // if data returned failure - throw an exception.
9273         if (o.success === false) {
9274             // show a message if no listener is registered.
9275             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9276                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9277             }
9278             // loadmask wil be hooked into this..
9279             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9280             return;
9281         }
9282         var r = o.records, t = o.totalRecords || r.length;
9283         
9284         this.fireEvent("beforeloadadd", this, r, options, o);
9285         
9286         if(!options || options.add !== true){
9287             if(this.pruneModifiedRecords){
9288                 this.modified = [];
9289             }
9290             for(var i = 0, len = r.length; i < len; i++){
9291                 r[i].join(this);
9292             }
9293             if(this.snapshot){
9294                 this.data = this.snapshot;
9295                 delete this.snapshot;
9296             }
9297             this.data.clear();
9298             this.data.addAll(r);
9299             this.totalLength = t;
9300             this.applySort();
9301             this.fireEvent("datachanged", this);
9302         }else{
9303             this.totalLength = Math.max(t, this.data.length+r.length);
9304             this.add(r);
9305         }
9306         this.fireEvent("load", this, r, options, o);
9307         if(options.callback){
9308             options.callback.call(options.scope || this, r, options, true);
9309         }
9310     },
9311
9312
9313     /**
9314      * Loads data from a passed data block. A Reader which understands the format of the data
9315      * must have been configured in the constructor.
9316      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9317      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9318      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9319      */
9320     loadData : function(o, append){
9321         var r = this.reader.readRecords(o);
9322         this.loadRecords(r, {add: append}, true);
9323     },
9324
9325     /**
9326      * Gets the number of cached records.
9327      * <p>
9328      * <em>If using paging, this may not be the total size of the dataset. If the data object
9329      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9330      * the data set size</em>
9331      */
9332     getCount : function(){
9333         return this.data.length || 0;
9334     },
9335
9336     /**
9337      * Gets the total number of records in the dataset as returned by the server.
9338      * <p>
9339      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9340      * the dataset size</em>
9341      */
9342     getTotalCount : function(){
9343         return this.totalLength || 0;
9344     },
9345
9346     /**
9347      * Returns the sort state of the Store as an object with two properties:
9348      * <pre><code>
9349  field {String} The name of the field by which the Records are sorted
9350  direction {String} The sort order, "ASC" or "DESC"
9351      * </code></pre>
9352      */
9353     getSortState : function(){
9354         return this.sortInfo;
9355     },
9356
9357     // private
9358     applySort : function(){
9359         if(this.sortInfo && !this.remoteSort){
9360             var s = this.sortInfo, f = s.field;
9361             var st = this.fields.get(f).sortType;
9362             var fn = function(r1, r2){
9363                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9364                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9365             };
9366             this.data.sort(s.direction, fn);
9367             if(this.snapshot && this.snapshot != this.data){
9368                 this.snapshot.sort(s.direction, fn);
9369             }
9370         }
9371     },
9372
9373     /**
9374      * Sets the default sort column and order to be used by the next load operation.
9375      * @param {String} fieldName The name of the field to sort by.
9376      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9377      */
9378     setDefaultSort : function(field, dir){
9379         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9380     },
9381
9382     /**
9383      * Sort the Records.
9384      * If remote sorting is used, the sort is performed on the server, and the cache is
9385      * reloaded. If local sorting is used, the cache is sorted internally.
9386      * @param {String} fieldName The name of the field to sort by.
9387      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9388      */
9389     sort : function(fieldName, dir){
9390         var f = this.fields.get(fieldName);
9391         if(!dir){
9392             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9393             
9394             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9395                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9396             }else{
9397                 dir = f.sortDir;
9398             }
9399         }
9400         this.sortToggle[f.name] = dir;
9401         this.sortInfo = {field: f.name, direction: dir};
9402         if(!this.remoteSort){
9403             this.applySort();
9404             this.fireEvent("datachanged", this);
9405         }else{
9406             this.load(this.lastOptions);
9407         }
9408     },
9409
9410     /**
9411      * Calls the specified function for each of the Records in the cache.
9412      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9413      * Returning <em>false</em> aborts and exits the iteration.
9414      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9415      */
9416     each : function(fn, scope){
9417         this.data.each(fn, scope);
9418     },
9419
9420     /**
9421      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9422      * (e.g., during paging).
9423      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9424      */
9425     getModifiedRecords : function(){
9426         return this.modified;
9427     },
9428
9429     // private
9430     createFilterFn : function(property, value, anyMatch){
9431         if(!value.exec){ // not a regex
9432             value = String(value);
9433             if(value.length == 0){
9434                 return false;
9435             }
9436             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9437         }
9438         return function(r){
9439             return value.test(r.data[property]);
9440         };
9441     },
9442
9443     /**
9444      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9445      * @param {String} property A field on your records
9446      * @param {Number} start The record index to start at (defaults to 0)
9447      * @param {Number} end The last record index to include (defaults to length - 1)
9448      * @return {Number} The sum
9449      */
9450     sum : function(property, start, end){
9451         var rs = this.data.items, v = 0;
9452         start = start || 0;
9453         end = (end || end === 0) ? end : rs.length-1;
9454
9455         for(var i = start; i <= end; i++){
9456             v += (rs[i].data[property] || 0);
9457         }
9458         return v;
9459     },
9460
9461     /**
9462      * Filter the records by a specified property.
9463      * @param {String} field A field on your records
9464      * @param {String/RegExp} value Either a string that the field
9465      * should start with or a RegExp to test against the field
9466      * @param {Boolean} anyMatch True to match any part not just the beginning
9467      */
9468     filter : function(property, value, anyMatch){
9469         var fn = this.createFilterFn(property, value, anyMatch);
9470         return fn ? this.filterBy(fn) : this.clearFilter();
9471     },
9472
9473     /**
9474      * Filter by a function. The specified function will be called with each
9475      * record in this data source. If the function returns true the record is included,
9476      * otherwise it is filtered.
9477      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9478      * @param {Object} scope (optional) The scope of the function (defaults to this)
9479      */
9480     filterBy : function(fn, scope){
9481         this.snapshot = this.snapshot || this.data;
9482         this.data = this.queryBy(fn, scope||this);
9483         this.fireEvent("datachanged", this);
9484     },
9485
9486     /**
9487      * Query the records by a specified property.
9488      * @param {String} field A field on your records
9489      * @param {String/RegExp} value Either a string that the field
9490      * should start with or a RegExp to test against the field
9491      * @param {Boolean} anyMatch True to match any part not just the beginning
9492      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9493      */
9494     query : function(property, value, anyMatch){
9495         var fn = this.createFilterFn(property, value, anyMatch);
9496         return fn ? this.queryBy(fn) : this.data.clone();
9497     },
9498
9499     /**
9500      * Query by a function. The specified function will be called with each
9501      * record in this data source. If the function returns true the record is included
9502      * in the results.
9503      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9504      * @param {Object} scope (optional) The scope of the function (defaults to this)
9505       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9506      **/
9507     queryBy : function(fn, scope){
9508         var data = this.snapshot || this.data;
9509         return data.filterBy(fn, scope||this);
9510     },
9511
9512     /**
9513      * Collects unique values for a particular dataIndex from this store.
9514      * @param {String} dataIndex The property to collect
9515      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9516      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9517      * @return {Array} An array of the unique values
9518      **/
9519     collect : function(dataIndex, allowNull, bypassFilter){
9520         var d = (bypassFilter === true && this.snapshot) ?
9521                 this.snapshot.items : this.data.items;
9522         var v, sv, r = [], l = {};
9523         for(var i = 0, len = d.length; i < len; i++){
9524             v = d[i].data[dataIndex];
9525             sv = String(v);
9526             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9527                 l[sv] = true;
9528                 r[r.length] = v;
9529             }
9530         }
9531         return r;
9532     },
9533
9534     /**
9535      * Revert to a view of the Record cache with no filtering applied.
9536      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9537      */
9538     clearFilter : function(suppressEvent){
9539         if(this.snapshot && this.snapshot != this.data){
9540             this.data = this.snapshot;
9541             delete this.snapshot;
9542             if(suppressEvent !== true){
9543                 this.fireEvent("datachanged", this);
9544             }
9545         }
9546     },
9547
9548     // private
9549     afterEdit : function(record){
9550         if(this.modified.indexOf(record) == -1){
9551             this.modified.push(record);
9552         }
9553         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9554     },
9555     
9556     // private
9557     afterReject : function(record){
9558         this.modified.remove(record);
9559         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9560     },
9561
9562     // private
9563     afterCommit : function(record){
9564         this.modified.remove(record);
9565         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9566     },
9567
9568     /**
9569      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9570      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9571      */
9572     commitChanges : function(){
9573         var m = this.modified.slice(0);
9574         this.modified = [];
9575         for(var i = 0, len = m.length; i < len; i++){
9576             m[i].commit();
9577         }
9578     },
9579
9580     /**
9581      * Cancel outstanding changes on all changed records.
9582      */
9583     rejectChanges : function(){
9584         var m = this.modified.slice(0);
9585         this.modified = [];
9586         for(var i = 0, len = m.length; i < len; i++){
9587             m[i].reject();
9588         }
9589     },
9590
9591     onMetaChange : function(meta, rtype, o){
9592         this.recordType = rtype;
9593         this.fields = rtype.prototype.fields;
9594         delete this.snapshot;
9595         this.sortInfo = meta.sortInfo || this.sortInfo;
9596         this.modified = [];
9597         this.fireEvent('metachange', this, this.reader.meta);
9598     },
9599     
9600     moveIndex : function(data, type)
9601     {
9602         var index = this.indexOf(data);
9603         
9604         var newIndex = index + type;
9605         
9606         this.remove(data);
9607         
9608         this.insert(newIndex, data);
9609         
9610     }
9611 });/*
9612  * Based on:
9613  * Ext JS Library 1.1.1
9614  * Copyright(c) 2006-2007, Ext JS, LLC.
9615  *
9616  * Originally Released Under LGPL - original licence link has changed is not relivant.
9617  *
9618  * Fork - LGPL
9619  * <script type="text/javascript">
9620  */
9621
9622 /**
9623  * @class Roo.data.SimpleStore
9624  * @extends Roo.data.Store
9625  * Small helper class to make creating Stores from Array data easier.
9626  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9627  * @cfg {Array} fields An array of field definition objects, or field name strings.
9628  * @cfg {Array} data The multi-dimensional array of data
9629  * @constructor
9630  * @param {Object} config
9631  */
9632 Roo.data.SimpleStore = function(config){
9633     Roo.data.SimpleStore.superclass.constructor.call(this, {
9634         isLocal : true,
9635         reader: new Roo.data.ArrayReader({
9636                 id: config.id
9637             },
9638             Roo.data.Record.create(config.fields)
9639         ),
9640         proxy : new Roo.data.MemoryProxy(config.data)
9641     });
9642     this.load();
9643 };
9644 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9645  * Based on:
9646  * Ext JS Library 1.1.1
9647  * Copyright(c) 2006-2007, Ext JS, LLC.
9648  *
9649  * Originally Released Under LGPL - original licence link has changed is not relivant.
9650  *
9651  * Fork - LGPL
9652  * <script type="text/javascript">
9653  */
9654
9655 /**
9656 /**
9657  * @extends Roo.data.Store
9658  * @class Roo.data.JsonStore
9659  * Small helper class to make creating Stores for JSON data easier. <br/>
9660 <pre><code>
9661 var store = new Roo.data.JsonStore({
9662     url: 'get-images.php',
9663     root: 'images',
9664     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9665 });
9666 </code></pre>
9667  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9668  * JsonReader and HttpProxy (unless inline data is provided).</b>
9669  * @cfg {Array} fields An array of field definition objects, or field name strings.
9670  * @constructor
9671  * @param {Object} config
9672  */
9673 Roo.data.JsonStore = function(c){
9674     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9675         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9676         reader: new Roo.data.JsonReader(c, c.fields)
9677     }));
9678 };
9679 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9680  * Based on:
9681  * Ext JS Library 1.1.1
9682  * Copyright(c) 2006-2007, Ext JS, LLC.
9683  *
9684  * Originally Released Under LGPL - original licence link has changed is not relivant.
9685  *
9686  * Fork - LGPL
9687  * <script type="text/javascript">
9688  */
9689
9690  
9691 Roo.data.Field = function(config){
9692     if(typeof config == "string"){
9693         config = {name: config};
9694     }
9695     Roo.apply(this, config);
9696     
9697     if(!this.type){
9698         this.type = "auto";
9699     }
9700     
9701     var st = Roo.data.SortTypes;
9702     // named sortTypes are supported, here we look them up
9703     if(typeof this.sortType == "string"){
9704         this.sortType = st[this.sortType];
9705     }
9706     
9707     // set default sortType for strings and dates
9708     if(!this.sortType){
9709         switch(this.type){
9710             case "string":
9711                 this.sortType = st.asUCString;
9712                 break;
9713             case "date":
9714                 this.sortType = st.asDate;
9715                 break;
9716             default:
9717                 this.sortType = st.none;
9718         }
9719     }
9720
9721     // define once
9722     var stripRe = /[\$,%]/g;
9723
9724     // prebuilt conversion function for this field, instead of
9725     // switching every time we're reading a value
9726     if(!this.convert){
9727         var cv, dateFormat = this.dateFormat;
9728         switch(this.type){
9729             case "":
9730             case "auto":
9731             case undefined:
9732                 cv = function(v){ return v; };
9733                 break;
9734             case "string":
9735                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9736                 break;
9737             case "int":
9738                 cv = function(v){
9739                     return v !== undefined && v !== null && v !== '' ?
9740                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9741                     };
9742                 break;
9743             case "float":
9744                 cv = function(v){
9745                     return v !== undefined && v !== null && v !== '' ?
9746                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9747                     };
9748                 break;
9749             case "bool":
9750             case "boolean":
9751                 cv = function(v){ return v === true || v === "true" || v == 1; };
9752                 break;
9753             case "date":
9754                 cv = function(v){
9755                     if(!v){
9756                         return '';
9757                     }
9758                     if(v instanceof Date){
9759                         return v;
9760                     }
9761                     if(dateFormat){
9762                         if(dateFormat == "timestamp"){
9763                             return new Date(v*1000);
9764                         }
9765                         return Date.parseDate(v, dateFormat);
9766                     }
9767                     var parsed = Date.parse(v);
9768                     return parsed ? new Date(parsed) : null;
9769                 };
9770              break;
9771             
9772         }
9773         this.convert = cv;
9774     }
9775 };
9776
9777 Roo.data.Field.prototype = {
9778     dateFormat: null,
9779     defaultValue: "",
9780     mapping: null,
9781     sortType : null,
9782     sortDir : "ASC"
9783 };/*
9784  * Based on:
9785  * Ext JS Library 1.1.1
9786  * Copyright(c) 2006-2007, Ext JS, LLC.
9787  *
9788  * Originally Released Under LGPL - original licence link has changed is not relivant.
9789  *
9790  * Fork - LGPL
9791  * <script type="text/javascript">
9792  */
9793  
9794 // Base class for reading structured data from a data source.  This class is intended to be
9795 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9796
9797 /**
9798  * @class Roo.data.DataReader
9799  * Base class for reading structured data from a data source.  This class is intended to be
9800  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9801  */
9802
9803 Roo.data.DataReader = function(meta, recordType){
9804     
9805     this.meta = meta;
9806     
9807     this.recordType = recordType instanceof Array ? 
9808         Roo.data.Record.create(recordType) : recordType;
9809 };
9810
9811 Roo.data.DataReader.prototype = {
9812      /**
9813      * Create an empty record
9814      * @param {Object} data (optional) - overlay some values
9815      * @return {Roo.data.Record} record created.
9816      */
9817     newRow :  function(d) {
9818         var da =  {};
9819         this.recordType.prototype.fields.each(function(c) {
9820             switch( c.type) {
9821                 case 'int' : da[c.name] = 0; break;
9822                 case 'date' : da[c.name] = new Date(); break;
9823                 case 'float' : da[c.name] = 0.0; break;
9824                 case 'boolean' : da[c.name] = false; break;
9825                 default : da[c.name] = ""; break;
9826             }
9827             
9828         });
9829         return new this.recordType(Roo.apply(da, d));
9830     }
9831     
9832 };/*
9833  * Based on:
9834  * Ext JS Library 1.1.1
9835  * Copyright(c) 2006-2007, Ext JS, LLC.
9836  *
9837  * Originally Released Under LGPL - original licence link has changed is not relivant.
9838  *
9839  * Fork - LGPL
9840  * <script type="text/javascript">
9841  */
9842
9843 /**
9844  * @class Roo.data.DataProxy
9845  * @extends Roo.data.Observable
9846  * This class is an abstract base class for implementations which provide retrieval of
9847  * unformatted data objects.<br>
9848  * <p>
9849  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9850  * (of the appropriate type which knows how to parse the data object) to provide a block of
9851  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9852  * <p>
9853  * Custom implementations must implement the load method as described in
9854  * {@link Roo.data.HttpProxy#load}.
9855  */
9856 Roo.data.DataProxy = function(){
9857     this.addEvents({
9858         /**
9859          * @event beforeload
9860          * Fires before a network request is made to retrieve a data object.
9861          * @param {Object} This DataProxy object.
9862          * @param {Object} params The params parameter to the load function.
9863          */
9864         beforeload : true,
9865         /**
9866          * @event load
9867          * Fires before the load method's callback is called.
9868          * @param {Object} This DataProxy object.
9869          * @param {Object} o The data object.
9870          * @param {Object} arg The callback argument object passed to the load function.
9871          */
9872         load : true,
9873         /**
9874          * @event loadexception
9875          * Fires if an Exception occurs during data retrieval.
9876          * @param {Object} This DataProxy object.
9877          * @param {Object} o The data object.
9878          * @param {Object} arg The callback argument object passed to the load function.
9879          * @param {Object} e The Exception.
9880          */
9881         loadexception : true
9882     });
9883     Roo.data.DataProxy.superclass.constructor.call(this);
9884 };
9885
9886 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9887
9888     /**
9889      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9890      */
9891 /*
9892  * Based on:
9893  * Ext JS Library 1.1.1
9894  * Copyright(c) 2006-2007, Ext JS, LLC.
9895  *
9896  * Originally Released Under LGPL - original licence link has changed is not relivant.
9897  *
9898  * Fork - LGPL
9899  * <script type="text/javascript">
9900  */
9901 /**
9902  * @class Roo.data.MemoryProxy
9903  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9904  * to the Reader when its load method is called.
9905  * @constructor
9906  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9907  */
9908 Roo.data.MemoryProxy = function(data){
9909     if (data.data) {
9910         data = data.data;
9911     }
9912     Roo.data.MemoryProxy.superclass.constructor.call(this);
9913     this.data = data;
9914 };
9915
9916 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9917     /**
9918      * Load data from the requested source (in this case an in-memory
9919      * data object passed to the constructor), read the data object into
9920      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9921      * process that block using the passed callback.
9922      * @param {Object} params This parameter is not used by the MemoryProxy class.
9923      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9924      * object into a block of Roo.data.Records.
9925      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9926      * The function must be passed <ul>
9927      * <li>The Record block object</li>
9928      * <li>The "arg" argument from the load function</li>
9929      * <li>A boolean success indicator</li>
9930      * </ul>
9931      * @param {Object} scope The scope in which to call the callback
9932      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9933      */
9934     load : function(params, reader, callback, scope, arg){
9935         params = params || {};
9936         var result;
9937         try {
9938             result = reader.readRecords(this.data);
9939         }catch(e){
9940             this.fireEvent("loadexception", this, arg, null, e);
9941             callback.call(scope, null, arg, false);
9942             return;
9943         }
9944         callback.call(scope, result, arg, true);
9945     },
9946     
9947     // private
9948     update : function(params, records){
9949         
9950     }
9951 });/*
9952  * Based on:
9953  * Ext JS Library 1.1.1
9954  * Copyright(c) 2006-2007, Ext JS, LLC.
9955  *
9956  * Originally Released Under LGPL - original licence link has changed is not relivant.
9957  *
9958  * Fork - LGPL
9959  * <script type="text/javascript">
9960  */
9961 /**
9962  * @class Roo.data.HttpProxy
9963  * @extends Roo.data.DataProxy
9964  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9965  * configured to reference a certain URL.<br><br>
9966  * <p>
9967  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9968  * from which the running page was served.<br><br>
9969  * <p>
9970  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9971  * <p>
9972  * Be aware that to enable the browser to parse an XML document, the server must set
9973  * the Content-Type header in the HTTP response to "text/xml".
9974  * @constructor
9975  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9976  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9977  * will be used to make the request.
9978  */
9979 Roo.data.HttpProxy = function(conn){
9980     Roo.data.HttpProxy.superclass.constructor.call(this);
9981     // is conn a conn config or a real conn?
9982     this.conn = conn;
9983     this.useAjax = !conn || !conn.events;
9984   
9985 };
9986
9987 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9988     // thse are take from connection...
9989     
9990     /**
9991      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9992      */
9993     /**
9994      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9995      * extra parameters to each request made by this object. (defaults to undefined)
9996      */
9997     /**
9998      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9999      *  to each request made by this object. (defaults to undefined)
10000      */
10001     /**
10002      * @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)
10003      */
10004     /**
10005      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10006      */
10007      /**
10008      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10009      * @type Boolean
10010      */
10011   
10012
10013     /**
10014      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10015      * @type Boolean
10016      */
10017     /**
10018      * Return the {@link Roo.data.Connection} object being used by this Proxy.
10019      * @return {Connection} The Connection object. This object may be used to subscribe to events on
10020      * a finer-grained basis than the DataProxy events.
10021      */
10022     getConnection : function(){
10023         return this.useAjax ? Roo.Ajax : this.conn;
10024     },
10025
10026     /**
10027      * Load data from the configured {@link Roo.data.Connection}, read the data object into
10028      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10029      * process that block using the passed callback.
10030      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10031      * for the request to the remote server.
10032      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10033      * object into a block of Roo.data.Records.
10034      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10035      * The function must be passed <ul>
10036      * <li>The Record block object</li>
10037      * <li>The "arg" argument from the load function</li>
10038      * <li>A boolean success indicator</li>
10039      * </ul>
10040      * @param {Object} scope The scope in which to call the callback
10041      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10042      */
10043     load : function(params, reader, callback, scope, arg){
10044         if(this.fireEvent("beforeload", this, params) !== false){
10045             var  o = {
10046                 params : params || {},
10047                 request: {
10048                     callback : callback,
10049                     scope : scope,
10050                     arg : arg
10051                 },
10052                 reader: reader,
10053                 callback : this.loadResponse,
10054                 scope: this
10055             };
10056             if(this.useAjax){
10057                 Roo.applyIf(o, this.conn);
10058                 if(this.activeRequest){
10059                     Roo.Ajax.abort(this.activeRequest);
10060                 }
10061                 this.activeRequest = Roo.Ajax.request(o);
10062             }else{
10063                 this.conn.request(o);
10064             }
10065         }else{
10066             callback.call(scope||this, null, arg, false);
10067         }
10068     },
10069
10070     // private
10071     loadResponse : function(o, success, response){
10072         delete this.activeRequest;
10073         if(!success){
10074             this.fireEvent("loadexception", this, o, response);
10075             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10076             return;
10077         }
10078         var result;
10079         try {
10080             result = o.reader.read(response);
10081         }catch(e){
10082             this.fireEvent("loadexception", this, o, response, e);
10083             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10084             return;
10085         }
10086         
10087         this.fireEvent("load", this, o, o.request.arg);
10088         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10089     },
10090
10091     // private
10092     update : function(dataSet){
10093
10094     },
10095
10096     // private
10097     updateResponse : function(dataSet){
10098
10099     }
10100 });/*
10101  * Based on:
10102  * Ext JS Library 1.1.1
10103  * Copyright(c) 2006-2007, Ext JS, LLC.
10104  *
10105  * Originally Released Under LGPL - original licence link has changed is not relivant.
10106  *
10107  * Fork - LGPL
10108  * <script type="text/javascript">
10109  */
10110
10111 /**
10112  * @class Roo.data.ScriptTagProxy
10113  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10114  * other than the originating domain of the running page.<br><br>
10115  * <p>
10116  * <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
10117  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10118  * <p>
10119  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10120  * source code that is used as the source inside a &lt;script> tag.<br><br>
10121  * <p>
10122  * In order for the browser to process the returned data, the server must wrap the data object
10123  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10124  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10125  * depending on whether the callback name was passed:
10126  * <p>
10127  * <pre><code>
10128 boolean scriptTag = false;
10129 String cb = request.getParameter("callback");
10130 if (cb != null) {
10131     scriptTag = true;
10132     response.setContentType("text/javascript");
10133 } else {
10134     response.setContentType("application/x-json");
10135 }
10136 Writer out = response.getWriter();
10137 if (scriptTag) {
10138     out.write(cb + "(");
10139 }
10140 out.print(dataBlock.toJsonString());
10141 if (scriptTag) {
10142     out.write(");");
10143 }
10144 </pre></code>
10145  *
10146  * @constructor
10147  * @param {Object} config A configuration object.
10148  */
10149 Roo.data.ScriptTagProxy = function(config){
10150     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10151     Roo.apply(this, config);
10152     this.head = document.getElementsByTagName("head")[0];
10153 };
10154
10155 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10156
10157 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10158     /**
10159      * @cfg {String} url The URL from which to request the data object.
10160      */
10161     /**
10162      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10163      */
10164     timeout : 30000,
10165     /**
10166      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10167      * the server the name of the callback function set up by the load call to process the returned data object.
10168      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10169      * javascript output which calls this named function passing the data object as its only parameter.
10170      */
10171     callbackParam : "callback",
10172     /**
10173      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10174      * name to the request.
10175      */
10176     nocache : true,
10177
10178     /**
10179      * Load data from the configured URL, read the data object into
10180      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10181      * process that block using the passed callback.
10182      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10183      * for the request to the remote server.
10184      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10185      * object into a block of Roo.data.Records.
10186      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10187      * The function must be passed <ul>
10188      * <li>The Record block object</li>
10189      * <li>The "arg" argument from the load function</li>
10190      * <li>A boolean success indicator</li>
10191      * </ul>
10192      * @param {Object} scope The scope in which to call the callback
10193      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10194      */
10195     load : function(params, reader, callback, scope, arg){
10196         if(this.fireEvent("beforeload", this, params) !== false){
10197
10198             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10199
10200             var url = this.url;
10201             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10202             if(this.nocache){
10203                 url += "&_dc=" + (new Date().getTime());
10204             }
10205             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10206             var trans = {
10207                 id : transId,
10208                 cb : "stcCallback"+transId,
10209                 scriptId : "stcScript"+transId,
10210                 params : params,
10211                 arg : arg,
10212                 url : url,
10213                 callback : callback,
10214                 scope : scope,
10215                 reader : reader
10216             };
10217             var conn = this;
10218
10219             window[trans.cb] = function(o){
10220                 conn.handleResponse(o, trans);
10221             };
10222
10223             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10224
10225             if(this.autoAbort !== false){
10226                 this.abort();
10227             }
10228
10229             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10230
10231             var script = document.createElement("script");
10232             script.setAttribute("src", url);
10233             script.setAttribute("type", "text/javascript");
10234             script.setAttribute("id", trans.scriptId);
10235             this.head.appendChild(script);
10236
10237             this.trans = trans;
10238         }else{
10239             callback.call(scope||this, null, arg, false);
10240         }
10241     },
10242
10243     // private
10244     isLoading : function(){
10245         return this.trans ? true : false;
10246     },
10247
10248     /**
10249      * Abort the current server request.
10250      */
10251     abort : function(){
10252         if(this.isLoading()){
10253             this.destroyTrans(this.trans);
10254         }
10255     },
10256
10257     // private
10258     destroyTrans : function(trans, isLoaded){
10259         this.head.removeChild(document.getElementById(trans.scriptId));
10260         clearTimeout(trans.timeoutId);
10261         if(isLoaded){
10262             window[trans.cb] = undefined;
10263             try{
10264                 delete window[trans.cb];
10265             }catch(e){}
10266         }else{
10267             // if hasn't been loaded, wait for load to remove it to prevent script error
10268             window[trans.cb] = function(){
10269                 window[trans.cb] = undefined;
10270                 try{
10271                     delete window[trans.cb];
10272                 }catch(e){}
10273             };
10274         }
10275     },
10276
10277     // private
10278     handleResponse : function(o, trans){
10279         this.trans = false;
10280         this.destroyTrans(trans, true);
10281         var result;
10282         try {
10283             result = trans.reader.readRecords(o);
10284         }catch(e){
10285             this.fireEvent("loadexception", this, o, trans.arg, e);
10286             trans.callback.call(trans.scope||window, null, trans.arg, false);
10287             return;
10288         }
10289         this.fireEvent("load", this, o, trans.arg);
10290         trans.callback.call(trans.scope||window, result, trans.arg, true);
10291     },
10292
10293     // private
10294     handleFailure : function(trans){
10295         this.trans = false;
10296         this.destroyTrans(trans, false);
10297         this.fireEvent("loadexception", this, null, trans.arg);
10298         trans.callback.call(trans.scope||window, null, trans.arg, false);
10299     }
10300 });/*
10301  * Based on:
10302  * Ext JS Library 1.1.1
10303  * Copyright(c) 2006-2007, Ext JS, LLC.
10304  *
10305  * Originally Released Under LGPL - original licence link has changed is not relivant.
10306  *
10307  * Fork - LGPL
10308  * <script type="text/javascript">
10309  */
10310
10311 /**
10312  * @class Roo.data.JsonReader
10313  * @extends Roo.data.DataReader
10314  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10315  * based on mappings in a provided Roo.data.Record constructor.
10316  * 
10317  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10318  * in the reply previously. 
10319  * 
10320  * <p>
10321  * Example code:
10322  * <pre><code>
10323 var RecordDef = Roo.data.Record.create([
10324     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10325     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10326 ]);
10327 var myReader = new Roo.data.JsonReader({
10328     totalProperty: "results",    // The property which contains the total dataset size (optional)
10329     root: "rows",                // The property which contains an Array of row objects
10330     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10331 }, RecordDef);
10332 </code></pre>
10333  * <p>
10334  * This would consume a JSON file like this:
10335  * <pre><code>
10336 { 'results': 2, 'rows': [
10337     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10338     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10339 }
10340 </code></pre>
10341  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10342  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10343  * paged from the remote server.
10344  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10345  * @cfg {String} root name of the property which contains the Array of row objects.
10346  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10347  * @constructor
10348  * Create a new JsonReader
10349  * @param {Object} meta Metadata configuration options
10350  * @param {Object} recordType Either an Array of field definition objects,
10351  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10352  */
10353 Roo.data.JsonReader = function(meta, recordType){
10354     
10355     meta = meta || {};
10356     // set some defaults:
10357     Roo.applyIf(meta, {
10358         totalProperty: 'total',
10359         successProperty : 'success',
10360         root : 'data',
10361         id : 'id'
10362     });
10363     
10364     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10365 };
10366 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10367     
10368     /**
10369      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10370      * Used by Store query builder to append _requestMeta to params.
10371      * 
10372      */
10373     metaFromRemote : false,
10374     /**
10375      * This method is only used by a DataProxy which has retrieved data from a remote server.
10376      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10377      * @return {Object} data A data block which is used by an Roo.data.Store object as
10378      * a cache of Roo.data.Records.
10379      */
10380     read : function(response){
10381         var json = response.responseText;
10382        
10383         var o = /* eval:var:o */ eval("("+json+")");
10384         if(!o) {
10385             throw {message: "JsonReader.read: Json object not found"};
10386         }
10387         
10388         if(o.metaData){
10389             
10390             delete this.ef;
10391             this.metaFromRemote = true;
10392             this.meta = o.metaData;
10393             this.recordType = Roo.data.Record.create(o.metaData.fields);
10394             this.onMetaChange(this.meta, this.recordType, o);
10395         }
10396         return this.readRecords(o);
10397     },
10398
10399     // private function a store will implement
10400     onMetaChange : function(meta, recordType, o){
10401
10402     },
10403
10404     /**
10405          * @ignore
10406          */
10407     simpleAccess: function(obj, subsc) {
10408         return obj[subsc];
10409     },
10410
10411         /**
10412          * @ignore
10413          */
10414     getJsonAccessor: function(){
10415         var re = /[\[\.]/;
10416         return function(expr) {
10417             try {
10418                 return(re.test(expr))
10419                     ? new Function("obj", "return obj." + expr)
10420                     : function(obj){
10421                         return obj[expr];
10422                     };
10423             } catch(e){}
10424             return Roo.emptyFn;
10425         };
10426     }(),
10427
10428     /**
10429      * Create a data block containing Roo.data.Records from an XML document.
10430      * @param {Object} o An object which contains an Array of row objects in the property specified
10431      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10432      * which contains the total size of the dataset.
10433      * @return {Object} data A data block which is used by an Roo.data.Store object as
10434      * a cache of Roo.data.Records.
10435      */
10436     readRecords : function(o){
10437         /**
10438          * After any data loads, the raw JSON data is available for further custom processing.
10439          * @type Object
10440          */
10441         this.o = o;
10442         var s = this.meta, Record = this.recordType,
10443             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10444
10445 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10446         if (!this.ef) {
10447             if(s.totalProperty) {
10448                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10449                 }
10450                 if(s.successProperty) {
10451                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10452                 }
10453                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10454                 if (s.id) {
10455                         var g = this.getJsonAccessor(s.id);
10456                         this.getId = function(rec) {
10457                                 var r = g(rec);  
10458                                 return (r === undefined || r === "") ? null : r;
10459                         };
10460                 } else {
10461                         this.getId = function(){return null;};
10462                 }
10463             this.ef = [];
10464             for(var jj = 0; jj < fl; jj++){
10465                 f = fi[jj];
10466                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10467                 this.ef[jj] = this.getJsonAccessor(map);
10468             }
10469         }
10470
10471         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10472         if(s.totalProperty){
10473             var vt = parseInt(this.getTotal(o), 10);
10474             if(!isNaN(vt)){
10475                 totalRecords = vt;
10476             }
10477         }
10478         if(s.successProperty){
10479             var vs = this.getSuccess(o);
10480             if(vs === false || vs === 'false'){
10481                 success = false;
10482             }
10483         }
10484         var records = [];
10485         for(var i = 0; i < c; i++){
10486                 var n = root[i];
10487             var values = {};
10488             var id = this.getId(n);
10489             for(var j = 0; j < fl; j++){
10490                 f = fi[j];
10491             var v = this.ef[j](n);
10492             if (!f.convert) {
10493                 Roo.log('missing convert for ' + f.name);
10494                 Roo.log(f);
10495                 continue;
10496             }
10497             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10498             }
10499             var record = new Record(values, id);
10500             record.json = n;
10501             records[i] = record;
10502         }
10503         return {
10504             raw : o,
10505             success : success,
10506             records : records,
10507             totalRecords : totalRecords
10508         };
10509     }
10510 });/*
10511  * Based on:
10512  * Ext JS Library 1.1.1
10513  * Copyright(c) 2006-2007, Ext JS, LLC.
10514  *
10515  * Originally Released Under LGPL - original licence link has changed is not relivant.
10516  *
10517  * Fork - LGPL
10518  * <script type="text/javascript">
10519  */
10520
10521 /**
10522  * @class Roo.data.ArrayReader
10523  * @extends Roo.data.DataReader
10524  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10525  * Each element of that Array represents a row of data fields. The
10526  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10527  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10528  * <p>
10529  * Example code:.
10530  * <pre><code>
10531 var RecordDef = Roo.data.Record.create([
10532     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10533     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10534 ]);
10535 var myReader = new Roo.data.ArrayReader({
10536     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10537 }, RecordDef);
10538 </code></pre>
10539  * <p>
10540  * This would consume an Array like this:
10541  * <pre><code>
10542 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10543   </code></pre>
10544  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10545  * @constructor
10546  * Create a new JsonReader
10547  * @param {Object} meta Metadata configuration options.
10548  * @param {Object} recordType Either an Array of field definition objects
10549  * as specified to {@link Roo.data.Record#create},
10550  * or an {@link Roo.data.Record} object
10551  * created using {@link Roo.data.Record#create}.
10552  */
10553 Roo.data.ArrayReader = function(meta, recordType){
10554     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10555 };
10556
10557 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10558     /**
10559      * Create a data block containing Roo.data.Records from an XML document.
10560      * @param {Object} o An Array of row objects which represents the dataset.
10561      * @return {Object} data A data block which is used by an Roo.data.Store object as
10562      * a cache of Roo.data.Records.
10563      */
10564     readRecords : function(o){
10565         var sid = this.meta ? this.meta.id : null;
10566         var recordType = this.recordType, fields = recordType.prototype.fields;
10567         var records = [];
10568         var root = o;
10569             for(var i = 0; i < root.length; i++){
10570                     var n = root[i];
10571                 var values = {};
10572                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10573                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10574                 var f = fields.items[j];
10575                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10576                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10577                 v = f.convert(v);
10578                 values[f.name] = v;
10579             }
10580                 var record = new recordType(values, id);
10581                 record.json = n;
10582                 records[records.length] = record;
10583             }
10584             return {
10585                 records : records,
10586                 totalRecords : records.length
10587             };
10588     }
10589 });/*
10590  * - LGPL
10591  * * 
10592  */
10593
10594 /**
10595  * @class Roo.bootstrap.ComboBox
10596  * @extends Roo.bootstrap.TriggerField
10597  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10598  * @cfg {Boolean} append (true|false) default false
10599  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10600  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10601  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10602  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10603  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10604  * @constructor
10605  * Create a new ComboBox.
10606  * @param {Object} config Configuration options
10607  */
10608 Roo.bootstrap.ComboBox = function(config){
10609     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10610     this.addEvents({
10611         /**
10612          * @event expand
10613          * Fires when the dropdown list is expanded
10614              * @param {Roo.bootstrap.ComboBox} combo This combo box
10615              */
10616         'expand' : true,
10617         /**
10618          * @event collapse
10619          * Fires when the dropdown list is collapsed
10620              * @param {Roo.bootstrap.ComboBox} combo This combo box
10621              */
10622         'collapse' : true,
10623         /**
10624          * @event beforeselect
10625          * Fires before a list item is selected. Return false to cancel the selection.
10626              * @param {Roo.bootstrap.ComboBox} combo This combo box
10627              * @param {Roo.data.Record} record The data record returned from the underlying store
10628              * @param {Number} index The index of the selected item in the dropdown list
10629              */
10630         'beforeselect' : true,
10631         /**
10632          * @event select
10633          * Fires when a list item is selected
10634              * @param {Roo.bootstrap.ComboBox} combo This combo box
10635              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10636              * @param {Number} index The index of the selected item in the dropdown list
10637              */
10638         'select' : true,
10639         /**
10640          * @event beforequery
10641          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10642          * The event object passed has these properties:
10643              * @param {Roo.bootstrap.ComboBox} combo This combo box
10644              * @param {String} query The query
10645              * @param {Boolean} forceAll true to force "all" query
10646              * @param {Boolean} cancel true to cancel the query
10647              * @param {Object} e The query event object
10648              */
10649         'beforequery': true,
10650          /**
10651          * @event add
10652          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10653              * @param {Roo.bootstrap.ComboBox} combo This combo box
10654              */
10655         'add' : true,
10656         /**
10657          * @event edit
10658          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10659              * @param {Roo.bootstrap.ComboBox} combo This combo box
10660              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10661              */
10662         'edit' : true,
10663         /**
10664          * @event remove
10665          * Fires when the remove value from the combobox array
10666              * @param {Roo.bootstrap.ComboBox} combo This combo box
10667              */
10668         'remove' : true
10669         
10670     });
10671     
10672     this.item = [];
10673     this.tickItems = [];
10674     
10675     this.selectedIndex = -1;
10676     if(this.mode == 'local'){
10677         if(config.queryDelay === undefined){
10678             this.queryDelay = 10;
10679         }
10680         if(config.minChars === undefined){
10681             this.minChars = 0;
10682         }
10683     }
10684 };
10685
10686 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10687      
10688     /**
10689      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10690      * rendering into an Roo.Editor, defaults to false)
10691      */
10692     /**
10693      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10694      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10695      */
10696     /**
10697      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10698      */
10699     /**
10700      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10701      * the dropdown list (defaults to undefined, with no header element)
10702      */
10703
10704      /**
10705      * @cfg {String/Roo.Template} tpl The template to use to render the output
10706      */
10707      
10708      /**
10709      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10710      */
10711     listWidth: undefined,
10712     /**
10713      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10714      * mode = 'remote' or 'text' if mode = 'local')
10715      */
10716     displayField: undefined,
10717     /**
10718      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10719      * mode = 'remote' or 'value' if mode = 'local'). 
10720      * Note: use of a valueField requires the user make a selection
10721      * in order for a value to be mapped.
10722      */
10723     valueField: undefined,
10724     
10725     
10726     /**
10727      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10728      * field's data value (defaults to the underlying DOM element's name)
10729      */
10730     hiddenName: undefined,
10731     /**
10732      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10733      */
10734     listClass: '',
10735     /**
10736      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10737      */
10738     selectedClass: 'active',
10739     
10740     /**
10741      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10742      */
10743     shadow:'sides',
10744     /**
10745      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10746      * anchor positions (defaults to 'tl-bl')
10747      */
10748     listAlign: 'tl-bl?',
10749     /**
10750      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10751      */
10752     maxHeight: 300,
10753     /**
10754      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10755      * query specified by the allQuery config option (defaults to 'query')
10756      */
10757     triggerAction: 'query',
10758     /**
10759      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10760      * (defaults to 4, does not apply if editable = false)
10761      */
10762     minChars : 4,
10763     /**
10764      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10765      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10766      */
10767     typeAhead: false,
10768     /**
10769      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10770      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10771      */
10772     queryDelay: 500,
10773     /**
10774      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10775      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10776      */
10777     pageSize: 0,
10778     /**
10779      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10780      * when editable = true (defaults to false)
10781      */
10782     selectOnFocus:false,
10783     /**
10784      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10785      */
10786     queryParam: 'query',
10787     /**
10788      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10789      * when mode = 'remote' (defaults to 'Loading...')
10790      */
10791     loadingText: 'Loading...',
10792     /**
10793      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10794      */
10795     resizable: false,
10796     /**
10797      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10798      */
10799     handleHeight : 8,
10800     /**
10801      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10802      * traditional select (defaults to true)
10803      */
10804     editable: true,
10805     /**
10806      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10807      */
10808     allQuery: '',
10809     /**
10810      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10811      */
10812     mode: 'remote',
10813     /**
10814      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10815      * listWidth has a higher value)
10816      */
10817     minListWidth : 70,
10818     /**
10819      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10820      * allow the user to set arbitrary text into the field (defaults to false)
10821      */
10822     forceSelection:false,
10823     /**
10824      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10825      * if typeAhead = true (defaults to 250)
10826      */
10827     typeAheadDelay : 250,
10828     /**
10829      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10830      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10831      */
10832     valueNotFoundText : undefined,
10833     /**
10834      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10835      */
10836     blockFocus : false,
10837     
10838     /**
10839      * @cfg {Boolean} disableClear Disable showing of clear button.
10840      */
10841     disableClear : false,
10842     /**
10843      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10844      */
10845     alwaysQuery : false,
10846     
10847     /**
10848      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10849      */
10850     multiple : false,
10851     
10852     /**
10853      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10854      */
10855     invalidClass : "has-warning",
10856     
10857     /**
10858      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10859      */
10860     validClass : "has-success",
10861     
10862     //private
10863     addicon : false,
10864     editicon: false,
10865     
10866     page: 0,
10867     hasQuery: false,
10868     append: false,
10869     loadNext: false,
10870     autoFocus : true,
10871     tickable : false,
10872     btnPosition : 'right',
10873     triggerList : true,
10874     showToggleBtn : true,
10875     // element that contains real text value.. (when hidden is used..)
10876     
10877     getAutoCreate : function()
10878     {
10879         var cfg = false;
10880         
10881         /*
10882          *  Normal ComboBox
10883          */
10884         if(!this.tickable){
10885             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10886             return cfg;
10887         }
10888         
10889         /*
10890          *  ComboBox with tickable selections
10891          */
10892              
10893         var align = this.labelAlign || this.parentLabelAlign();
10894         
10895         cfg = {
10896             cls : 'form-group roo-combobox-tickable' //input-group
10897         };
10898         
10899         
10900         var buttons = {
10901             tag : 'div',
10902             cls : 'tickable-buttons',
10903             cn : [
10904                 {
10905                     tag : 'button',
10906                     type : 'button',
10907                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10908                     html : 'Edit'
10909                 },
10910                 {
10911                     tag : 'button',
10912                     type : 'button',
10913                     name : 'ok',
10914                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10915                     html : 'Done'
10916                 },
10917                 {
10918                     tag : 'button',
10919                     type : 'button',
10920                     name : 'cancel',
10921                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10922                     html : 'Cancel'
10923                 }
10924             ]
10925         };
10926         
10927         var _this = this;
10928         Roo.each(buttons.cn, function(c){
10929             if (_this.size) {
10930                 c.cls += ' btn-' + _this.size;
10931             }
10932
10933             if (_this.disabled) {
10934                 c.disabled = true;
10935             }
10936         });
10937         
10938         var box = {
10939             tag: 'div',
10940             cn: [
10941                 {
10942                     tag: 'input',
10943                     type : 'hidden',
10944                     cls: 'form-hidden-field'
10945                 },
10946                 {
10947                     tag: 'ul',
10948                     cls: 'select2-choices',
10949                     cn:[
10950                         {
10951                             tag: 'li',
10952                             cls: 'select2-search-field',
10953                             cn: [
10954
10955                                 buttons
10956                             ]
10957                         }
10958                     ]
10959                 }
10960             ]
10961         }
10962         
10963         var combobox = {
10964             cls: 'select2-container input-group select2-container-multi',
10965             cn: [
10966                 box
10967 //                {
10968 //                    tag: 'ul',
10969 //                    cls: 'typeahead typeahead-long dropdown-menu',
10970 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
10971 //                }
10972             ]
10973         };
10974         
10975         if(this.hasFeedback && !this.allowBlank){
10976             
10977             var feedback = {
10978                 tag: 'span',
10979                 cls: 'glyphicon form-control-feedback'
10980             };
10981
10982             combobox.cn.push(feedback);
10983         }
10984         
10985         if (align ==='left' && this.fieldLabel.length) {
10986             
10987                 Roo.log("left and has label");
10988                 cfg.cn = [
10989                     
10990                     {
10991                         tag: 'label',
10992                         'for' :  id,
10993                         cls : 'control-label col-sm-' + this.labelWidth,
10994                         html : this.fieldLabel
10995                         
10996                     },
10997                     {
10998                         cls : "col-sm-" + (12 - this.labelWidth), 
10999                         cn: [
11000                             combobox
11001                         ]
11002                     }
11003                     
11004                 ];
11005         } else if ( this.fieldLabel.length) {
11006                 Roo.log(" label");
11007                  cfg.cn = [
11008                    
11009                     {
11010                         tag: 'label',
11011                         //cls : 'input-group-addon',
11012                         html : this.fieldLabel
11013                         
11014                     },
11015                     
11016                     combobox
11017                     
11018                 ];
11019
11020         } else {
11021             
11022                 Roo.log(" no label && no align");
11023                 cfg = combobox
11024                      
11025                 
11026         }
11027          
11028         var settings=this;
11029         ['xs','sm','md','lg'].map(function(size){
11030             if (settings[size]) {
11031                 cfg.cls += ' col-' + size + '-' + settings[size];
11032             }
11033         });
11034         
11035         return cfg;
11036         
11037     },
11038     
11039     // private
11040     initEvents: function()
11041     {
11042         
11043         if (!this.store) {
11044             throw "can not find store for combo";
11045         }
11046         this.store = Roo.factory(this.store, Roo.data);
11047         
11048         if(this.tickable){
11049             this.initTickableEvents();
11050             return;
11051         }
11052         
11053         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11054         
11055         if(this.hiddenName){
11056             
11057             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11058             
11059             this.hiddenField.dom.value =
11060                 this.hiddenValue !== undefined ? this.hiddenValue :
11061                 this.value !== undefined ? this.value : '';
11062
11063             // prevent input submission
11064             this.el.dom.removeAttribute('name');
11065             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11066              
11067              
11068         }
11069         //if(Roo.isGecko){
11070         //    this.el.dom.setAttribute('autocomplete', 'off');
11071         //}
11072         
11073         var cls = 'x-combo-list';
11074         
11075         //this.list = new Roo.Layer({
11076         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11077         //});
11078         
11079         var _this = this;
11080         
11081         (function(){
11082             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11083             _this.list.setWidth(lw);
11084         }).defer(100);
11085         
11086         this.list.on('mouseover', this.onViewOver, this);
11087         this.list.on('mousemove', this.onViewMove, this);
11088         
11089         this.list.on('scroll', this.onViewScroll, this);
11090         
11091         /*
11092         this.list.swallowEvent('mousewheel');
11093         this.assetHeight = 0;
11094
11095         if(this.title){
11096             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11097             this.assetHeight += this.header.getHeight();
11098         }
11099
11100         this.innerList = this.list.createChild({cls:cls+'-inner'});
11101         this.innerList.on('mouseover', this.onViewOver, this);
11102         this.innerList.on('mousemove', this.onViewMove, this);
11103         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11104         
11105         if(this.allowBlank && !this.pageSize && !this.disableClear){
11106             this.footer = this.list.createChild({cls:cls+'-ft'});
11107             this.pageTb = new Roo.Toolbar(this.footer);
11108            
11109         }
11110         if(this.pageSize){
11111             this.footer = this.list.createChild({cls:cls+'-ft'});
11112             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11113                     {pageSize: this.pageSize});
11114             
11115         }
11116         
11117         if (this.pageTb && this.allowBlank && !this.disableClear) {
11118             var _this = this;
11119             this.pageTb.add(new Roo.Toolbar.Fill(), {
11120                 cls: 'x-btn-icon x-btn-clear',
11121                 text: '&#160;',
11122                 handler: function()
11123                 {
11124                     _this.collapse();
11125                     _this.clearValue();
11126                     _this.onSelect(false, -1);
11127                 }
11128             });
11129         }
11130         if (this.footer) {
11131             this.assetHeight += this.footer.getHeight();
11132         }
11133         */
11134             
11135         if(!this.tpl){
11136             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11137         }
11138
11139         this.view = new Roo.View(this.list, this.tpl, {
11140             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11141         });
11142         //this.view.wrapEl.setDisplayed(false);
11143         this.view.on('click', this.onViewClick, this);
11144         
11145         
11146         
11147         this.store.on('beforeload', this.onBeforeLoad, this);
11148         this.store.on('load', this.onLoad, this);
11149         this.store.on('loadexception', this.onLoadException, this);
11150         /*
11151         if(this.resizable){
11152             this.resizer = new Roo.Resizable(this.list,  {
11153                pinned:true, handles:'se'
11154             });
11155             this.resizer.on('resize', function(r, w, h){
11156                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11157                 this.listWidth = w;
11158                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11159                 this.restrictHeight();
11160             }, this);
11161             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11162         }
11163         */
11164         if(!this.editable){
11165             this.editable = true;
11166             this.setEditable(false);
11167         }
11168         
11169         /*
11170         
11171         if (typeof(this.events.add.listeners) != 'undefined') {
11172             
11173             this.addicon = this.wrap.createChild(
11174                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11175        
11176             this.addicon.on('click', function(e) {
11177                 this.fireEvent('add', this);
11178             }, this);
11179         }
11180         if (typeof(this.events.edit.listeners) != 'undefined') {
11181             
11182             this.editicon = this.wrap.createChild(
11183                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11184             if (this.addicon) {
11185                 this.editicon.setStyle('margin-left', '40px');
11186             }
11187             this.editicon.on('click', function(e) {
11188                 
11189                 // we fire even  if inothing is selected..
11190                 this.fireEvent('edit', this, this.lastData );
11191                 
11192             }, this);
11193         }
11194         */
11195         
11196         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11197             "up" : function(e){
11198                 this.inKeyMode = true;
11199                 this.selectPrev();
11200             },
11201
11202             "down" : function(e){
11203                 if(!this.isExpanded()){
11204                     this.onTriggerClick();
11205                 }else{
11206                     this.inKeyMode = true;
11207                     this.selectNext();
11208                 }
11209             },
11210
11211             "enter" : function(e){
11212 //                this.onViewClick();
11213                 //return true;
11214                 this.collapse();
11215                 
11216                 if(this.fireEvent("specialkey", this, e)){
11217                     this.onViewClick(false);
11218                 }
11219                 
11220                 return true;
11221             },
11222
11223             "esc" : function(e){
11224                 this.collapse();
11225             },
11226
11227             "tab" : function(e){
11228                 this.collapse();
11229                 
11230                 if(this.fireEvent("specialkey", this, e)){
11231                     this.onViewClick(false);
11232                 }
11233                 
11234                 return true;
11235             },
11236
11237             scope : this,
11238
11239             doRelay : function(foo, bar, hname){
11240                 if(hname == 'down' || this.scope.isExpanded()){
11241                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11242                 }
11243                 return true;
11244             },
11245
11246             forceKeyDown: true
11247         });
11248         
11249         
11250         this.queryDelay = Math.max(this.queryDelay || 10,
11251                 this.mode == 'local' ? 10 : 250);
11252         
11253         
11254         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11255         
11256         if(this.typeAhead){
11257             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11258         }
11259         if(this.editable !== false){
11260             this.inputEl().on("keyup", this.onKeyUp, this);
11261         }
11262         if(this.forceSelection){
11263             this.inputEl().on('blur', this.doForce, this);
11264         }
11265         
11266         if(this.multiple){
11267             this.choices = this.el.select('ul.select2-choices', true).first();
11268             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11269         }
11270     },
11271     
11272     initTickableEvents: function()
11273     {   
11274         this.createList();
11275         
11276         if(this.hiddenName){
11277             
11278             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11279             
11280             this.hiddenField.dom.value =
11281                 this.hiddenValue !== undefined ? this.hiddenValue :
11282                 this.value !== undefined ? this.value : '';
11283
11284             // prevent input submission
11285             this.el.dom.removeAttribute('name');
11286             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11287              
11288              
11289         }
11290         
11291 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11292         
11293         this.choices = this.el.select('ul.select2-choices', true).first();
11294         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11295         if(this.triggerList){
11296             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11297         }
11298          
11299         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11300         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11301         
11302         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11303         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11304         
11305         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11306         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11307         
11308         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11309         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11310         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11311         
11312         this.okBtn.hide();
11313         this.cancelBtn.hide();
11314         
11315         var _this = this;
11316         
11317         (function(){
11318             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11319             _this.list.setWidth(lw);
11320         }).defer(100);
11321         
11322         this.list.on('mouseover', this.onViewOver, this);
11323         this.list.on('mousemove', this.onViewMove, this);
11324         
11325         this.list.on('scroll', this.onViewScroll, this);
11326         
11327         if(!this.tpl){
11328             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>';
11329         }
11330
11331         this.view = new Roo.View(this.list, this.tpl, {
11332             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11333         });
11334         
11335         //this.view.wrapEl.setDisplayed(false);
11336         this.view.on('click', this.onViewClick, this);
11337         
11338         
11339         
11340         this.store.on('beforeload', this.onBeforeLoad, this);
11341         this.store.on('load', this.onLoad, this);
11342         this.store.on('loadexception', this.onLoadException, this);
11343         
11344 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11345 //            "up" : function(e){
11346 //                this.inKeyMode = true;
11347 //                this.selectPrev();
11348 //            },
11349 //
11350 //            "down" : function(e){
11351 //                if(!this.isExpanded()){
11352 //                    this.onTriggerClick();
11353 //                }else{
11354 //                    this.inKeyMode = true;
11355 //                    this.selectNext();
11356 //                }
11357 //            },
11358 //
11359 //            "enter" : function(e){
11360 ////                this.onViewClick();
11361 //                //return true;
11362 //                this.collapse();
11363 //                
11364 //                if(this.fireEvent("specialkey", this, e)){
11365 //                    this.onViewClick(false);
11366 //                }
11367 //                
11368 //                return true;
11369 //            },
11370 //
11371 //            "esc" : function(e){
11372 //                this.collapse();
11373 //            },
11374 //
11375 //            "tab" : function(e){
11376 //                this.collapse();
11377 //                
11378 //                if(this.fireEvent("specialkey", this, e)){
11379 //                    this.onViewClick(false);
11380 //                }
11381 //                
11382 //                return true;
11383 //            },
11384 //
11385 //            scope : this,
11386 //
11387 //            doRelay : function(foo, bar, hname){
11388 //                if(hname == 'down' || this.scope.isExpanded()){
11389 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11390 //                }
11391 //                return true;
11392 //            },
11393 //
11394 //            forceKeyDown: true
11395 //        });
11396         
11397         
11398         this.queryDelay = Math.max(this.queryDelay || 10,
11399                 this.mode == 'local' ? 10 : 250);
11400         
11401         
11402         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11403         
11404         if(this.typeAhead){
11405             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11406         }
11407         
11408     },
11409
11410     onDestroy : function(){
11411         if(this.view){
11412             this.view.setStore(null);
11413             this.view.el.removeAllListeners();
11414             this.view.el.remove();
11415             this.view.purgeListeners();
11416         }
11417         if(this.list){
11418             this.list.dom.innerHTML  = '';
11419         }
11420         
11421         if(this.store){
11422             this.store.un('beforeload', this.onBeforeLoad, this);
11423             this.store.un('load', this.onLoad, this);
11424             this.store.un('loadexception', this.onLoadException, this);
11425         }
11426         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11427     },
11428
11429     // private
11430     fireKey : function(e){
11431         if(e.isNavKeyPress() && !this.list.isVisible()){
11432             this.fireEvent("specialkey", this, e);
11433         }
11434     },
11435
11436     // private
11437     onResize: function(w, h){
11438 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11439 //        
11440 //        if(typeof w != 'number'){
11441 //            // we do not handle it!?!?
11442 //            return;
11443 //        }
11444 //        var tw = this.trigger.getWidth();
11445 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11446 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11447 //        var x = w - tw;
11448 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11449 //            
11450 //        //this.trigger.setStyle('left', x+'px');
11451 //        
11452 //        if(this.list && this.listWidth === undefined){
11453 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11454 //            this.list.setWidth(lw);
11455 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11456 //        }
11457         
11458     
11459         
11460     },
11461
11462     /**
11463      * Allow or prevent the user from directly editing the field text.  If false is passed,
11464      * the user will only be able to select from the items defined in the dropdown list.  This method
11465      * is the runtime equivalent of setting the 'editable' config option at config time.
11466      * @param {Boolean} value True to allow the user to directly edit the field text
11467      */
11468     setEditable : function(value){
11469         if(value == this.editable){
11470             return;
11471         }
11472         this.editable = value;
11473         if(!value){
11474             this.inputEl().dom.setAttribute('readOnly', true);
11475             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11476             this.inputEl().addClass('x-combo-noedit');
11477         }else{
11478             this.inputEl().dom.setAttribute('readOnly', false);
11479             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11480             this.inputEl().removeClass('x-combo-noedit');
11481         }
11482     },
11483
11484     // private
11485     
11486     onBeforeLoad : function(combo,opts){
11487         if(!this.hasFocus){
11488             return;
11489         }
11490          if (!opts.add) {
11491             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11492          }
11493         this.restrictHeight();
11494         this.selectedIndex = -1;
11495     },
11496
11497     // private
11498     onLoad : function(){
11499         
11500         this.hasQuery = false;
11501         
11502         if(!this.hasFocus){
11503             return;
11504         }
11505         
11506         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11507             this.loading.hide();
11508         }
11509         
11510         if(this.store.getCount() > 0){
11511             this.expand();
11512 //            this.restrictHeight();
11513             if(this.lastQuery == this.allQuery){
11514                 if(this.editable && !this.tickable){
11515                     this.inputEl().dom.select();
11516                 }
11517                 
11518                 if(
11519                     !this.selectByValue(this.value, true) &&
11520                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11521                     this.store.lastOptions.add != true)
11522                 ){
11523                     this.select(0, true);
11524                 }
11525             }else{
11526                 if(this.autoFocus){
11527                     this.selectNext();
11528                 }
11529                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11530                     this.taTask.delay(this.typeAheadDelay);
11531                 }
11532             }
11533         }else{
11534             this.onEmptyResults();
11535         }
11536         
11537         //this.el.focus();
11538     },
11539     // private
11540     onLoadException : function()
11541     {
11542         this.hasQuery = false;
11543         
11544         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11545             this.loading.hide();
11546         }
11547         
11548         this.collapse();
11549         Roo.log(this.store.reader.jsonData);
11550         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11551             // fixme
11552             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11553         }
11554         
11555         
11556     },
11557     // private
11558     onTypeAhead : function(){
11559         if(this.store.getCount() > 0){
11560             var r = this.store.getAt(0);
11561             var newValue = r.data[this.displayField];
11562             var len = newValue.length;
11563             var selStart = this.getRawValue().length;
11564             
11565             if(selStart != len){
11566                 this.setRawValue(newValue);
11567                 this.selectText(selStart, newValue.length);
11568             }
11569         }
11570     },
11571
11572     // private
11573     onSelect : function(record, index){
11574         
11575         if(this.fireEvent('beforeselect', this, record, index) !== false){
11576         
11577             this.setFromData(index > -1 ? record.data : false);
11578             
11579             this.collapse();
11580             this.fireEvent('select', this, record, index);
11581         }
11582     },
11583
11584     /**
11585      * Returns the currently selected field value or empty string if no value is set.
11586      * @return {String} value The selected value
11587      */
11588     getValue : function(){
11589         
11590         if(this.multiple){
11591             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11592         }
11593         
11594         if(this.valueField){
11595             return typeof this.value != 'undefined' ? this.value : '';
11596         }else{
11597             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11598         }
11599     },
11600
11601     /**
11602      * Clears any text/value currently set in the field
11603      */
11604     clearValue : function(){
11605         if(this.hiddenField){
11606             this.hiddenField.dom.value = '';
11607         }
11608         this.value = '';
11609         this.setRawValue('');
11610         this.lastSelectionText = '';
11611         this.lastData = false;
11612         
11613     },
11614
11615     /**
11616      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11617      * will be displayed in the field.  If the value does not match the data value of an existing item,
11618      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11619      * Otherwise the field will be blank (although the value will still be set).
11620      * @param {String} value The value to match
11621      */
11622     setValue : function(v){
11623         if(this.multiple){
11624             this.syncValue();
11625             return;
11626         }
11627         
11628         var text = v;
11629         if(this.valueField){
11630             var r = this.findRecord(this.valueField, v);
11631             if(r){
11632                 text = r.data[this.displayField];
11633             }else if(this.valueNotFoundText !== undefined){
11634                 text = this.valueNotFoundText;
11635             }
11636         }
11637         this.lastSelectionText = text;
11638         if(this.hiddenField){
11639             this.hiddenField.dom.value = v;
11640         }
11641         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11642         this.value = v;
11643     },
11644     /**
11645      * @property {Object} the last set data for the element
11646      */
11647     
11648     lastData : false,
11649     /**
11650      * Sets the value of the field based on a object which is related to the record format for the store.
11651      * @param {Object} value the value to set as. or false on reset?
11652      */
11653     setFromData : function(o){
11654         
11655         if(this.multiple){
11656             this.addItem(o);
11657             return;
11658         }
11659             
11660         var dv = ''; // display value
11661         var vv = ''; // value value..
11662         this.lastData = o;
11663         if (this.displayField) {
11664             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11665         } else {
11666             // this is an error condition!!!
11667             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11668         }
11669         
11670         if(this.valueField){
11671             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11672         }
11673         
11674         if(this.hiddenField){
11675             this.hiddenField.dom.value = vv;
11676             
11677             this.lastSelectionText = dv;
11678             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11679             this.value = vv;
11680             return;
11681         }
11682         // no hidden field.. - we store the value in 'value', but still display
11683         // display field!!!!
11684         this.lastSelectionText = dv;
11685         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11686         this.value = vv;
11687         
11688         
11689     },
11690     // private
11691     reset : function(){
11692         // overridden so that last data is reset..
11693         this.setValue(this.originalValue);
11694         this.clearInvalid();
11695         this.lastData = false;
11696         if (this.view) {
11697             this.view.clearSelections();
11698         }
11699     },
11700     // private
11701     findRecord : function(prop, value){
11702         var record;
11703         if(this.store.getCount() > 0){
11704             this.store.each(function(r){
11705                 if(r.data[prop] == value){
11706                     record = r;
11707                     return false;
11708                 }
11709                 return true;
11710             });
11711         }
11712         return record;
11713     },
11714     
11715     getName: function()
11716     {
11717         // returns hidden if it's set..
11718         if (!this.rendered) {return ''};
11719         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11720         
11721     },
11722     // private
11723     onViewMove : function(e, t){
11724         this.inKeyMode = false;
11725     },
11726
11727     // private
11728     onViewOver : function(e, t){
11729         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11730             return;
11731         }
11732         var item = this.view.findItemFromChild(t);
11733         
11734         if(item){
11735             var index = this.view.indexOf(item);
11736             this.select(index, false);
11737         }
11738     },
11739
11740     // private
11741     onViewClick : function(view, doFocus, el, e)
11742     {
11743         var index = this.view.getSelectedIndexes()[0];
11744         
11745         var r = this.store.getAt(index);
11746         
11747         if(this.tickable){
11748             
11749             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11750                 return;
11751             }
11752             
11753             var rm = false;
11754             var _this = this;
11755             
11756             Roo.each(this.tickItems, function(v,k){
11757                 
11758                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11759                     _this.tickItems.splice(k, 1);
11760                     rm = true;
11761                     return;
11762                 }
11763             });
11764             
11765             if(rm){
11766                 return;
11767             }
11768             
11769             this.tickItems.push(r.data);
11770             return;
11771         }
11772         
11773         if(r){
11774             this.onSelect(r, index);
11775         }
11776         if(doFocus !== false && !this.blockFocus){
11777             this.inputEl().focus();
11778         }
11779     },
11780
11781     // private
11782     restrictHeight : function(){
11783         //this.innerList.dom.style.height = '';
11784         //var inner = this.innerList.dom;
11785         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11786         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11787         //this.list.beginUpdate();
11788         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11789         this.list.alignTo(this.inputEl(), this.listAlign);
11790         this.list.alignTo(this.inputEl(), this.listAlign);
11791         //this.list.endUpdate();
11792     },
11793
11794     // private
11795     onEmptyResults : function(){
11796         this.collapse();
11797     },
11798
11799     /**
11800      * Returns true if the dropdown list is expanded, else false.
11801      */
11802     isExpanded : function(){
11803         return this.list.isVisible();
11804     },
11805
11806     /**
11807      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11808      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11809      * @param {String} value The data value of the item to select
11810      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11811      * selected item if it is not currently in view (defaults to true)
11812      * @return {Boolean} True if the value matched an item in the list, else false
11813      */
11814     selectByValue : function(v, scrollIntoView){
11815         if(v !== undefined && v !== null){
11816             var r = this.findRecord(this.valueField || this.displayField, v);
11817             if(r){
11818                 this.select(this.store.indexOf(r), scrollIntoView);
11819                 return true;
11820             }
11821         }
11822         return false;
11823     },
11824
11825     /**
11826      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11827      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11828      * @param {Number} index The zero-based index of the list item to select
11829      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11830      * selected item if it is not currently in view (defaults to true)
11831      */
11832     select : function(index, scrollIntoView){
11833         this.selectedIndex = index;
11834         this.view.select(index);
11835         if(scrollIntoView !== false){
11836             var el = this.view.getNode(index);
11837             if(el && !this.multiple && !this.tickable){
11838                 this.list.scrollChildIntoView(el, false);
11839             }
11840         }
11841     },
11842
11843     // private
11844     selectNext : function(){
11845         var ct = this.store.getCount();
11846         if(ct > 0){
11847             if(this.selectedIndex == -1){
11848                 this.select(0);
11849             }else if(this.selectedIndex < ct-1){
11850                 this.select(this.selectedIndex+1);
11851             }
11852         }
11853     },
11854
11855     // private
11856     selectPrev : function(){
11857         var ct = this.store.getCount();
11858         if(ct > 0){
11859             if(this.selectedIndex == -1){
11860                 this.select(0);
11861             }else if(this.selectedIndex != 0){
11862                 this.select(this.selectedIndex-1);
11863             }
11864         }
11865     },
11866
11867     // private
11868     onKeyUp : function(e){
11869         if(this.editable !== false && !e.isSpecialKey()){
11870             this.lastKey = e.getKey();
11871             this.dqTask.delay(this.queryDelay);
11872         }
11873     },
11874
11875     // private
11876     validateBlur : function(){
11877         return !this.list || !this.list.isVisible();   
11878     },
11879
11880     // private
11881     initQuery : function(){
11882         this.doQuery(this.getRawValue());
11883     },
11884
11885     // private
11886     doForce : function(){
11887         if(this.inputEl().dom.value.length > 0){
11888             this.inputEl().dom.value =
11889                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11890              
11891         }
11892     },
11893
11894     /**
11895      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11896      * query allowing the query action to be canceled if needed.
11897      * @param {String} query The SQL query to execute
11898      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11899      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11900      * saved in the current store (defaults to false)
11901      */
11902     doQuery : function(q, forceAll){
11903         
11904         if(q === undefined || q === null){
11905             q = '';
11906         }
11907         var qe = {
11908             query: q,
11909             forceAll: forceAll,
11910             combo: this,
11911             cancel:false
11912         };
11913         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11914             return false;
11915         }
11916         q = qe.query;
11917         
11918         forceAll = qe.forceAll;
11919         if(forceAll === true || (q.length >= this.minChars)){
11920             
11921             this.hasQuery = true;
11922             
11923             if(this.lastQuery != q || this.alwaysQuery){
11924                 this.lastQuery = q;
11925                 if(this.mode == 'local'){
11926                     this.selectedIndex = -1;
11927                     if(forceAll){
11928                         this.store.clearFilter();
11929                     }else{
11930                         this.store.filter(this.displayField, q);
11931                     }
11932                     this.onLoad();
11933                 }else{
11934                     this.store.baseParams[this.queryParam] = q;
11935                     
11936                     var options = {params : this.getParams(q)};
11937                     
11938                     if(this.loadNext){
11939                         options.add = true;
11940                         options.params.start = this.page * this.pageSize;
11941                     }
11942                     
11943                     this.store.load(options);
11944                     /*
11945                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11946                      *  we should expand the list on onLoad
11947                      *  so command out it
11948                      */
11949 //                    this.expand();
11950                 }
11951             }else{
11952                 this.selectedIndex = -1;
11953                 this.onLoad();   
11954             }
11955         }
11956         
11957         this.loadNext = false;
11958     },
11959
11960     // private
11961     getParams : function(q){
11962         var p = {};
11963         //p[this.queryParam] = q;
11964         
11965         if(this.pageSize){
11966             p.start = 0;
11967             p.limit = this.pageSize;
11968         }
11969         return p;
11970     },
11971
11972     /**
11973      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11974      */
11975     collapse : function(){
11976         if(!this.isExpanded()){
11977             return;
11978         }
11979         
11980         this.list.hide();
11981         
11982         if(this.tickable){
11983             this.hasFocus = false;
11984             this.okBtn.hide();
11985             this.cancelBtn.hide();
11986             this.trigger.show();
11987         }
11988         
11989         Roo.get(document).un('mousedown', this.collapseIf, this);
11990         Roo.get(document).un('mousewheel', this.collapseIf, this);
11991         if (!this.editable) {
11992             Roo.get(document).un('keydown', this.listKeyPress, this);
11993         }
11994         this.fireEvent('collapse', this);
11995     },
11996
11997     // private
11998     collapseIf : function(e){
11999         var in_combo  = e.within(this.el);
12000         var in_list =  e.within(this.list);
12001         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12002         
12003         if (in_combo || in_list || is_list) {
12004             //e.stopPropagation();
12005             return;
12006         }
12007         
12008         if(this.tickable){
12009             this.onTickableFooterButtonClick(e, false, false);
12010         }
12011
12012         this.collapse();
12013         
12014     },
12015
12016     /**
12017      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12018      */
12019     expand : function(){
12020        
12021         if(this.isExpanded() || !this.hasFocus){
12022             return;
12023         }
12024         
12025         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12026         this.list.setWidth(lw);
12027         
12028         
12029          Roo.log('expand');
12030         
12031         this.list.show();
12032         
12033         this.restrictHeight();
12034         
12035         if(this.tickable){
12036             
12037             this.tickItems = Roo.apply([], this.item);
12038             
12039             this.okBtn.show();
12040             this.cancelBtn.show();
12041             this.trigger.hide();
12042             
12043         }
12044         
12045         Roo.get(document).on('mousedown', this.collapseIf, this);
12046         Roo.get(document).on('mousewheel', this.collapseIf, this);
12047         if (!this.editable) {
12048             Roo.get(document).on('keydown', this.listKeyPress, this);
12049         }
12050         
12051         this.fireEvent('expand', this);
12052     },
12053
12054     // private
12055     // Implements the default empty TriggerField.onTriggerClick function
12056     onTriggerClick : function(e)
12057     {
12058         Roo.log('trigger click');
12059         
12060         if(this.disabled || !this.triggerList){
12061             return;
12062         }
12063         
12064         this.page = 0;
12065         this.loadNext = false;
12066         
12067         if(this.isExpanded()){
12068             this.collapse();
12069             if (!this.blockFocus) {
12070                 this.inputEl().focus();
12071             }
12072             
12073         }else {
12074             this.hasFocus = true;
12075             if(this.triggerAction == 'all') {
12076                 this.doQuery(this.allQuery, true);
12077             } else {
12078                 this.doQuery(this.getRawValue());
12079             }
12080             if (!this.blockFocus) {
12081                 this.inputEl().focus();
12082             }
12083         }
12084     },
12085     
12086     onTickableTriggerClick : function(e)
12087     {
12088         if(this.disabled){
12089             return;
12090         }
12091         
12092         this.page = 0;
12093         this.loadNext = false;
12094         this.hasFocus = true;
12095         
12096         if(this.triggerAction == 'all') {
12097             this.doQuery(this.allQuery, true);
12098         } else {
12099             this.doQuery(this.getRawValue());
12100         }
12101     },
12102     
12103     onSearchFieldClick : function(e)
12104     {
12105         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12106             this.onTickableFooterButtonClick(e, false, false);
12107             return;
12108         }
12109         
12110         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12111             return;
12112         }
12113         
12114         this.page = 0;
12115         this.loadNext = false;
12116         this.hasFocus = true;
12117         
12118         if(this.triggerAction == 'all') {
12119             this.doQuery(this.allQuery, true);
12120         } else {
12121             this.doQuery(this.getRawValue());
12122         }
12123     },
12124     
12125     listKeyPress : function(e)
12126     {
12127         //Roo.log('listkeypress');
12128         // scroll to first matching element based on key pres..
12129         if (e.isSpecialKey()) {
12130             return false;
12131         }
12132         var k = String.fromCharCode(e.getKey()).toUpperCase();
12133         //Roo.log(k);
12134         var match  = false;
12135         var csel = this.view.getSelectedNodes();
12136         var cselitem = false;
12137         if (csel.length) {
12138             var ix = this.view.indexOf(csel[0]);
12139             cselitem  = this.store.getAt(ix);
12140             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12141                 cselitem = false;
12142             }
12143             
12144         }
12145         
12146         this.store.each(function(v) { 
12147             if (cselitem) {
12148                 // start at existing selection.
12149                 if (cselitem.id == v.id) {
12150                     cselitem = false;
12151                 }
12152                 return true;
12153             }
12154                 
12155             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12156                 match = this.store.indexOf(v);
12157                 return false;
12158             }
12159             return true;
12160         }, this);
12161         
12162         if (match === false) {
12163             return true; // no more action?
12164         }
12165         // scroll to?
12166         this.view.select(match);
12167         var sn = Roo.get(this.view.getSelectedNodes()[0])
12168         sn.scrollIntoView(sn.dom.parentNode, false);
12169     },
12170     
12171     onViewScroll : function(e, t){
12172         
12173         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){
12174             return;
12175         }
12176         
12177         this.hasQuery = true;
12178         
12179         this.loading = this.list.select('.loading', true).first();
12180         
12181         if(this.loading === null){
12182             this.list.createChild({
12183                 tag: 'div',
12184                 cls: 'loading select2-more-results select2-active',
12185                 html: 'Loading more results...'
12186             })
12187             
12188             this.loading = this.list.select('.loading', true).first();
12189             
12190             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12191             
12192             this.loading.hide();
12193         }
12194         
12195         this.loading.show();
12196         
12197         var _combo = this;
12198         
12199         this.page++;
12200         this.loadNext = true;
12201         
12202         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12203         
12204         return;
12205     },
12206     
12207     addItem : function(o)
12208     {   
12209         var dv = ''; // display value
12210         
12211         if (this.displayField) {
12212             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12213         } else {
12214             // this is an error condition!!!
12215             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12216         }
12217         
12218         if(!dv.length){
12219             return;
12220         }
12221         
12222         var choice = this.choices.createChild({
12223             tag: 'li',
12224             cls: 'select2-search-choice',
12225             cn: [
12226                 {
12227                     tag: 'div',
12228                     html: dv
12229                 },
12230                 {
12231                     tag: 'a',
12232                     href: '#',
12233                     cls: 'select2-search-choice-close',
12234                     tabindex: '-1'
12235                 }
12236             ]
12237             
12238         }, this.searchField);
12239         
12240         var close = choice.select('a.select2-search-choice-close', true).first()
12241         
12242         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12243         
12244         this.item.push(o);
12245         
12246         this.lastData = o;
12247         
12248         this.syncValue();
12249         
12250         this.inputEl().dom.value = '';
12251         
12252         this.validate();
12253     },
12254     
12255     onRemoveItem : function(e, _self, o)
12256     {
12257         e.preventDefault();
12258         
12259         this.lastItem = Roo.apply([], this.item);
12260         
12261         var index = this.item.indexOf(o.data) * 1;
12262         
12263         if( index < 0){
12264             Roo.log('not this item?!');
12265             return;
12266         }
12267         
12268         this.item.splice(index, 1);
12269         o.item.remove();
12270         
12271         this.syncValue();
12272         
12273         this.fireEvent('remove', this, e);
12274         
12275         this.validate();
12276         
12277     },
12278     
12279     syncValue : function()
12280     {
12281         if(!this.item.length){
12282             this.clearValue();
12283             return;
12284         }
12285             
12286         var value = [];
12287         var _this = this;
12288         Roo.each(this.item, function(i){
12289             if(_this.valueField){
12290                 value.push(i[_this.valueField]);
12291                 return;
12292             }
12293
12294             value.push(i);
12295         });
12296
12297         this.value = value.join(',');
12298
12299         if(this.hiddenField){
12300             this.hiddenField.dom.value = this.value;
12301         }
12302     },
12303     
12304     clearItem : function()
12305     {
12306         if(!this.multiple){
12307             return;
12308         }
12309         
12310         this.item = [];
12311         
12312         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12313            c.remove();
12314         });
12315         
12316         this.syncValue();
12317         
12318         this.validate();
12319     },
12320     
12321     inputEl: function ()
12322     {
12323         if(this.tickable){
12324             return this.searchField;
12325         }
12326         return this.el.select('input.form-control',true).first();
12327     },
12328     
12329     
12330     onTickableFooterButtonClick : function(e, btn, el)
12331     {
12332         e.preventDefault();
12333         
12334         this.lastItem = Roo.apply([], this.item);
12335         
12336         if(btn && btn.name == 'cancel'){
12337             this.tickItems = Roo.apply([], this.item);
12338             this.collapse();
12339             return;
12340         }
12341         
12342         this.clearItem();
12343         
12344         var _this = this;
12345         
12346         Roo.each(this.tickItems, function(o){
12347             _this.addItem(o);
12348         });
12349         
12350         this.collapse();
12351         
12352     },
12353     
12354     validate : function()
12355     {
12356         var v = this.getRawValue();
12357         
12358         if(this.multiple){
12359             v = this.getValue();
12360         }
12361         
12362         if(this.disabled || this.allowBlank || v.length){
12363             this.markValid();
12364             return true;
12365         }
12366         
12367         this.markInvalid();
12368         return false;
12369     }
12370     
12371     
12372
12373     /** 
12374     * @cfg {Boolean} grow 
12375     * @hide 
12376     */
12377     /** 
12378     * @cfg {Number} growMin 
12379     * @hide 
12380     */
12381     /** 
12382     * @cfg {Number} growMax 
12383     * @hide 
12384     */
12385     /**
12386      * @hide
12387      * @method autoSize
12388      */
12389 });
12390 /*
12391  * Based on:
12392  * Ext JS Library 1.1.1
12393  * Copyright(c) 2006-2007, Ext JS, LLC.
12394  *
12395  * Originally Released Under LGPL - original licence link has changed is not relivant.
12396  *
12397  * Fork - LGPL
12398  * <script type="text/javascript">
12399  */
12400
12401 /**
12402  * @class Roo.View
12403  * @extends Roo.util.Observable
12404  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12405  * This class also supports single and multi selection modes. <br>
12406  * Create a data model bound view:
12407  <pre><code>
12408  var store = new Roo.data.Store(...);
12409
12410  var view = new Roo.View({
12411     el : "my-element",
12412     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12413  
12414     singleSelect: true,
12415     selectedClass: "ydataview-selected",
12416     store: store
12417  });
12418
12419  // listen for node click?
12420  view.on("click", function(vw, index, node, e){
12421  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12422  });
12423
12424  // load XML data
12425  dataModel.load("foobar.xml");
12426  </code></pre>
12427  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12428  * <br><br>
12429  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12430  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12431  * 
12432  * Note: old style constructor is still suported (container, template, config)
12433  * 
12434  * @constructor
12435  * Create a new View
12436  * @param {Object} config The config object
12437  * 
12438  */
12439 Roo.View = function(config, depreciated_tpl, depreciated_config){
12440     
12441     this.parent = false;
12442     
12443     if (typeof(depreciated_tpl) == 'undefined') {
12444         // new way.. - universal constructor.
12445         Roo.apply(this, config);
12446         this.el  = Roo.get(this.el);
12447     } else {
12448         // old format..
12449         this.el  = Roo.get(config);
12450         this.tpl = depreciated_tpl;
12451         Roo.apply(this, depreciated_config);
12452     }
12453     this.wrapEl  = this.el.wrap().wrap();
12454     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12455     
12456     
12457     if(typeof(this.tpl) == "string"){
12458         this.tpl = new Roo.Template(this.tpl);
12459     } else {
12460         // support xtype ctors..
12461         this.tpl = new Roo.factory(this.tpl, Roo);
12462     }
12463     
12464     
12465     this.tpl.compile();
12466     
12467     /** @private */
12468     this.addEvents({
12469         /**
12470          * @event beforeclick
12471          * Fires before a click is processed. Returns false to cancel the default action.
12472          * @param {Roo.View} this
12473          * @param {Number} index The index of the target node
12474          * @param {HTMLElement} node The target node
12475          * @param {Roo.EventObject} e The raw event object
12476          */
12477             "beforeclick" : true,
12478         /**
12479          * @event click
12480          * Fires when a template node is clicked.
12481          * @param {Roo.View} this
12482          * @param {Number} index The index of the target node
12483          * @param {HTMLElement} node The target node
12484          * @param {Roo.EventObject} e The raw event object
12485          */
12486             "click" : true,
12487         /**
12488          * @event dblclick
12489          * Fires when a template node is double clicked.
12490          * @param {Roo.View} this
12491          * @param {Number} index The index of the target node
12492          * @param {HTMLElement} node The target node
12493          * @param {Roo.EventObject} e The raw event object
12494          */
12495             "dblclick" : true,
12496         /**
12497          * @event contextmenu
12498          * Fires when a template node is right clicked.
12499          * @param {Roo.View} this
12500          * @param {Number} index The index of the target node
12501          * @param {HTMLElement} node The target node
12502          * @param {Roo.EventObject} e The raw event object
12503          */
12504             "contextmenu" : true,
12505         /**
12506          * @event selectionchange
12507          * Fires when the selected nodes change.
12508          * @param {Roo.View} this
12509          * @param {Array} selections Array of the selected nodes
12510          */
12511             "selectionchange" : true,
12512     
12513         /**
12514          * @event beforeselect
12515          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12516          * @param {Roo.View} this
12517          * @param {HTMLElement} node The node to be selected
12518          * @param {Array} selections Array of currently selected nodes
12519          */
12520             "beforeselect" : true,
12521         /**
12522          * @event preparedata
12523          * Fires on every row to render, to allow you to change the data.
12524          * @param {Roo.View} this
12525          * @param {Object} data to be rendered (change this)
12526          */
12527           "preparedata" : true
12528           
12529           
12530         });
12531
12532
12533
12534     this.el.on({
12535         "click": this.onClick,
12536         "dblclick": this.onDblClick,
12537         "contextmenu": this.onContextMenu,
12538         scope:this
12539     });
12540
12541     this.selections = [];
12542     this.nodes = [];
12543     this.cmp = new Roo.CompositeElementLite([]);
12544     if(this.store){
12545         this.store = Roo.factory(this.store, Roo.data);
12546         this.setStore(this.store, true);
12547     }
12548     
12549     if ( this.footer && this.footer.xtype) {
12550            
12551          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12552         
12553         this.footer.dataSource = this.store
12554         this.footer.container = fctr;
12555         this.footer = Roo.factory(this.footer, Roo);
12556         fctr.insertFirst(this.el);
12557         
12558         // this is a bit insane - as the paging toolbar seems to detach the el..
12559 //        dom.parentNode.parentNode.parentNode
12560          // they get detached?
12561     }
12562     
12563     
12564     Roo.View.superclass.constructor.call(this);
12565     
12566     
12567 };
12568
12569 Roo.extend(Roo.View, Roo.util.Observable, {
12570     
12571      /**
12572      * @cfg {Roo.data.Store} store Data store to load data from.
12573      */
12574     store : false,
12575     
12576     /**
12577      * @cfg {String|Roo.Element} el The container element.
12578      */
12579     el : '',
12580     
12581     /**
12582      * @cfg {String|Roo.Template} tpl The template used by this View 
12583      */
12584     tpl : false,
12585     /**
12586      * @cfg {String} dataName the named area of the template to use as the data area
12587      *                          Works with domtemplates roo-name="name"
12588      */
12589     dataName: false,
12590     /**
12591      * @cfg {String} selectedClass The css class to add to selected nodes
12592      */
12593     selectedClass : "x-view-selected",
12594      /**
12595      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12596      */
12597     emptyText : "",
12598     
12599     /**
12600      * @cfg {String} text to display on mask (default Loading)
12601      */
12602     mask : false,
12603     /**
12604      * @cfg {Boolean} multiSelect Allow multiple selection
12605      */
12606     multiSelect : false,
12607     /**
12608      * @cfg {Boolean} singleSelect Allow single selection
12609      */
12610     singleSelect:  false,
12611     
12612     /**
12613      * @cfg {Boolean} toggleSelect - selecting 
12614      */
12615     toggleSelect : false,
12616     
12617     /**
12618      * @cfg {Boolean} tickable - selecting 
12619      */
12620     tickable : false,
12621     
12622     /**
12623      * Returns the element this view is bound to.
12624      * @return {Roo.Element}
12625      */
12626     getEl : function(){
12627         return this.wrapEl;
12628     },
12629     
12630     
12631
12632     /**
12633      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12634      */
12635     refresh : function(){
12636         //Roo.log('refresh');
12637         var t = this.tpl;
12638         
12639         // if we are using something like 'domtemplate', then
12640         // the what gets used is:
12641         // t.applySubtemplate(NAME, data, wrapping data..)
12642         // the outer template then get' applied with
12643         //     the store 'extra data'
12644         // and the body get's added to the
12645         //      roo-name="data" node?
12646         //      <span class='roo-tpl-{name}'></span> ?????
12647         
12648         
12649         
12650         this.clearSelections();
12651         this.el.update("");
12652         var html = [];
12653         var records = this.store.getRange();
12654         if(records.length < 1) {
12655             
12656             // is this valid??  = should it render a template??
12657             
12658             this.el.update(this.emptyText);
12659             return;
12660         }
12661         var el = this.el;
12662         if (this.dataName) {
12663             this.el.update(t.apply(this.store.meta)); //????
12664             el = this.el.child('.roo-tpl-' + this.dataName);
12665         }
12666         
12667         for(var i = 0, len = records.length; i < len; i++){
12668             var data = this.prepareData(records[i].data, i, records[i]);
12669             this.fireEvent("preparedata", this, data, i, records[i]);
12670             
12671             var d = Roo.apply({}, data);
12672             
12673             if(this.tickable){
12674                 Roo.apply(d, {'roo-id' : Roo.id()});
12675                 
12676                 var _this = this;
12677             
12678                 Roo.each(this.parent.item, function(item){
12679                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12680                         return;
12681                     }
12682                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12683                 });
12684             }
12685             
12686             html[html.length] = Roo.util.Format.trim(
12687                 this.dataName ?
12688                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12689                     t.apply(d)
12690             );
12691         }
12692         
12693         
12694         
12695         el.update(html.join(""));
12696         this.nodes = el.dom.childNodes;
12697         this.updateIndexes(0);
12698     },
12699     
12700
12701     /**
12702      * Function to override to reformat the data that is sent to
12703      * the template for each node.
12704      * DEPRICATED - use the preparedata event handler.
12705      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12706      * a JSON object for an UpdateManager bound view).
12707      */
12708     prepareData : function(data, index, record)
12709     {
12710         this.fireEvent("preparedata", this, data, index, record);
12711         return data;
12712     },
12713
12714     onUpdate : function(ds, record){
12715         // Roo.log('on update');   
12716         this.clearSelections();
12717         var index = this.store.indexOf(record);
12718         var n = this.nodes[index];
12719         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12720         n.parentNode.removeChild(n);
12721         this.updateIndexes(index, index);
12722     },
12723
12724     
12725     
12726 // --------- FIXME     
12727     onAdd : function(ds, records, index)
12728     {
12729         //Roo.log(['on Add', ds, records, index] );        
12730         this.clearSelections();
12731         if(this.nodes.length == 0){
12732             this.refresh();
12733             return;
12734         }
12735         var n = this.nodes[index];
12736         for(var i = 0, len = records.length; i < len; i++){
12737             var d = this.prepareData(records[i].data, i, records[i]);
12738             if(n){
12739                 this.tpl.insertBefore(n, d);
12740             }else{
12741                 
12742                 this.tpl.append(this.el, d);
12743             }
12744         }
12745         this.updateIndexes(index);
12746     },
12747
12748     onRemove : function(ds, record, index){
12749        // Roo.log('onRemove');
12750         this.clearSelections();
12751         var el = this.dataName  ?
12752             this.el.child('.roo-tpl-' + this.dataName) :
12753             this.el; 
12754         
12755         el.dom.removeChild(this.nodes[index]);
12756         this.updateIndexes(index);
12757     },
12758
12759     /**
12760      * Refresh an individual node.
12761      * @param {Number} index
12762      */
12763     refreshNode : function(index){
12764         this.onUpdate(this.store, this.store.getAt(index));
12765     },
12766
12767     updateIndexes : function(startIndex, endIndex){
12768         var ns = this.nodes;
12769         startIndex = startIndex || 0;
12770         endIndex = endIndex || ns.length - 1;
12771         for(var i = startIndex; i <= endIndex; i++){
12772             ns[i].nodeIndex = i;
12773         }
12774     },
12775
12776     /**
12777      * Changes the data store this view uses and refresh the view.
12778      * @param {Store} store
12779      */
12780     setStore : function(store, initial){
12781         if(!initial && this.store){
12782             this.store.un("datachanged", this.refresh);
12783             this.store.un("add", this.onAdd);
12784             this.store.un("remove", this.onRemove);
12785             this.store.un("update", this.onUpdate);
12786             this.store.un("clear", this.refresh);
12787             this.store.un("beforeload", this.onBeforeLoad);
12788             this.store.un("load", this.onLoad);
12789             this.store.un("loadexception", this.onLoad);
12790         }
12791         if(store){
12792           
12793             store.on("datachanged", this.refresh, this);
12794             store.on("add", this.onAdd, this);
12795             store.on("remove", this.onRemove, this);
12796             store.on("update", this.onUpdate, this);
12797             store.on("clear", this.refresh, this);
12798             store.on("beforeload", this.onBeforeLoad, this);
12799             store.on("load", this.onLoad, this);
12800             store.on("loadexception", this.onLoad, this);
12801         }
12802         
12803         if(store){
12804             this.refresh();
12805         }
12806     },
12807     /**
12808      * onbeforeLoad - masks the loading area.
12809      *
12810      */
12811     onBeforeLoad : function(store,opts)
12812     {
12813          //Roo.log('onBeforeLoad');   
12814         if (!opts.add) {
12815             this.el.update("");
12816         }
12817         this.el.mask(this.mask ? this.mask : "Loading" ); 
12818     },
12819     onLoad : function ()
12820     {
12821         this.el.unmask();
12822     },
12823     
12824
12825     /**
12826      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12827      * @param {HTMLElement} node
12828      * @return {HTMLElement} The template node
12829      */
12830     findItemFromChild : function(node){
12831         var el = this.dataName  ?
12832             this.el.child('.roo-tpl-' + this.dataName,true) :
12833             this.el.dom; 
12834         
12835         if(!node || node.parentNode == el){
12836                     return node;
12837             }
12838             var p = node.parentNode;
12839             while(p && p != el){
12840             if(p.parentNode == el){
12841                 return p;
12842             }
12843             p = p.parentNode;
12844         }
12845             return null;
12846     },
12847
12848     /** @ignore */
12849     onClick : function(e){
12850         var item = this.findItemFromChild(e.getTarget());
12851         if(item){
12852             var index = this.indexOf(item);
12853             if(this.onItemClick(item, index, e) !== false){
12854                 this.fireEvent("click", this, index, item, e);
12855             }
12856         }else{
12857             this.clearSelections();
12858         }
12859     },
12860
12861     /** @ignore */
12862     onContextMenu : function(e){
12863         var item = this.findItemFromChild(e.getTarget());
12864         if(item){
12865             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12866         }
12867     },
12868
12869     /** @ignore */
12870     onDblClick : function(e){
12871         var item = this.findItemFromChild(e.getTarget());
12872         if(item){
12873             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12874         }
12875     },
12876
12877     onItemClick : function(item, index, e)
12878     {
12879         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12880             return false;
12881         }
12882         if (this.toggleSelect) {
12883             var m = this.isSelected(item) ? 'unselect' : 'select';
12884             //Roo.log(m);
12885             var _t = this;
12886             _t[m](item, true, false);
12887             return true;
12888         }
12889         if(this.multiSelect || this.singleSelect){
12890             if(this.multiSelect && e.shiftKey && this.lastSelection){
12891                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12892             }else{
12893                 this.select(item, this.multiSelect && e.ctrlKey);
12894                 this.lastSelection = item;
12895             }
12896             
12897             if(!this.tickable){
12898                 e.preventDefault();
12899             }
12900             
12901         }
12902         return true;
12903     },
12904
12905     /**
12906      * Get the number of selected nodes.
12907      * @return {Number}
12908      */
12909     getSelectionCount : function(){
12910         return this.selections.length;
12911     },
12912
12913     /**
12914      * Get the currently selected nodes.
12915      * @return {Array} An array of HTMLElements
12916      */
12917     getSelectedNodes : function(){
12918         return this.selections;
12919     },
12920
12921     /**
12922      * Get the indexes of the selected nodes.
12923      * @return {Array}
12924      */
12925     getSelectedIndexes : function(){
12926         var indexes = [], s = this.selections;
12927         for(var i = 0, len = s.length; i < len; i++){
12928             indexes.push(s[i].nodeIndex);
12929         }
12930         return indexes;
12931     },
12932
12933     /**
12934      * Clear all selections
12935      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12936      */
12937     clearSelections : function(suppressEvent){
12938         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12939             this.cmp.elements = this.selections;
12940             this.cmp.removeClass(this.selectedClass);
12941             this.selections = [];
12942             if(!suppressEvent){
12943                 this.fireEvent("selectionchange", this, this.selections);
12944             }
12945         }
12946     },
12947
12948     /**
12949      * Returns true if the passed node is selected
12950      * @param {HTMLElement/Number} node The node or node index
12951      * @return {Boolean}
12952      */
12953     isSelected : function(node){
12954         var s = this.selections;
12955         if(s.length < 1){
12956             return false;
12957         }
12958         node = this.getNode(node);
12959         return s.indexOf(node) !== -1;
12960     },
12961
12962     /**
12963      * Selects nodes.
12964      * @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
12965      * @param {Boolean} keepExisting (optional) true to keep existing selections
12966      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12967      */
12968     select : function(nodeInfo, keepExisting, suppressEvent){
12969         if(nodeInfo instanceof Array){
12970             if(!keepExisting){
12971                 this.clearSelections(true);
12972             }
12973             for(var i = 0, len = nodeInfo.length; i < len; i++){
12974                 this.select(nodeInfo[i], true, true);
12975             }
12976             return;
12977         } 
12978         var node = this.getNode(nodeInfo);
12979         if(!node || this.isSelected(node)){
12980             return; // already selected.
12981         }
12982         if(!keepExisting){
12983             this.clearSelections(true);
12984         }
12985         
12986         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12987             Roo.fly(node).addClass(this.selectedClass);
12988             this.selections.push(node);
12989             if(!suppressEvent){
12990                 this.fireEvent("selectionchange", this, this.selections);
12991             }
12992         }
12993         
12994         
12995     },
12996       /**
12997      * Unselects nodes.
12998      * @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
12999      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13000      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13001      */
13002     unselect : function(nodeInfo, keepExisting, suppressEvent)
13003     {
13004         if(nodeInfo instanceof Array){
13005             Roo.each(this.selections, function(s) {
13006                 this.unselect(s, nodeInfo);
13007             }, this);
13008             return;
13009         }
13010         var node = this.getNode(nodeInfo);
13011         if(!node || !this.isSelected(node)){
13012             //Roo.log("not selected");
13013             return; // not selected.
13014         }
13015         // fireevent???
13016         var ns = [];
13017         Roo.each(this.selections, function(s) {
13018             if (s == node ) {
13019                 Roo.fly(node).removeClass(this.selectedClass);
13020
13021                 return;
13022             }
13023             ns.push(s);
13024         },this);
13025         
13026         this.selections= ns;
13027         this.fireEvent("selectionchange", this, this.selections);
13028     },
13029
13030     /**
13031      * Gets a template node.
13032      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13033      * @return {HTMLElement} The node or null if it wasn't found
13034      */
13035     getNode : function(nodeInfo){
13036         if(typeof nodeInfo == "string"){
13037             return document.getElementById(nodeInfo);
13038         }else if(typeof nodeInfo == "number"){
13039             return this.nodes[nodeInfo];
13040         }
13041         return nodeInfo;
13042     },
13043
13044     /**
13045      * Gets a range template nodes.
13046      * @param {Number} startIndex
13047      * @param {Number} endIndex
13048      * @return {Array} An array of nodes
13049      */
13050     getNodes : function(start, end){
13051         var ns = this.nodes;
13052         start = start || 0;
13053         end = typeof end == "undefined" ? ns.length - 1 : end;
13054         var nodes = [];
13055         if(start <= end){
13056             for(var i = start; i <= end; i++){
13057                 nodes.push(ns[i]);
13058             }
13059         } else{
13060             for(var i = start; i >= end; i--){
13061                 nodes.push(ns[i]);
13062             }
13063         }
13064         return nodes;
13065     },
13066
13067     /**
13068      * Finds the index of the passed node
13069      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13070      * @return {Number} The index of the node or -1
13071      */
13072     indexOf : function(node){
13073         node = this.getNode(node);
13074         if(typeof node.nodeIndex == "number"){
13075             return node.nodeIndex;
13076         }
13077         var ns = this.nodes;
13078         for(var i = 0, len = ns.length; i < len; i++){
13079             if(ns[i] == node){
13080                 return i;
13081             }
13082         }
13083         return -1;
13084     }
13085 });
13086 /*
13087  * - LGPL
13088  *
13089  * based on jquery fullcalendar
13090  * 
13091  */
13092
13093 Roo.bootstrap = Roo.bootstrap || {};
13094 /**
13095  * @class Roo.bootstrap.Calendar
13096  * @extends Roo.bootstrap.Component
13097  * Bootstrap Calendar class
13098  * @cfg {Boolean} loadMask (true|false) default false
13099  * @cfg {Object} header generate the user specific header of the calendar, default false
13100
13101  * @constructor
13102  * Create a new Container
13103  * @param {Object} config The config object
13104  */
13105
13106
13107
13108 Roo.bootstrap.Calendar = function(config){
13109     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13110      this.addEvents({
13111         /**
13112              * @event select
13113              * Fires when a date is selected
13114              * @param {DatePicker} this
13115              * @param {Date} date The selected date
13116              */
13117         'select': true,
13118         /**
13119              * @event monthchange
13120              * Fires when the displayed month changes 
13121              * @param {DatePicker} this
13122              * @param {Date} date The selected month
13123              */
13124         'monthchange': true,
13125         /**
13126              * @event evententer
13127              * Fires when mouse over an event
13128              * @param {Calendar} this
13129              * @param {event} Event
13130              */
13131         'evententer': true,
13132         /**
13133              * @event eventleave
13134              * Fires when the mouse leaves an
13135              * @param {Calendar} this
13136              * @param {event}
13137              */
13138         'eventleave': true,
13139         /**
13140              * @event eventclick
13141              * Fires when the mouse click an
13142              * @param {Calendar} this
13143              * @param {event}
13144              */
13145         'eventclick': true
13146         
13147     });
13148
13149 };
13150
13151 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13152     
13153      /**
13154      * @cfg {Number} startDay
13155      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13156      */
13157     startDay : 0,
13158     
13159     loadMask : false,
13160     
13161     header : false,
13162       
13163     getAutoCreate : function(){
13164         
13165         
13166         var fc_button = function(name, corner, style, content ) {
13167             return Roo.apply({},{
13168                 tag : 'span',
13169                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13170                          (corner.length ?
13171                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13172                             ''
13173                         ),
13174                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13175                 unselectable: 'on'
13176             });
13177         };
13178         
13179         var header = {};
13180         
13181         if(!this.header){
13182             header = {
13183                 tag : 'table',
13184                 cls : 'fc-header',
13185                 style : 'width:100%',
13186                 cn : [
13187                     {
13188                         tag: 'tr',
13189                         cn : [
13190                             {
13191                                 tag : 'td',
13192                                 cls : 'fc-header-left',
13193                                 cn : [
13194                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13195                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13196                                     { tag: 'span', cls: 'fc-header-space' },
13197                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13198
13199
13200                                 ]
13201                             },
13202
13203                             {
13204                                 tag : 'td',
13205                                 cls : 'fc-header-center',
13206                                 cn : [
13207                                     {
13208                                         tag: 'span',
13209                                         cls: 'fc-header-title',
13210                                         cn : {
13211                                             tag: 'H2',
13212                                             html : 'month / year'
13213                                         }
13214                                     }
13215
13216                                 ]
13217                             },
13218                             {
13219                                 tag : 'td',
13220                                 cls : 'fc-header-right',
13221                                 cn : [
13222                               /*      fc_button('month', 'left', '', 'month' ),
13223                                     fc_button('week', '', '', 'week' ),
13224                                     fc_button('day', 'right', '', 'day' )
13225                                 */    
13226
13227                                 ]
13228                             }
13229
13230                         ]
13231                     }
13232                 ]
13233             };
13234         }
13235         
13236         header = this.header;
13237         
13238        
13239         var cal_heads = function() {
13240             var ret = [];
13241             // fixme - handle this.
13242             
13243             for (var i =0; i < Date.dayNames.length; i++) {
13244                 var d = Date.dayNames[i];
13245                 ret.push({
13246                     tag: 'th',
13247                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13248                     html : d.substring(0,3)
13249                 });
13250                 
13251             }
13252             ret[0].cls += ' fc-first';
13253             ret[6].cls += ' fc-last';
13254             return ret;
13255         };
13256         var cal_cell = function(n) {
13257             return  {
13258                 tag: 'td',
13259                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13260                 cn : [
13261                     {
13262                         cn : [
13263                             {
13264                                 cls: 'fc-day-number',
13265                                 html: 'D'
13266                             },
13267                             {
13268                                 cls: 'fc-day-content',
13269                              
13270                                 cn : [
13271                                      {
13272                                         style: 'position: relative;' // height: 17px;
13273                                     }
13274                                 ]
13275                             }
13276                             
13277                             
13278                         ]
13279                     }
13280                 ]
13281                 
13282             }
13283         };
13284         var cal_rows = function() {
13285             
13286             var ret = [];
13287             for (var r = 0; r < 6; r++) {
13288                 var row= {
13289                     tag : 'tr',
13290                     cls : 'fc-week',
13291                     cn : []
13292                 };
13293                 
13294                 for (var i =0; i < Date.dayNames.length; i++) {
13295                     var d = Date.dayNames[i];
13296                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13297
13298                 }
13299                 row.cn[0].cls+=' fc-first';
13300                 row.cn[0].cn[0].style = 'min-height:90px';
13301                 row.cn[6].cls+=' fc-last';
13302                 ret.push(row);
13303                 
13304             }
13305             ret[0].cls += ' fc-first';
13306             ret[4].cls += ' fc-prev-last';
13307             ret[5].cls += ' fc-last';
13308             return ret;
13309             
13310         };
13311         
13312         var cal_table = {
13313             tag: 'table',
13314             cls: 'fc-border-separate',
13315             style : 'width:100%',
13316             cellspacing  : 0,
13317             cn : [
13318                 { 
13319                     tag: 'thead',
13320                     cn : [
13321                         { 
13322                             tag: 'tr',
13323                             cls : 'fc-first fc-last',
13324                             cn : cal_heads()
13325                         }
13326                     ]
13327                 },
13328                 { 
13329                     tag: 'tbody',
13330                     cn : cal_rows()
13331                 }
13332                   
13333             ]
13334         };
13335          
13336          var cfg = {
13337             cls : 'fc fc-ltr',
13338             cn : [
13339                 header,
13340                 {
13341                     cls : 'fc-content',
13342                     style : "position: relative;",
13343                     cn : [
13344                         {
13345                             cls : 'fc-view fc-view-month fc-grid',
13346                             style : 'position: relative',
13347                             unselectable : 'on',
13348                             cn : [
13349                                 {
13350                                     cls : 'fc-event-container',
13351                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13352                                 },
13353                                 cal_table
13354                             ]
13355                         }
13356                     ]
13357     
13358                 }
13359            ] 
13360             
13361         };
13362         
13363          
13364         
13365         return cfg;
13366     },
13367     
13368     
13369     initEvents : function()
13370     {
13371         if(!this.store){
13372             throw "can not find store for calendar";
13373         }
13374         
13375         var mark = {
13376             tag: "div",
13377             cls:"x-dlg-mask",
13378             style: "text-align:center",
13379             cn: [
13380                 {
13381                     tag: "div",
13382                     style: "background-color:white;width:50%;margin:250 auto",
13383                     cn: [
13384                         {
13385                             tag: "img",
13386                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13387                         },
13388                         {
13389                             tag: "span",
13390                             html: "Loading"
13391                         }
13392                         
13393                     ]
13394                 }
13395             ]
13396         }
13397         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13398         
13399         var size = this.el.select('.fc-content', true).first().getSize();
13400         this.maskEl.setSize(size.width, size.height);
13401         this.maskEl.enableDisplayMode("block");
13402         if(!this.loadMask){
13403             this.maskEl.hide();
13404         }
13405         
13406         this.store = Roo.factory(this.store, Roo.data);
13407         this.store.on('load', this.onLoad, this);
13408         this.store.on('beforeload', this.onBeforeLoad, this);
13409         
13410         this.resize();
13411         
13412         this.cells = this.el.select('.fc-day',true);
13413         //Roo.log(this.cells);
13414         this.textNodes = this.el.query('.fc-day-number');
13415         this.cells.addClassOnOver('fc-state-hover');
13416         
13417         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13418         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13419         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13420         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13421         
13422         this.on('monthchange', this.onMonthChange, this);
13423         
13424         this.update(new Date().clearTime());
13425     },
13426     
13427     resize : function() {
13428         var sz  = this.el.getSize();
13429         
13430         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13431         this.el.select('.fc-day-content div',true).setHeight(34);
13432     },
13433     
13434     
13435     // private
13436     showPrevMonth : function(e){
13437         this.update(this.activeDate.add("mo", -1));
13438     },
13439     showToday : function(e){
13440         this.update(new Date().clearTime());
13441     },
13442     // private
13443     showNextMonth : function(e){
13444         this.update(this.activeDate.add("mo", 1));
13445     },
13446
13447     // private
13448     showPrevYear : function(){
13449         this.update(this.activeDate.add("y", -1));
13450     },
13451
13452     // private
13453     showNextYear : function(){
13454         this.update(this.activeDate.add("y", 1));
13455     },
13456
13457     
13458    // private
13459     update : function(date)
13460     {
13461         var vd = this.activeDate;
13462         this.activeDate = date;
13463 //        if(vd && this.el){
13464 //            var t = date.getTime();
13465 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13466 //                Roo.log('using add remove');
13467 //                
13468 //                this.fireEvent('monthchange', this, date);
13469 //                
13470 //                this.cells.removeClass("fc-state-highlight");
13471 //                this.cells.each(function(c){
13472 //                   if(c.dateValue == t){
13473 //                       c.addClass("fc-state-highlight");
13474 //                       setTimeout(function(){
13475 //                            try{c.dom.firstChild.focus();}catch(e){}
13476 //                       }, 50);
13477 //                       return false;
13478 //                   }
13479 //                   return true;
13480 //                });
13481 //                return;
13482 //            }
13483 //        }
13484         
13485         var days = date.getDaysInMonth();
13486         
13487         var firstOfMonth = date.getFirstDateOfMonth();
13488         var startingPos = firstOfMonth.getDay()-this.startDay;
13489         
13490         if(startingPos < this.startDay){
13491             startingPos += 7;
13492         }
13493         
13494         var pm = date.add(Date.MONTH, -1);
13495         var prevStart = pm.getDaysInMonth()-startingPos;
13496 //        
13497         this.cells = this.el.select('.fc-day',true);
13498         this.textNodes = this.el.query('.fc-day-number');
13499         this.cells.addClassOnOver('fc-state-hover');
13500         
13501         var cells = this.cells.elements;
13502         var textEls = this.textNodes;
13503         
13504         Roo.each(cells, function(cell){
13505             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13506         });
13507         
13508         days += startingPos;
13509
13510         // convert everything to numbers so it's fast
13511         var day = 86400000;
13512         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13513         //Roo.log(d);
13514         //Roo.log(pm);
13515         //Roo.log(prevStart);
13516         
13517         var today = new Date().clearTime().getTime();
13518         var sel = date.clearTime().getTime();
13519         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13520         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13521         var ddMatch = this.disabledDatesRE;
13522         var ddText = this.disabledDatesText;
13523         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13524         var ddaysText = this.disabledDaysText;
13525         var format = this.format;
13526         
13527         var setCellClass = function(cal, cell){
13528             cell.row = 0;
13529             cell.events = [];
13530             cell.more = [];
13531             //Roo.log('set Cell Class');
13532             cell.title = "";
13533             var t = d.getTime();
13534             
13535             //Roo.log(d);
13536             
13537             cell.dateValue = t;
13538             if(t == today){
13539                 cell.className += " fc-today";
13540                 cell.className += " fc-state-highlight";
13541                 cell.title = cal.todayText;
13542             }
13543             if(t == sel){
13544                 // disable highlight in other month..
13545                 //cell.className += " fc-state-highlight";
13546                 
13547             }
13548             // disabling
13549             if(t < min) {
13550                 cell.className = " fc-state-disabled";
13551                 cell.title = cal.minText;
13552                 return;
13553             }
13554             if(t > max) {
13555                 cell.className = " fc-state-disabled";
13556                 cell.title = cal.maxText;
13557                 return;
13558             }
13559             if(ddays){
13560                 if(ddays.indexOf(d.getDay()) != -1){
13561                     cell.title = ddaysText;
13562                     cell.className = " fc-state-disabled";
13563                 }
13564             }
13565             if(ddMatch && format){
13566                 var fvalue = d.dateFormat(format);
13567                 if(ddMatch.test(fvalue)){
13568                     cell.title = ddText.replace("%0", fvalue);
13569                     cell.className = " fc-state-disabled";
13570                 }
13571             }
13572             
13573             if (!cell.initialClassName) {
13574                 cell.initialClassName = cell.dom.className;
13575             }
13576             
13577             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13578         };
13579
13580         var i = 0;
13581         
13582         for(; i < startingPos; i++) {
13583             textEls[i].innerHTML = (++prevStart);
13584             d.setDate(d.getDate()+1);
13585             
13586             cells[i].className = "fc-past fc-other-month";
13587             setCellClass(this, cells[i]);
13588         }
13589         
13590         var intDay = 0;
13591         
13592         for(; i < days; i++){
13593             intDay = i - startingPos + 1;
13594             textEls[i].innerHTML = (intDay);
13595             d.setDate(d.getDate()+1);
13596             
13597             cells[i].className = ''; // "x-date-active";
13598             setCellClass(this, cells[i]);
13599         }
13600         var extraDays = 0;
13601         
13602         for(; i < 42; i++) {
13603             textEls[i].innerHTML = (++extraDays);
13604             d.setDate(d.getDate()+1);
13605             
13606             cells[i].className = "fc-future fc-other-month";
13607             setCellClass(this, cells[i]);
13608         }
13609         
13610         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13611         
13612         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13613         
13614         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13615         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13616         
13617         if(totalRows != 6){
13618             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13619             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13620         }
13621         
13622         this.fireEvent('monthchange', this, date);
13623         
13624         
13625         /*
13626         if(!this.internalRender){
13627             var main = this.el.dom.firstChild;
13628             var w = main.offsetWidth;
13629             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13630             Roo.fly(main).setWidth(w);
13631             this.internalRender = true;
13632             // opera does not respect the auto grow header center column
13633             // then, after it gets a width opera refuses to recalculate
13634             // without a second pass
13635             if(Roo.isOpera && !this.secondPass){
13636                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13637                 this.secondPass = true;
13638                 this.update.defer(10, this, [date]);
13639             }
13640         }
13641         */
13642         
13643     },
13644     
13645     findCell : function(dt) {
13646         dt = dt.clearTime().getTime();
13647         var ret = false;
13648         this.cells.each(function(c){
13649             //Roo.log("check " +c.dateValue + '?=' + dt);
13650             if(c.dateValue == dt){
13651                 ret = c;
13652                 return false;
13653             }
13654             return true;
13655         });
13656         
13657         return ret;
13658     },
13659     
13660     findCells : function(ev) {
13661         var s = ev.start.clone().clearTime().getTime();
13662        // Roo.log(s);
13663         var e= ev.end.clone().clearTime().getTime();
13664        // Roo.log(e);
13665         var ret = [];
13666         this.cells.each(function(c){
13667              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13668             
13669             if(c.dateValue > e){
13670                 return ;
13671             }
13672             if(c.dateValue < s){
13673                 return ;
13674             }
13675             ret.push(c);
13676         });
13677         
13678         return ret;    
13679     },
13680     
13681 //    findBestRow: function(cells)
13682 //    {
13683 //        var ret = 0;
13684 //        
13685 //        for (var i =0 ; i < cells.length;i++) {
13686 //            ret  = Math.max(cells[i].rows || 0,ret);
13687 //        }
13688 //        return ret;
13689 //        
13690 //    },
13691     
13692     
13693     addItem : function(ev)
13694     {
13695         // look for vertical location slot in
13696         var cells = this.findCells(ev);
13697         
13698 //        ev.row = this.findBestRow(cells);
13699         
13700         // work out the location.
13701         
13702         var crow = false;
13703         var rows = [];
13704         for(var i =0; i < cells.length; i++) {
13705             
13706             cells[i].row = cells[0].row;
13707             
13708             if(i == 0){
13709                 cells[i].row = cells[i].row + 1;
13710             }
13711             
13712             if (!crow) {
13713                 crow = {
13714                     start : cells[i],
13715                     end :  cells[i]
13716                 };
13717                 continue;
13718             }
13719             if (crow.start.getY() == cells[i].getY()) {
13720                 // on same row.
13721                 crow.end = cells[i];
13722                 continue;
13723             }
13724             // different row.
13725             rows.push(crow);
13726             crow = {
13727                 start: cells[i],
13728                 end : cells[i]
13729             };
13730             
13731         }
13732         
13733         rows.push(crow);
13734         ev.els = [];
13735         ev.rows = rows;
13736         ev.cells = cells;
13737         
13738         cells[0].events.push(ev);
13739         
13740         this.calevents.push(ev);
13741     },
13742     
13743     clearEvents: function() {
13744         
13745         if(!this.calevents){
13746             return;
13747         }
13748         
13749         Roo.each(this.cells.elements, function(c){
13750             c.row = 0;
13751             c.events = [];
13752             c.more = [];
13753         });
13754         
13755         Roo.each(this.calevents, function(e) {
13756             Roo.each(e.els, function(el) {
13757                 el.un('mouseenter' ,this.onEventEnter, this);
13758                 el.un('mouseleave' ,this.onEventLeave, this);
13759                 el.remove();
13760             },this);
13761         },this);
13762         
13763         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13764             e.remove();
13765         });
13766         
13767     },
13768     
13769     renderEvents: function()
13770     {   
13771         var _this = this;
13772         
13773         this.cells.each(function(c) {
13774             
13775             if(c.row < 5){
13776                 return;
13777             }
13778             
13779             var ev = c.events;
13780             
13781             var r = 4;
13782             if(c.row != c.events.length){
13783                 r = 4 - (4 - (c.row - c.events.length));
13784             }
13785             
13786             c.events = ev.slice(0, r);
13787             c.more = ev.slice(r);
13788             
13789             if(c.more.length && c.more.length == 1){
13790                 c.events.push(c.more.pop());
13791             }
13792             
13793             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13794             
13795         });
13796             
13797         this.cells.each(function(c) {
13798             
13799             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13800             
13801             
13802             for (var e = 0; e < c.events.length; e++){
13803                 var ev = c.events[e];
13804                 var rows = ev.rows;
13805                 
13806                 for(var i = 0; i < rows.length; i++) {
13807                 
13808                     // how many rows should it span..
13809
13810                     var  cfg = {
13811                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13812                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13813
13814                         unselectable : "on",
13815                         cn : [
13816                             {
13817                                 cls: 'fc-event-inner',
13818                                 cn : [
13819     //                                {
13820     //                                  tag:'span',
13821     //                                  cls: 'fc-event-time',
13822     //                                  html : cells.length > 1 ? '' : ev.time
13823     //                                },
13824                                     {
13825                                       tag:'span',
13826                                       cls: 'fc-event-title',
13827                                       html : String.format('{0}', ev.title)
13828                                     }
13829
13830
13831                                 ]
13832                             },
13833                             {
13834                                 cls: 'ui-resizable-handle ui-resizable-e',
13835                                 html : '&nbsp;&nbsp;&nbsp'
13836                             }
13837
13838                         ]
13839                     };
13840
13841                     if (i == 0) {
13842                         cfg.cls += ' fc-event-start';
13843                     }
13844                     if ((i+1) == rows.length) {
13845                         cfg.cls += ' fc-event-end';
13846                     }
13847
13848                     var ctr = _this.el.select('.fc-event-container',true).first();
13849                     var cg = ctr.createChild(cfg);
13850
13851                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13852                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13853
13854                     var r = (c.more.length) ? 1 : 0;
13855                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13856                     cg.setWidth(ebox.right - sbox.x -2);
13857
13858                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13859                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13860                     cg.on('click', _this.onEventClick, _this, ev);
13861
13862                     ev.els.push(cg);
13863                     
13864                 }
13865                 
13866             }
13867             
13868             
13869             if(c.more.length){
13870                 var  cfg = {
13871                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13872                     style : 'position: absolute',
13873                     unselectable : "on",
13874                     cn : [
13875                         {
13876                             cls: 'fc-event-inner',
13877                             cn : [
13878                                 {
13879                                   tag:'span',
13880                                   cls: 'fc-event-title',
13881                                   html : 'More'
13882                                 }
13883
13884
13885                             ]
13886                         },
13887                         {
13888                             cls: 'ui-resizable-handle ui-resizable-e',
13889                             html : '&nbsp;&nbsp;&nbsp'
13890                         }
13891
13892                     ]
13893                 };
13894
13895                 var ctr = _this.el.select('.fc-event-container',true).first();
13896                 var cg = ctr.createChild(cfg);
13897
13898                 var sbox = c.select('.fc-day-content',true).first().getBox();
13899                 var ebox = c.select('.fc-day-content',true).first().getBox();
13900                 //Roo.log(cg);
13901                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13902                 cg.setWidth(ebox.right - sbox.x -2);
13903
13904                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13905                 
13906             }
13907             
13908         });
13909         
13910         
13911         
13912     },
13913     
13914     onEventEnter: function (e, el,event,d) {
13915         this.fireEvent('evententer', this, el, event);
13916     },
13917     
13918     onEventLeave: function (e, el,event,d) {
13919         this.fireEvent('eventleave', this, el, event);
13920     },
13921     
13922     onEventClick: function (e, el,event,d) {
13923         this.fireEvent('eventclick', this, el, event);
13924     },
13925     
13926     onMonthChange: function () {
13927         this.store.load();
13928     },
13929     
13930     onMoreEventClick: function(e, el, more)
13931     {
13932         var _this = this;
13933         
13934         this.calpopover.placement = 'right';
13935         this.calpopover.setTitle('More');
13936         
13937         this.calpopover.setContent('');
13938         
13939         var ctr = this.calpopover.el.select('.popover-content', true).first();
13940         
13941         Roo.each(more, function(m){
13942             var cfg = {
13943                 cls : 'fc-event-hori fc-event-draggable',
13944                 html : m.title
13945             }
13946             var cg = ctr.createChild(cfg);
13947             
13948             cg.on('click', _this.onEventClick, _this, m);
13949         });
13950         
13951         this.calpopover.show(el);
13952         
13953         
13954     },
13955     
13956     onLoad: function () 
13957     {   
13958         this.calevents = [];
13959         var cal = this;
13960         
13961         if(this.store.getCount() > 0){
13962             this.store.data.each(function(d){
13963                cal.addItem({
13964                     id : d.data.id,
13965                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13966                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13967                     time : d.data.start_time,
13968                     title : d.data.title,
13969                     description : d.data.description,
13970                     venue : d.data.venue
13971                 });
13972             });
13973         }
13974         
13975         this.renderEvents();
13976         
13977         if(this.calevents.length && this.loadMask){
13978             this.maskEl.hide();
13979         }
13980     },
13981     
13982     onBeforeLoad: function()
13983     {
13984         this.clearEvents();
13985         if(this.loadMask){
13986             this.maskEl.show();
13987         }
13988     }
13989 });
13990
13991  
13992  /*
13993  * - LGPL
13994  *
13995  * element
13996  * 
13997  */
13998
13999 /**
14000  * @class Roo.bootstrap.Popover
14001  * @extends Roo.bootstrap.Component
14002  * Bootstrap Popover class
14003  * @cfg {String} html contents of the popover   (or false to use children..)
14004  * @cfg {String} title of popover (or false to hide)
14005  * @cfg {String} placement how it is placed
14006  * @cfg {String} trigger click || hover (or false to trigger manually)
14007  * @cfg {String} over what (parent or false to trigger manually.)
14008  * @cfg {Number} delay - delay before showing
14009  
14010  * @constructor
14011  * Create a new Popover
14012  * @param {Object} config The config object
14013  */
14014
14015 Roo.bootstrap.Popover = function(config){
14016     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14017 };
14018
14019 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14020     
14021     title: 'Fill in a title',
14022     html: false,
14023     
14024     placement : 'right',
14025     trigger : 'hover', // hover
14026     
14027     delay : 0,
14028     
14029     over: 'parent',
14030     
14031     can_build_overlaid : false,
14032     
14033     getChildContainer : function()
14034     {
14035         return this.el.select('.popover-content',true).first();
14036     },
14037     
14038     getAutoCreate : function(){
14039          Roo.log('make popover?');
14040         var cfg = {
14041            cls : 'popover roo-dynamic',
14042            style: 'display:block',
14043            cn : [
14044                 {
14045                     cls : 'arrow'
14046                 },
14047                 {
14048                     cls : 'popover-inner',
14049                     cn : [
14050                         {
14051                             tag: 'h3',
14052                             cls: 'popover-title',
14053                             html : this.title
14054                         },
14055                         {
14056                             cls : 'popover-content',
14057                             html : this.html
14058                         }
14059                     ]
14060                     
14061                 }
14062            ]
14063         };
14064         
14065         return cfg;
14066     },
14067     setTitle: function(str)
14068     {
14069         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14070     },
14071     setContent: function(str)
14072     {
14073         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14074     },
14075     // as it get's added to the bottom of the page.
14076     onRender : function(ct, position)
14077     {
14078         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14079         if(!this.el){
14080             var cfg = Roo.apply({},  this.getAutoCreate());
14081             cfg.id = Roo.id();
14082             
14083             if (this.cls) {
14084                 cfg.cls += ' ' + this.cls;
14085             }
14086             if (this.style) {
14087                 cfg.style = this.style;
14088             }
14089             Roo.log("adding to ")
14090             this.el = Roo.get(document.body).createChild(cfg, position);
14091             Roo.log(this.el);
14092         }
14093         this.initEvents();
14094     },
14095     
14096     initEvents : function()
14097     {
14098         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14099         this.el.enableDisplayMode('block');
14100         this.el.hide();
14101         if (this.over === false) {
14102             return; 
14103         }
14104         if (this.triggers === false) {
14105             return;
14106         }
14107         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14108         var triggers = this.trigger ? this.trigger.split(' ') : [];
14109         Roo.each(triggers, function(trigger) {
14110         
14111             if (trigger == 'click') {
14112                 on_el.on('click', this.toggle, this);
14113             } else if (trigger != 'manual') {
14114                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14115                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14116       
14117                 on_el.on(eventIn  ,this.enter, this);
14118                 on_el.on(eventOut, this.leave, this);
14119             }
14120         }, this);
14121         
14122     },
14123     
14124     
14125     // private
14126     timeout : null,
14127     hoverState : null,
14128     
14129     toggle : function () {
14130         this.hoverState == 'in' ? this.leave() : this.enter();
14131     },
14132     
14133     enter : function () {
14134        
14135     
14136         clearTimeout(this.timeout);
14137     
14138         this.hoverState = 'in';
14139     
14140         if (!this.delay || !this.delay.show) {
14141             this.show();
14142             return;
14143         }
14144         var _t = this;
14145         this.timeout = setTimeout(function () {
14146             if (_t.hoverState == 'in') {
14147                 _t.show();
14148             }
14149         }, this.delay.show)
14150     },
14151     leave : function() {
14152         clearTimeout(this.timeout);
14153     
14154         this.hoverState = 'out';
14155     
14156         if (!this.delay || !this.delay.hide) {
14157             this.hide();
14158             return;
14159         }
14160         var _t = this;
14161         this.timeout = setTimeout(function () {
14162             if (_t.hoverState == 'out') {
14163                 _t.hide();
14164             }
14165         }, this.delay.hide)
14166     },
14167     
14168     show : function (on_el)
14169     {
14170         if (!on_el) {
14171             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14172         }
14173         // set content.
14174         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14175         if (this.html !== false) {
14176             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14177         }
14178         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14179         if (!this.title.length) {
14180             this.el.select('.popover-title',true).hide();
14181         }
14182         
14183         var placement = typeof this.placement == 'function' ?
14184             this.placement.call(this, this.el, on_el) :
14185             this.placement;
14186             
14187         var autoToken = /\s?auto?\s?/i;
14188         var autoPlace = autoToken.test(placement);
14189         if (autoPlace) {
14190             placement = placement.replace(autoToken, '') || 'top';
14191         }
14192         
14193         //this.el.detach()
14194         //this.el.setXY([0,0]);
14195         this.el.show();
14196         this.el.dom.style.display='block';
14197         this.el.addClass(placement);
14198         
14199         //this.el.appendTo(on_el);
14200         
14201         var p = this.getPosition();
14202         var box = this.el.getBox();
14203         
14204         if (autoPlace) {
14205             // fixme..
14206         }
14207         var align = Roo.bootstrap.Popover.alignment[placement];
14208         this.el.alignTo(on_el, align[0],align[1]);
14209         //var arrow = this.el.select('.arrow',true).first();
14210         //arrow.set(align[2], 
14211         
14212         this.el.addClass('in');
14213         this.hoverState = null;
14214         
14215         if (this.el.hasClass('fade')) {
14216             // fade it?
14217         }
14218         
14219     },
14220     hide : function()
14221     {
14222         this.el.setXY([0,0]);
14223         this.el.removeClass('in');
14224         this.el.hide();
14225         
14226     }
14227     
14228 });
14229
14230 Roo.bootstrap.Popover.alignment = {
14231     'left' : ['r-l', [-10,0], 'right'],
14232     'right' : ['l-r', [10,0], 'left'],
14233     'bottom' : ['t-b', [0,10], 'top'],
14234     'top' : [ 'b-t', [0,-10], 'bottom']
14235 };
14236
14237  /*
14238  * - LGPL
14239  *
14240  * Progress
14241  * 
14242  */
14243
14244 /**
14245  * @class Roo.bootstrap.Progress
14246  * @extends Roo.bootstrap.Component
14247  * Bootstrap Progress class
14248  * @cfg {Boolean} striped striped of the progress bar
14249  * @cfg {Boolean} active animated of the progress bar
14250  * 
14251  * 
14252  * @constructor
14253  * Create a new Progress
14254  * @param {Object} config The config object
14255  */
14256
14257 Roo.bootstrap.Progress = function(config){
14258     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14259 };
14260
14261 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14262     
14263     striped : false,
14264     active: false,
14265     
14266     getAutoCreate : function(){
14267         var cfg = {
14268             tag: 'div',
14269             cls: 'progress'
14270         };
14271         
14272         
14273         if(this.striped){
14274             cfg.cls += ' progress-striped';
14275         }
14276       
14277         if(this.active){
14278             cfg.cls += ' active';
14279         }
14280         
14281         
14282         return cfg;
14283     }
14284    
14285 });
14286
14287  
14288
14289  /*
14290  * - LGPL
14291  *
14292  * ProgressBar
14293  * 
14294  */
14295
14296 /**
14297  * @class Roo.bootstrap.ProgressBar
14298  * @extends Roo.bootstrap.Component
14299  * Bootstrap ProgressBar class
14300  * @cfg {Number} aria_valuenow aria-value now
14301  * @cfg {Number} aria_valuemin aria-value min
14302  * @cfg {Number} aria_valuemax aria-value max
14303  * @cfg {String} label label for the progress bar
14304  * @cfg {String} panel (success | info | warning | danger )
14305  * @cfg {String} role role of the progress bar
14306  * @cfg {String} sr_only text
14307  * 
14308  * 
14309  * @constructor
14310  * Create a new ProgressBar
14311  * @param {Object} config The config object
14312  */
14313
14314 Roo.bootstrap.ProgressBar = function(config){
14315     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14316 };
14317
14318 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14319     
14320     aria_valuenow : 0,
14321     aria_valuemin : 0,
14322     aria_valuemax : 100,
14323     label : false,
14324     panel : false,
14325     role : false,
14326     sr_only: false,
14327     
14328     getAutoCreate : function()
14329     {
14330         
14331         var cfg = {
14332             tag: 'div',
14333             cls: 'progress-bar',
14334             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14335         };
14336         
14337         if(this.sr_only){
14338             cfg.cn = {
14339                 tag: 'span',
14340                 cls: 'sr-only',
14341                 html: this.sr_only
14342             }
14343         }
14344         
14345         if(this.role){
14346             cfg.role = this.role;
14347         }
14348         
14349         if(this.aria_valuenow){
14350             cfg['aria-valuenow'] = this.aria_valuenow;
14351         }
14352         
14353         if(this.aria_valuemin){
14354             cfg['aria-valuemin'] = this.aria_valuemin;
14355         }
14356         
14357         if(this.aria_valuemax){
14358             cfg['aria-valuemax'] = this.aria_valuemax;
14359         }
14360         
14361         if(this.label && !this.sr_only){
14362             cfg.html = this.label;
14363         }
14364         
14365         if(this.panel){
14366             cfg.cls += ' progress-bar-' + this.panel;
14367         }
14368         
14369         return cfg;
14370     },
14371     
14372     update : function(aria_valuenow)
14373     {
14374         this.aria_valuenow = aria_valuenow;
14375         
14376         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14377     }
14378    
14379 });
14380
14381  
14382
14383  /*
14384  * - LGPL
14385  *
14386  * column
14387  * 
14388  */
14389
14390 /**
14391  * @class Roo.bootstrap.TabGroup
14392  * @extends Roo.bootstrap.Column
14393  * Bootstrap Column class
14394  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14395  * @cfg {Boolean} carousel true to make the group behave like a carousel
14396  * 
14397  * @constructor
14398  * Create a new TabGroup
14399  * @param {Object} config The config object
14400  */
14401
14402 Roo.bootstrap.TabGroup = function(config){
14403     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14404     if (!this.navId) {
14405         this.navId = Roo.id();
14406     }
14407     this.tabs = [];
14408     Roo.bootstrap.TabGroup.register(this);
14409     
14410 };
14411
14412 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14413     
14414     carousel : false,
14415     transition : false,
14416      
14417     getAutoCreate : function()
14418     {
14419         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14420         
14421         cfg.cls += ' tab-content';
14422         
14423         if (this.carousel) {
14424             cfg.cls += ' carousel slide';
14425             cfg.cn = [{
14426                cls : 'carousel-inner'
14427             }]
14428         }
14429         
14430         
14431         return cfg;
14432     },
14433     getChildContainer : function()
14434     {
14435         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14436     },
14437     
14438     /**
14439     * register a Navigation item
14440     * @param {Roo.bootstrap.NavItem} the navitem to add
14441     */
14442     register : function(item)
14443     {
14444         this.tabs.push( item);
14445         item.navId = this.navId; // not really needed..
14446     
14447     },
14448     
14449     getActivePanel : function()
14450     {
14451         var r = false;
14452         Roo.each(this.tabs, function(t) {
14453             if (t.active) {
14454                 r = t;
14455                 return false;
14456             }
14457             return null;
14458         });
14459         return r;
14460         
14461     },
14462     getPanelByName : function(n)
14463     {
14464         var r = false;
14465         Roo.each(this.tabs, function(t) {
14466             if (t.tabId == n) {
14467                 r = t;
14468                 return false;
14469             }
14470             return null;
14471         });
14472         return r;
14473     },
14474     indexOfPanel : function(p)
14475     {
14476         var r = false;
14477         Roo.each(this.tabs, function(t,i) {
14478             if (t.tabId == p.tabId) {
14479                 r = i;
14480                 return false;
14481             }
14482             return null;
14483         });
14484         return r;
14485     },
14486     /**
14487      * show a specific panel
14488      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14489      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14490      */
14491     showPanel : function (pan)
14492     {
14493         
14494         if (typeof(pan) == 'number') {
14495             pan = this.tabs[pan];
14496         }
14497         if (typeof(pan) == 'string') {
14498             pan = this.getPanelByName(pan);
14499         }
14500         if (pan.tabId == this.getActivePanel().tabId) {
14501             return true;
14502         }
14503         var cur = this.getActivePanel();
14504         
14505         if (false === cur.fireEvent('beforedeactivate')) {
14506             return false;
14507         }
14508         
14509         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14510             
14511             this.transition = true;
14512             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14513             var lr = dir == 'next' ? 'left' : 'right';
14514             pan.el.addClass(dir); // or prev
14515             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14516             cur.el.addClass(lr); // or right
14517             pan.el.addClass(lr);
14518             
14519             var _this = this;
14520             cur.el.on('transitionend', function() {
14521                 Roo.log("trans end?");
14522                 
14523                 pan.el.removeClass([lr,dir]);
14524                 pan.setActive(true);
14525                 
14526                 cur.el.removeClass([lr]);
14527                 cur.setActive(false);
14528                 
14529                 _this.transition = false;
14530                 
14531             }, this, { single:  true } );
14532             return true;
14533         }
14534         
14535         cur.setActive(false);
14536         pan.setActive(true);
14537         return true;
14538         
14539     },
14540     showPanelNext : function()
14541     {
14542         var i = this.indexOfPanel(this.getActivePanel());
14543         if (i > this.tabs.length) {
14544             return;
14545         }
14546         this.showPanel(this.tabs[i+1]);
14547     },
14548     showPanelPrev : function()
14549     {
14550         var i = this.indexOfPanel(this.getActivePanel());
14551         if (i  < 1) {
14552             return;
14553         }
14554         this.showPanel(this.tabs[i-1]);
14555     }
14556     
14557     
14558   
14559 });
14560
14561  
14562
14563  
14564  
14565 Roo.apply(Roo.bootstrap.TabGroup, {
14566     
14567     groups: {},
14568      /**
14569     * register a Navigation Group
14570     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14571     */
14572     register : function(navgrp)
14573     {
14574         this.groups[navgrp.navId] = navgrp;
14575         
14576     },
14577     /**
14578     * fetch a Navigation Group based on the navigation ID
14579     * if one does not exist , it will get created.
14580     * @param {string} the navgroup to add
14581     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14582     */
14583     get: function(navId) {
14584         if (typeof(this.groups[navId]) == 'undefined') {
14585             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14586         }
14587         return this.groups[navId] ;
14588     }
14589     
14590     
14591     
14592 });
14593
14594  /*
14595  * - LGPL
14596  *
14597  * TabPanel
14598  * 
14599  */
14600
14601 /**
14602  * @class Roo.bootstrap.TabPanel
14603  * @extends Roo.bootstrap.Component
14604  * Bootstrap TabPanel class
14605  * @cfg {Boolean} active panel active
14606  * @cfg {String} html panel content
14607  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14608  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14609  * 
14610  * 
14611  * @constructor
14612  * Create a new TabPanel
14613  * @param {Object} config The config object
14614  */
14615
14616 Roo.bootstrap.TabPanel = function(config){
14617     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14618     this.addEvents({
14619         /**
14620              * @event changed
14621              * Fires when the active status changes
14622              * @param {Roo.bootstrap.TabPanel} this
14623              * @param {Boolean} state the new state
14624             
14625          */
14626         'changed': true,
14627         /**
14628              * @event beforedeactivate
14629              * Fires before a tab is de-activated - can be used to do validation on a form.
14630              * @param {Roo.bootstrap.TabPanel} this
14631              * @return {Boolean} false if there is an error
14632             
14633          */
14634         'beforedeactivate': true
14635      });
14636     
14637     this.tabId = this.tabId || Roo.id();
14638   
14639 };
14640
14641 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14642     
14643     active: false,
14644     html: false,
14645     tabId: false,
14646     navId : false,
14647     
14648     getAutoCreate : function(){
14649         var cfg = {
14650             tag: 'div',
14651             // item is needed for carousel - not sure if it has any effect otherwise
14652             cls: 'tab-pane item',
14653             html: this.html || ''
14654         };
14655         
14656         if(this.active){
14657             cfg.cls += ' active';
14658         }
14659         
14660         if(this.tabId){
14661             cfg.tabId = this.tabId;
14662         }
14663         
14664         
14665         return cfg;
14666     },
14667     
14668     initEvents:  function()
14669     {
14670         Roo.log('-------- init events on tab panel ---------');
14671         
14672         var p = this.parent();
14673         this.navId = this.navId || p.navId;
14674         
14675         if (typeof(this.navId) != 'undefined') {
14676             // not really needed.. but just in case.. parent should be a NavGroup.
14677             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14678             Roo.log(['register', tg, this]);
14679             tg.register(this);
14680         }
14681     },
14682     
14683     
14684     onRender : function(ct, position)
14685     {
14686        // Roo.log("Call onRender: " + this.xtype);
14687         
14688         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14689         
14690         
14691         
14692         
14693         
14694     },
14695     
14696     setActive: function(state)
14697     {
14698         Roo.log("panel - set active " + this.tabId + "=" + state);
14699         
14700         this.active = state;
14701         if (!state) {
14702             this.el.removeClass('active');
14703             
14704         } else  if (!this.el.hasClass('active')) {
14705             this.el.addClass('active');
14706         }
14707         this.fireEvent('changed', this, state);
14708     }
14709     
14710     
14711 });
14712  
14713
14714  
14715
14716  /*
14717  * - LGPL
14718  *
14719  * DateField
14720  * 
14721  */
14722
14723 /**
14724  * @class Roo.bootstrap.DateField
14725  * @extends Roo.bootstrap.Input
14726  * Bootstrap DateField class
14727  * @cfg {Number} weekStart default 0
14728  * @cfg {String} viewMode default empty, (months|years)
14729  * @cfg {String} minViewMode default empty, (months|years)
14730  * @cfg {Number} startDate default -Infinity
14731  * @cfg {Number} endDate default Infinity
14732  * @cfg {Boolean} todayHighlight default false
14733  * @cfg {Boolean} todayBtn default false
14734  * @cfg {Boolean} calendarWeeks default false
14735  * @cfg {Object} daysOfWeekDisabled default empty
14736  * @cfg {Boolean} singleMode default false (true | false)
14737  * 
14738  * @cfg {Boolean} keyboardNavigation default true
14739  * @cfg {String} language default en
14740  * 
14741  * @constructor
14742  * Create a new DateField
14743  * @param {Object} config The config object
14744  */
14745
14746 Roo.bootstrap.DateField = function(config){
14747     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14748      this.addEvents({
14749             /**
14750              * @event show
14751              * Fires when this field show.
14752              * @param {Roo.bootstrap.DateField} this
14753              * @param {Mixed} date The date value
14754              */
14755             show : true,
14756             /**
14757              * @event show
14758              * Fires when this field hide.
14759              * @param {Roo.bootstrap.DateField} this
14760              * @param {Mixed} date The date value
14761              */
14762             hide : true,
14763             /**
14764              * @event select
14765              * Fires when select a date.
14766              * @param {Roo.bootstrap.DateField} this
14767              * @param {Mixed} date The date value
14768              */
14769             select : true
14770         });
14771 };
14772
14773 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14774     
14775     /**
14776      * @cfg {String} format
14777      * The default date format string which can be overriden for localization support.  The format must be
14778      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14779      */
14780     format : "m/d/y",
14781     /**
14782      * @cfg {String} altFormats
14783      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14784      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14785      */
14786     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14787     
14788     weekStart : 0,
14789     
14790     viewMode : '',
14791     
14792     minViewMode : '',
14793     
14794     todayHighlight : false,
14795     
14796     todayBtn: false,
14797     
14798     language: 'en',
14799     
14800     keyboardNavigation: true,
14801     
14802     calendarWeeks: false,
14803     
14804     startDate: -Infinity,
14805     
14806     endDate: Infinity,
14807     
14808     daysOfWeekDisabled: [],
14809     
14810     _events: [],
14811     
14812     singleMode : false,
14813     
14814     UTCDate: function()
14815     {
14816         return new Date(Date.UTC.apply(Date, arguments));
14817     },
14818     
14819     UTCToday: function()
14820     {
14821         var today = new Date();
14822         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14823     },
14824     
14825     getDate: function() {
14826             var d = this.getUTCDate();
14827             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14828     },
14829     
14830     getUTCDate: function() {
14831             return this.date;
14832     },
14833     
14834     setDate: function(d) {
14835             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14836     },
14837     
14838     setUTCDate: function(d) {
14839             this.date = d;
14840             this.setValue(this.formatDate(this.date));
14841     },
14842         
14843     onRender: function(ct, position)
14844     {
14845         
14846         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14847         
14848         this.language = this.language || 'en';
14849         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14850         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14851         
14852         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14853         this.format = this.format || 'm/d/y';
14854         this.isInline = false;
14855         this.isInput = true;
14856         this.component = this.el.select('.add-on', true).first() || false;
14857         this.component = (this.component && this.component.length === 0) ? false : this.component;
14858         this.hasInput = this.component && this.inputEL().length;
14859         
14860         if (typeof(this.minViewMode === 'string')) {
14861             switch (this.minViewMode) {
14862                 case 'months':
14863                     this.minViewMode = 1;
14864                     break;
14865                 case 'years':
14866                     this.minViewMode = 2;
14867                     break;
14868                 default:
14869                     this.minViewMode = 0;
14870                     break;
14871             }
14872         }
14873         
14874         if (typeof(this.viewMode === 'string')) {
14875             switch (this.viewMode) {
14876                 case 'months':
14877                     this.viewMode = 1;
14878                     break;
14879                 case 'years':
14880                     this.viewMode = 2;
14881                     break;
14882                 default:
14883                     this.viewMode = 0;
14884                     break;
14885             }
14886         }
14887                 
14888         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14889         
14890 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14891         
14892         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14893         
14894         this.picker().on('mousedown', this.onMousedown, this);
14895         this.picker().on('click', this.onClick, this);
14896         
14897         this.picker().addClass('datepicker-dropdown');
14898         
14899         this.startViewMode = this.viewMode;
14900         
14901         if(this.singleMode){
14902             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14903                 v.setVisibilityMode(Roo.Element.DISPLAY)
14904                 v.hide();
14905             });
14906             
14907             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14908                 v.setStyle('width', '189px');
14909             });
14910         }
14911         
14912         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14913             if(!this.calendarWeeks){
14914                 v.remove();
14915                 return;
14916             }
14917             
14918             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14919             v.attr('colspan', function(i, val){
14920                 return parseInt(val) + 1;
14921             });
14922         })
14923                         
14924         
14925         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14926         
14927         this.setStartDate(this.startDate);
14928         this.setEndDate(this.endDate);
14929         
14930         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14931         
14932         this.fillDow();
14933         this.fillMonths();
14934         this.update();
14935         this.showMode();
14936         
14937         if(this.isInline) {
14938             this.show();
14939         }
14940     },
14941     
14942     picker : function()
14943     {
14944         return this.pickerEl;
14945 //        return this.el.select('.datepicker', true).first();
14946     },
14947     
14948     fillDow: function()
14949     {
14950         var dowCnt = this.weekStart;
14951         
14952         var dow = {
14953             tag: 'tr',
14954             cn: [
14955                 
14956             ]
14957         };
14958         
14959         if(this.calendarWeeks){
14960             dow.cn.push({
14961                 tag: 'th',
14962                 cls: 'cw',
14963                 html: '&nbsp;'
14964             })
14965         }
14966         
14967         while (dowCnt < this.weekStart + 7) {
14968             dow.cn.push({
14969                 tag: 'th',
14970                 cls: 'dow',
14971                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14972             });
14973         }
14974         
14975         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14976     },
14977     
14978     fillMonths: function()
14979     {    
14980         var i = 0;
14981         var months = this.picker().select('>.datepicker-months td', true).first();
14982         
14983         months.dom.innerHTML = '';
14984         
14985         while (i < 12) {
14986             var month = {
14987                 tag: 'span',
14988                 cls: 'month',
14989                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14990             }
14991             
14992             months.createChild(month);
14993         }
14994         
14995     },
14996     
14997     update: function()
14998     {
14999         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;
15000         
15001         if (this.date < this.startDate) {
15002             this.viewDate = new Date(this.startDate);
15003         } else if (this.date > this.endDate) {
15004             this.viewDate = new Date(this.endDate);
15005         } else {
15006             this.viewDate = new Date(this.date);
15007         }
15008         
15009         this.fill();
15010     },
15011     
15012     fill: function() 
15013     {
15014         var d = new Date(this.viewDate),
15015                 year = d.getUTCFullYear(),
15016                 month = d.getUTCMonth(),
15017                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15018                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15019                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15020                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15021                 currentDate = this.date && this.date.valueOf(),
15022                 today = this.UTCToday();
15023         
15024         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15025         
15026 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15027         
15028 //        this.picker.select('>tfoot th.today').
15029 //                                              .text(dates[this.language].today)
15030 //                                              .toggle(this.todayBtn !== false);
15031     
15032         this.updateNavArrows();
15033         this.fillMonths();
15034                                                 
15035         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15036         
15037         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15038          
15039         prevMonth.setUTCDate(day);
15040         
15041         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15042         
15043         var nextMonth = new Date(prevMonth);
15044         
15045         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15046         
15047         nextMonth = nextMonth.valueOf();
15048         
15049         var fillMonths = false;
15050         
15051         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15052         
15053         while(prevMonth.valueOf() < nextMonth) {
15054             var clsName = '';
15055             
15056             if (prevMonth.getUTCDay() === this.weekStart) {
15057                 if(fillMonths){
15058                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15059                 }
15060                     
15061                 fillMonths = {
15062                     tag: 'tr',
15063                     cn: []
15064                 };
15065                 
15066                 if(this.calendarWeeks){
15067                     // ISO 8601: First week contains first thursday.
15068                     // ISO also states week starts on Monday, but we can be more abstract here.
15069                     var
15070                     // Start of current week: based on weekstart/current date
15071                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15072                     // Thursday of this week
15073                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15074                     // First Thursday of year, year from thursday
15075                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15076                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15077                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15078                     
15079                     fillMonths.cn.push({
15080                         tag: 'td',
15081                         cls: 'cw',
15082                         html: calWeek
15083                     });
15084                 }
15085             }
15086             
15087             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15088                 clsName += ' old';
15089             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15090                 clsName += ' new';
15091             }
15092             if (this.todayHighlight &&
15093                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15094                 prevMonth.getUTCMonth() == today.getMonth() &&
15095                 prevMonth.getUTCDate() == today.getDate()) {
15096                 clsName += ' today';
15097             }
15098             
15099             if (currentDate && prevMonth.valueOf() === currentDate) {
15100                 clsName += ' active';
15101             }
15102             
15103             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15104                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15105                     clsName += ' disabled';
15106             }
15107             
15108             fillMonths.cn.push({
15109                 tag: 'td',
15110                 cls: 'day ' + clsName,
15111                 html: prevMonth.getDate()
15112             })
15113             
15114             prevMonth.setDate(prevMonth.getDate()+1);
15115         }
15116           
15117         var currentYear = this.date && this.date.getUTCFullYear();
15118         var currentMonth = this.date && this.date.getUTCMonth();
15119         
15120         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15121         
15122         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15123             v.removeClass('active');
15124             
15125             if(currentYear === year && k === currentMonth){
15126                 v.addClass('active');
15127             }
15128             
15129             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15130                 v.addClass('disabled');
15131             }
15132             
15133         });
15134         
15135         
15136         year = parseInt(year/10, 10) * 10;
15137         
15138         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15139         
15140         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15141         
15142         year -= 1;
15143         for (var i = -1; i < 11; i++) {
15144             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15145                 tag: 'span',
15146                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15147                 html: year
15148             })
15149             
15150             year += 1;
15151         }
15152     },
15153     
15154     showMode: function(dir) 
15155     {
15156         if (dir) {
15157             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15158         }
15159         
15160         Roo.each(this.picker().select('>div',true).elements, function(v){
15161             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15162             v.hide();
15163         });
15164         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15165     },
15166     
15167     place: function()
15168     {
15169         if(this.isInline) return;
15170         
15171         this.picker().removeClass(['bottom', 'top']);
15172         
15173         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15174             /*
15175              * place to the top of element!
15176              *
15177              */
15178             
15179             this.picker().addClass('top');
15180             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15181             
15182             return;
15183         }
15184         
15185         this.picker().addClass('bottom');
15186         
15187         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15188     },
15189     
15190     parseDate : function(value)
15191     {
15192         if(!value || value instanceof Date){
15193             return value;
15194         }
15195         var v = Date.parseDate(value, this.format);
15196         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15197             v = Date.parseDate(value, 'Y-m-d');
15198         }
15199         if(!v && this.altFormats){
15200             if(!this.altFormatsArray){
15201                 this.altFormatsArray = this.altFormats.split("|");
15202             }
15203             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15204                 v = Date.parseDate(value, this.altFormatsArray[i]);
15205             }
15206         }
15207         return v;
15208     },
15209     
15210     formatDate : function(date, fmt)
15211     {   
15212         return (!date || !(date instanceof Date)) ?
15213         date : date.dateFormat(fmt || this.format);
15214     },
15215     
15216     onFocus : function()
15217     {
15218         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15219         this.show();
15220     },
15221     
15222     onBlur : function()
15223     {
15224         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15225         
15226         var d = this.inputEl().getValue();
15227         
15228         this.setValue(d);
15229                 
15230         this.hide();
15231     },
15232     
15233     show : function()
15234     {
15235         this.picker().show();
15236         this.update();
15237         this.place();
15238         
15239         this.fireEvent('show', this, this.date);
15240     },
15241     
15242     hide : function()
15243     {
15244         if(this.isInline) return;
15245         this.picker().hide();
15246         this.viewMode = this.startViewMode;
15247         this.showMode();
15248         
15249         this.fireEvent('hide', this, this.date);
15250         
15251     },
15252     
15253     onMousedown: function(e)
15254     {
15255         e.stopPropagation();
15256         e.preventDefault();
15257     },
15258     
15259     keyup: function(e)
15260     {
15261         Roo.bootstrap.DateField.superclass.keyup.call(this);
15262         this.update();
15263     },
15264
15265     setValue: function(v)
15266     {
15267         
15268         // v can be a string or a date..
15269         
15270         
15271         var d = new Date(this.parseDate(v) ).clearTime();
15272         
15273         if(isNaN(d.getTime())){
15274             this.date = this.viewDate = '';
15275             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15276             return;
15277         }
15278         
15279         v = this.formatDate(d);
15280         
15281         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15282         
15283         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15284      
15285         this.update();
15286
15287         this.fireEvent('select', this, this.date);
15288         
15289     },
15290     
15291     getValue: function()
15292     {
15293         return this.formatDate(this.date);
15294     },
15295     
15296     fireKey: function(e)
15297     {
15298         if (!this.picker().isVisible()){
15299             if (e.keyCode == 27) // allow escape to hide and re-show picker
15300                 this.show();
15301             return;
15302         }
15303         
15304         var dateChanged = false,
15305         dir, day, month,
15306         newDate, newViewDate;
15307         
15308         switch(e.keyCode){
15309             case 27: // escape
15310                 this.hide();
15311                 e.preventDefault();
15312                 break;
15313             case 37: // left
15314             case 39: // right
15315                 if (!this.keyboardNavigation) break;
15316                 dir = e.keyCode == 37 ? -1 : 1;
15317                 
15318                 if (e.ctrlKey){
15319                     newDate = this.moveYear(this.date, dir);
15320                     newViewDate = this.moveYear(this.viewDate, dir);
15321                 } else if (e.shiftKey){
15322                     newDate = this.moveMonth(this.date, dir);
15323                     newViewDate = this.moveMonth(this.viewDate, dir);
15324                 } else {
15325                     newDate = new Date(this.date);
15326                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15327                     newViewDate = new Date(this.viewDate);
15328                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15329                 }
15330                 if (this.dateWithinRange(newDate)){
15331                     this.date = newDate;
15332                     this.viewDate = newViewDate;
15333                     this.setValue(this.formatDate(this.date));
15334 //                    this.update();
15335                     e.preventDefault();
15336                     dateChanged = true;
15337                 }
15338                 break;
15339             case 38: // up
15340             case 40: // down
15341                 if (!this.keyboardNavigation) break;
15342                 dir = e.keyCode == 38 ? -1 : 1;
15343                 if (e.ctrlKey){
15344                     newDate = this.moveYear(this.date, dir);
15345                     newViewDate = this.moveYear(this.viewDate, dir);
15346                 } else if (e.shiftKey){
15347                     newDate = this.moveMonth(this.date, dir);
15348                     newViewDate = this.moveMonth(this.viewDate, dir);
15349                 } else {
15350                     newDate = new Date(this.date);
15351                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15352                     newViewDate = new Date(this.viewDate);
15353                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15354                 }
15355                 if (this.dateWithinRange(newDate)){
15356                     this.date = newDate;
15357                     this.viewDate = newViewDate;
15358                     this.setValue(this.formatDate(this.date));
15359 //                    this.update();
15360                     e.preventDefault();
15361                     dateChanged = true;
15362                 }
15363                 break;
15364             case 13: // enter
15365                 this.setValue(this.formatDate(this.date));
15366                 this.hide();
15367                 e.preventDefault();
15368                 break;
15369             case 9: // tab
15370                 this.setValue(this.formatDate(this.date));
15371                 this.hide();
15372                 break;
15373             case 16: // shift
15374             case 17: // ctrl
15375             case 18: // alt
15376                 break;
15377             default :
15378                 this.hide();
15379                 
15380         }
15381     },
15382     
15383     
15384     onClick: function(e) 
15385     {
15386         e.stopPropagation();
15387         e.preventDefault();
15388         
15389         var target = e.getTarget();
15390         
15391         if(target.nodeName.toLowerCase() === 'i'){
15392             target = Roo.get(target).dom.parentNode;
15393         }
15394         
15395         var nodeName = target.nodeName;
15396         var className = target.className;
15397         var html = target.innerHTML;
15398         //Roo.log(nodeName);
15399         
15400         switch(nodeName.toLowerCase()) {
15401             case 'th':
15402                 switch(className) {
15403                     case 'switch':
15404                         this.showMode(1);
15405                         break;
15406                     case 'prev':
15407                     case 'next':
15408                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15409                         switch(this.viewMode){
15410                                 case 0:
15411                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15412                                         break;
15413                                 case 1:
15414                                 case 2:
15415                                         this.viewDate = this.moveYear(this.viewDate, dir);
15416                                         break;
15417                         }
15418                         this.fill();
15419                         break;
15420                     case 'today':
15421                         var date = new Date();
15422                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15423 //                        this.fill()
15424                         this.setValue(this.formatDate(this.date));
15425                         
15426                         this.hide();
15427                         break;
15428                 }
15429                 break;
15430             case 'span':
15431                 if (className.indexOf('disabled') < 0) {
15432                     this.viewDate.setUTCDate(1);
15433                     if (className.indexOf('month') > -1) {
15434                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15435                     } else {
15436                         var year = parseInt(html, 10) || 0;
15437                         this.viewDate.setUTCFullYear(year);
15438                         
15439                     }
15440                     
15441                     if(this.singleMode){
15442                         this.setValue(this.formatDate(this.viewDate));
15443                         this.hide();
15444                         return;
15445                     }
15446                     
15447                     this.showMode(-1);
15448                     this.fill();
15449                 }
15450                 break;
15451                 
15452             case 'td':
15453                 //Roo.log(className);
15454                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15455                     var day = parseInt(html, 10) || 1;
15456                     var year = this.viewDate.getUTCFullYear(),
15457                         month = this.viewDate.getUTCMonth();
15458
15459                     if (className.indexOf('old') > -1) {
15460                         if(month === 0 ){
15461                             month = 11;
15462                             year -= 1;
15463                         }else{
15464                             month -= 1;
15465                         }
15466                     } else if (className.indexOf('new') > -1) {
15467                         if (month == 11) {
15468                             month = 0;
15469                             year += 1;
15470                         } else {
15471                             month += 1;
15472                         }
15473                     }
15474                     //Roo.log([year,month,day]);
15475                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15476                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15477 //                    this.fill();
15478                     //Roo.log(this.formatDate(this.date));
15479                     this.setValue(this.formatDate(this.date));
15480                     this.hide();
15481                 }
15482                 break;
15483         }
15484     },
15485     
15486     setStartDate: function(startDate)
15487     {
15488         this.startDate = startDate || -Infinity;
15489         if (this.startDate !== -Infinity) {
15490             this.startDate = this.parseDate(this.startDate);
15491         }
15492         this.update();
15493         this.updateNavArrows();
15494     },
15495
15496     setEndDate: function(endDate)
15497     {
15498         this.endDate = endDate || Infinity;
15499         if (this.endDate !== Infinity) {
15500             this.endDate = this.parseDate(this.endDate);
15501         }
15502         this.update();
15503         this.updateNavArrows();
15504     },
15505     
15506     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15507     {
15508         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15509         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15510             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15511         }
15512         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15513             return parseInt(d, 10);
15514         });
15515         this.update();
15516         this.updateNavArrows();
15517     },
15518     
15519     updateNavArrows: function() 
15520     {
15521         if(this.singleMode){
15522             return;
15523         }
15524         
15525         var d = new Date(this.viewDate),
15526         year = d.getUTCFullYear(),
15527         month = d.getUTCMonth();
15528         
15529         Roo.each(this.picker().select('.prev', true).elements, function(v){
15530             v.show();
15531             switch (this.viewMode) {
15532                 case 0:
15533
15534                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15535                         v.hide();
15536                     }
15537                     break;
15538                 case 1:
15539                 case 2:
15540                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15541                         v.hide();
15542                     }
15543                     break;
15544             }
15545         });
15546         
15547         Roo.each(this.picker().select('.next', true).elements, function(v){
15548             v.show();
15549             switch (this.viewMode) {
15550                 case 0:
15551
15552                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15553                         v.hide();
15554                     }
15555                     break;
15556                 case 1:
15557                 case 2:
15558                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15559                         v.hide();
15560                     }
15561                     break;
15562             }
15563         })
15564     },
15565     
15566     moveMonth: function(date, dir)
15567     {
15568         if (!dir) return date;
15569         var new_date = new Date(date.valueOf()),
15570         day = new_date.getUTCDate(),
15571         month = new_date.getUTCMonth(),
15572         mag = Math.abs(dir),
15573         new_month, test;
15574         dir = dir > 0 ? 1 : -1;
15575         if (mag == 1){
15576             test = dir == -1
15577             // If going back one month, make sure month is not current month
15578             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15579             ? function(){
15580                 return new_date.getUTCMonth() == month;
15581             }
15582             // If going forward one month, make sure month is as expected
15583             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15584             : function(){
15585                 return new_date.getUTCMonth() != new_month;
15586             };
15587             new_month = month + dir;
15588             new_date.setUTCMonth(new_month);
15589             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15590             if (new_month < 0 || new_month > 11)
15591                 new_month = (new_month + 12) % 12;
15592         } else {
15593             // For magnitudes >1, move one month at a time...
15594             for (var i=0; i<mag; i++)
15595                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15596                 new_date = this.moveMonth(new_date, dir);
15597             // ...then reset the day, keeping it in the new month
15598             new_month = new_date.getUTCMonth();
15599             new_date.setUTCDate(day);
15600             test = function(){
15601                 return new_month != new_date.getUTCMonth();
15602             };
15603         }
15604         // Common date-resetting loop -- if date is beyond end of month, make it
15605         // end of month
15606         while (test()){
15607             new_date.setUTCDate(--day);
15608             new_date.setUTCMonth(new_month);
15609         }
15610         return new_date;
15611     },
15612
15613     moveYear: function(date, dir)
15614     {
15615         return this.moveMonth(date, dir*12);
15616     },
15617
15618     dateWithinRange: function(date)
15619     {
15620         return date >= this.startDate && date <= this.endDate;
15621     },
15622
15623     
15624     remove: function() 
15625     {
15626         this.picker().remove();
15627     }
15628    
15629 });
15630
15631 Roo.apply(Roo.bootstrap.DateField,  {
15632     
15633     head : {
15634         tag: 'thead',
15635         cn: [
15636         {
15637             tag: 'tr',
15638             cn: [
15639             {
15640                 tag: 'th',
15641                 cls: 'prev',
15642                 html: '<i class="fa fa-arrow-left"/>'
15643             },
15644             {
15645                 tag: 'th',
15646                 cls: 'switch',
15647                 colspan: '5'
15648             },
15649             {
15650                 tag: 'th',
15651                 cls: 'next',
15652                 html: '<i class="fa fa-arrow-right"/>'
15653             }
15654
15655             ]
15656         }
15657         ]
15658     },
15659     
15660     content : {
15661         tag: 'tbody',
15662         cn: [
15663         {
15664             tag: 'tr',
15665             cn: [
15666             {
15667                 tag: 'td',
15668                 colspan: '7'
15669             }
15670             ]
15671         }
15672         ]
15673     },
15674     
15675     footer : {
15676         tag: 'tfoot',
15677         cn: [
15678         {
15679             tag: 'tr',
15680             cn: [
15681             {
15682                 tag: 'th',
15683                 colspan: '7',
15684                 cls: 'today'
15685             }
15686                     
15687             ]
15688         }
15689         ]
15690     },
15691     
15692     dates:{
15693         en: {
15694             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15695             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15696             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15697             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15698             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15699             today: "Today"
15700         }
15701     },
15702     
15703     modes: [
15704     {
15705         clsName: 'days',
15706         navFnc: 'Month',
15707         navStep: 1
15708     },
15709     {
15710         clsName: 'months',
15711         navFnc: 'FullYear',
15712         navStep: 1
15713     },
15714     {
15715         clsName: 'years',
15716         navFnc: 'FullYear',
15717         navStep: 10
15718     }]
15719 });
15720
15721 Roo.apply(Roo.bootstrap.DateField,  {
15722   
15723     template : {
15724         tag: 'div',
15725         cls: 'datepicker dropdown-menu roo-dynamic',
15726         cn: [
15727         {
15728             tag: 'div',
15729             cls: 'datepicker-days',
15730             cn: [
15731             {
15732                 tag: 'table',
15733                 cls: 'table-condensed',
15734                 cn:[
15735                 Roo.bootstrap.DateField.head,
15736                 {
15737                     tag: 'tbody'
15738                 },
15739                 Roo.bootstrap.DateField.footer
15740                 ]
15741             }
15742             ]
15743         },
15744         {
15745             tag: 'div',
15746             cls: 'datepicker-months',
15747             cn: [
15748             {
15749                 tag: 'table',
15750                 cls: 'table-condensed',
15751                 cn:[
15752                 Roo.bootstrap.DateField.head,
15753                 Roo.bootstrap.DateField.content,
15754                 Roo.bootstrap.DateField.footer
15755                 ]
15756             }
15757             ]
15758         },
15759         {
15760             tag: 'div',
15761             cls: 'datepicker-years',
15762             cn: [
15763             {
15764                 tag: 'table',
15765                 cls: 'table-condensed',
15766                 cn:[
15767                 Roo.bootstrap.DateField.head,
15768                 Roo.bootstrap.DateField.content,
15769                 Roo.bootstrap.DateField.footer
15770                 ]
15771             }
15772             ]
15773         }
15774         ]
15775     }
15776 });
15777
15778  
15779
15780  /*
15781  * - LGPL
15782  *
15783  * TimeField
15784  * 
15785  */
15786
15787 /**
15788  * @class Roo.bootstrap.TimeField
15789  * @extends Roo.bootstrap.Input
15790  * Bootstrap DateField class
15791  * 
15792  * 
15793  * @constructor
15794  * Create a new TimeField
15795  * @param {Object} config The config object
15796  */
15797
15798 Roo.bootstrap.TimeField = function(config){
15799     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15800     this.addEvents({
15801             /**
15802              * @event show
15803              * Fires when this field show.
15804              * @param {Roo.bootstrap.DateField} thisthis
15805              * @param {Mixed} date The date value
15806              */
15807             show : true,
15808             /**
15809              * @event show
15810              * Fires when this field hide.
15811              * @param {Roo.bootstrap.DateField} this
15812              * @param {Mixed} date The date value
15813              */
15814             hide : true,
15815             /**
15816              * @event select
15817              * Fires when select a date.
15818              * @param {Roo.bootstrap.DateField} this
15819              * @param {Mixed} date The date value
15820              */
15821             select : true
15822         });
15823 };
15824
15825 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15826     
15827     /**
15828      * @cfg {String} format
15829      * The default time format string which can be overriden for localization support.  The format must be
15830      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15831      */
15832     format : "H:i",
15833        
15834     onRender: function(ct, position)
15835     {
15836         
15837         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15838                 
15839         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15840         
15841         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15842         
15843         this.pop = this.picker().select('>.datepicker-time',true).first();
15844         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15845         
15846         this.picker().on('mousedown', this.onMousedown, this);
15847         this.picker().on('click', this.onClick, this);
15848         
15849         this.picker().addClass('datepicker-dropdown');
15850     
15851         this.fillTime();
15852         this.update();
15853             
15854         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15855         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15856         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15857         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15858         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15859         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15860
15861     },
15862     
15863     fireKey: function(e){
15864         if (!this.picker().isVisible()){
15865             if (e.keyCode == 27) { // allow escape to hide and re-show picker
15866                 this.show();
15867             }
15868             return;
15869         }
15870
15871         e.preventDefault();
15872         
15873         switch(e.keyCode){
15874             case 27: // escape
15875                 this.hide();
15876                 break;
15877             case 37: // left
15878             case 39: // right
15879                 this.onTogglePeriod();
15880                 break;
15881             case 38: // up
15882                 this.onIncrementMinutes();
15883                 break;
15884             case 40: // down
15885                 this.onDecrementMinutes();
15886                 break;
15887             case 13: // enter
15888             case 9: // tab
15889                 this.setTime();
15890                 break;
15891         }
15892     },
15893     
15894     onClick: function(e) {
15895         e.stopPropagation();
15896         e.preventDefault();
15897     },
15898     
15899     picker : function()
15900     {
15901         return this.el.select('.datepicker', true).first();
15902     },
15903     
15904     fillTime: function()
15905     {    
15906         var time = this.pop.select('tbody', true).first();
15907         
15908         time.dom.innerHTML = '';
15909         
15910         time.createChild({
15911             tag: 'tr',
15912             cn: [
15913                 {
15914                     tag: 'td',
15915                     cn: [
15916                         {
15917                             tag: 'a',
15918                             href: '#',
15919                             cls: 'btn',
15920                             cn: [
15921                                 {
15922                                     tag: 'span',
15923                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15924                                 }
15925                             ]
15926                         } 
15927                     ]
15928                 },
15929                 {
15930                     tag: 'td',
15931                     cls: 'separator'
15932                 },
15933                 {
15934                     tag: 'td',
15935                     cn: [
15936                         {
15937                             tag: 'a',
15938                             href: '#',
15939                             cls: 'btn',
15940                             cn: [
15941                                 {
15942                                     tag: 'span',
15943                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15944                                 }
15945                             ]
15946                         }
15947                     ]
15948                 },
15949                 {
15950                     tag: 'td',
15951                     cls: 'separator'
15952                 }
15953             ]
15954         });
15955         
15956         time.createChild({
15957             tag: 'tr',
15958             cn: [
15959                 {
15960                     tag: 'td',
15961                     cn: [
15962                         {
15963                             tag: 'span',
15964                             cls: 'timepicker-hour',
15965                             html: '00'
15966                         }  
15967                     ]
15968                 },
15969                 {
15970                     tag: 'td',
15971                     cls: 'separator',
15972                     html: ':'
15973                 },
15974                 {
15975                     tag: 'td',
15976                     cn: [
15977                         {
15978                             tag: 'span',
15979                             cls: 'timepicker-minute',
15980                             html: '00'
15981                         }  
15982                     ]
15983                 },
15984                 {
15985                     tag: 'td',
15986                     cls: 'separator'
15987                 },
15988                 {
15989                     tag: 'td',
15990                     cn: [
15991                         {
15992                             tag: 'button',
15993                             type: 'button',
15994                             cls: 'btn btn-primary period',
15995                             html: 'AM'
15996                             
15997                         }
15998                     ]
15999                 }
16000             ]
16001         });
16002         
16003         time.createChild({
16004             tag: 'tr',
16005             cn: [
16006                 {
16007                     tag: 'td',
16008                     cn: [
16009                         {
16010                             tag: 'a',
16011                             href: '#',
16012                             cls: 'btn',
16013                             cn: [
16014                                 {
16015                                     tag: 'span',
16016                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16017                                 }
16018                             ]
16019                         }
16020                     ]
16021                 },
16022                 {
16023                     tag: 'td',
16024                     cls: 'separator'
16025                 },
16026                 {
16027                     tag: 'td',
16028                     cn: [
16029                         {
16030                             tag: 'a',
16031                             href: '#',
16032                             cls: 'btn',
16033                             cn: [
16034                                 {
16035                                     tag: 'span',
16036                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16037                                 }
16038                             ]
16039                         }
16040                     ]
16041                 },
16042                 {
16043                     tag: 'td',
16044                     cls: 'separator'
16045                 }
16046             ]
16047         });
16048         
16049     },
16050     
16051     update: function()
16052     {
16053         
16054         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16055         
16056         this.fill();
16057     },
16058     
16059     fill: function() 
16060     {
16061         var hours = this.time.getHours();
16062         var minutes = this.time.getMinutes();
16063         var period = 'AM';
16064         
16065         if(hours > 11){
16066             period = 'PM';
16067         }
16068         
16069         if(hours == 0){
16070             hours = 12;
16071         }
16072         
16073         
16074         if(hours > 12){
16075             hours = hours - 12;
16076         }
16077         
16078         if(hours < 10){
16079             hours = '0' + hours;
16080         }
16081         
16082         if(minutes < 10){
16083             minutes = '0' + minutes;
16084         }
16085         
16086         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16087         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16088         this.pop.select('button', true).first().dom.innerHTML = period;
16089         
16090     },
16091     
16092     place: function()
16093     {   
16094         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16095         
16096         var cls = ['bottom'];
16097         
16098         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16099             cls.pop();
16100             cls.push('top');
16101         }
16102         
16103         cls.push('right');
16104         
16105         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16106             cls.pop();
16107             cls.push('left');
16108         }
16109         
16110         this.picker().addClass(cls.join('-'));
16111         
16112         var _this = this;
16113         
16114         Roo.each(cls, function(c){
16115             if(c == 'bottom'){
16116                 _this.picker().setTop(_this.inputEl().getHeight());
16117                 return;
16118             }
16119             if(c == 'top'){
16120                 _this.picker().setTop(0 - _this.picker().getHeight());
16121                 return;
16122             }
16123             
16124             if(c == 'left'){
16125                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16126                 return;
16127             }
16128             if(c == 'right'){
16129                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16130                 return;
16131             }
16132         });
16133         
16134     },
16135   
16136     onFocus : function()
16137     {
16138         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16139         this.show();
16140     },
16141     
16142     onBlur : function()
16143     {
16144         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16145         this.hide();
16146     },
16147     
16148     show : function()
16149     {
16150         this.picker().show();
16151         this.pop.show();
16152         this.update();
16153         this.place();
16154         
16155         this.fireEvent('show', this, this.date);
16156     },
16157     
16158     hide : function()
16159     {
16160         this.picker().hide();
16161         this.pop.hide();
16162         
16163         this.fireEvent('hide', this, this.date);
16164     },
16165     
16166     setTime : function()
16167     {
16168         this.hide();
16169         this.setValue(this.time.format(this.format));
16170         
16171         this.fireEvent('select', this, this.date);
16172         
16173         
16174     },
16175     
16176     onMousedown: function(e){
16177         e.stopPropagation();
16178         e.preventDefault();
16179     },
16180     
16181     onIncrementHours: function()
16182     {
16183         Roo.log('onIncrementHours');
16184         this.time = this.time.add(Date.HOUR, 1);
16185         this.update();
16186         
16187     },
16188     
16189     onDecrementHours: function()
16190     {
16191         Roo.log('onDecrementHours');
16192         this.time = this.time.add(Date.HOUR, -1);
16193         this.update();
16194     },
16195     
16196     onIncrementMinutes: function()
16197     {
16198         Roo.log('onIncrementMinutes');
16199         this.time = this.time.add(Date.MINUTE, 1);
16200         this.update();
16201     },
16202     
16203     onDecrementMinutes: function()
16204     {
16205         Roo.log('onDecrementMinutes');
16206         this.time = this.time.add(Date.MINUTE, -1);
16207         this.update();
16208     },
16209     
16210     onTogglePeriod: function()
16211     {
16212         Roo.log('onTogglePeriod');
16213         this.time = this.time.add(Date.HOUR, 12);
16214         this.update();
16215     }
16216     
16217    
16218 });
16219
16220 Roo.apply(Roo.bootstrap.TimeField,  {
16221     
16222     content : {
16223         tag: 'tbody',
16224         cn: [
16225             {
16226                 tag: 'tr',
16227                 cn: [
16228                 {
16229                     tag: 'td',
16230                     colspan: '7'
16231                 }
16232                 ]
16233             }
16234         ]
16235     },
16236     
16237     footer : {
16238         tag: 'tfoot',
16239         cn: [
16240             {
16241                 tag: 'tr',
16242                 cn: [
16243                 {
16244                     tag: 'th',
16245                     colspan: '7',
16246                     cls: '',
16247                     cn: [
16248                         {
16249                             tag: 'button',
16250                             cls: 'btn btn-info ok',
16251                             html: 'OK'
16252                         }
16253                     ]
16254                 }
16255
16256                 ]
16257             }
16258         ]
16259     }
16260 });
16261
16262 Roo.apply(Roo.bootstrap.TimeField,  {
16263   
16264     template : {
16265         tag: 'div',
16266         cls: 'datepicker dropdown-menu',
16267         cn: [
16268             {
16269                 tag: 'div',
16270                 cls: 'datepicker-time',
16271                 cn: [
16272                 {
16273                     tag: 'table',
16274                     cls: 'table-condensed',
16275                     cn:[
16276                     Roo.bootstrap.TimeField.content,
16277                     Roo.bootstrap.TimeField.footer
16278                     ]
16279                 }
16280                 ]
16281             }
16282         ]
16283     }
16284 });
16285
16286  
16287
16288  /*
16289  * - LGPL
16290  *
16291  * MonthField
16292  * 
16293  */
16294
16295 /**
16296  * @class Roo.bootstrap.MonthField
16297  * @extends Roo.bootstrap.Input
16298  * Bootstrap MonthField class
16299  * 
16300  * @cfg {String} language default en
16301  * 
16302  * @constructor
16303  * Create a new MonthField
16304  * @param {Object} config The config object
16305  */
16306
16307 Roo.bootstrap.MonthField = function(config){
16308     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16309     
16310     this.addEvents({
16311         /**
16312          * @event show
16313          * Fires when this field show.
16314          * @param {Roo.bootstrap.MonthField} this
16315          * @param {Mixed} date The date value
16316          */
16317         show : true,
16318         /**
16319          * @event show
16320          * Fires when this field hide.
16321          * @param {Roo.bootstrap.MonthField} this
16322          * @param {Mixed} date The date value
16323          */
16324         hide : true,
16325         /**
16326          * @event select
16327          * Fires when select a date.
16328          * @param {Roo.bootstrap.MonthField} this
16329          * @param {String} oldvalue The old value
16330          * @param {String} newvalue The new value
16331          */
16332         select : true
16333     });
16334 };
16335
16336 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16337     
16338     onRender: function(ct, position)
16339     {
16340         
16341         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16342         
16343         this.language = this.language || 'en';
16344         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16345         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16346         
16347         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16348         this.isInline = false;
16349         this.isInput = true;
16350         this.component = this.el.select('.add-on', true).first() || false;
16351         this.component = (this.component && this.component.length === 0) ? false : this.component;
16352         this.hasInput = this.component && this.inputEL().length;
16353         
16354         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16355         
16356         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16357         
16358         this.picker().on('mousedown', this.onMousedown, this);
16359         this.picker().on('click', this.onClick, this);
16360         
16361         this.picker().addClass('datepicker-dropdown');
16362         
16363         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16364             v.setStyle('width', '189px');
16365         });
16366         
16367         this.fillMonths();
16368         
16369         this.update();
16370         
16371         if(this.isInline) {
16372             this.show();
16373         }
16374         
16375     },
16376     
16377     setValue: function(v, suppressEvent)
16378     {   
16379         var o = this.getValue();
16380         
16381         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16382         
16383         this.update();
16384
16385         if(suppressEvent !== true){
16386             this.fireEvent('select', this, o, v);
16387         }
16388         
16389     },
16390     
16391     getValue: function()
16392     {
16393         return this.value;
16394     },
16395     
16396     onClick: function(e) 
16397     {
16398         e.stopPropagation();
16399         e.preventDefault();
16400         
16401         var target = e.getTarget();
16402         
16403         if(target.nodeName.toLowerCase() === 'i'){
16404             target = Roo.get(target).dom.parentNode;
16405         }
16406         
16407         var nodeName = target.nodeName;
16408         var className = target.className;
16409         var html = target.innerHTML;
16410         
16411         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16412             return;
16413         }
16414         
16415         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16416         
16417         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16418         
16419         this.hide();
16420                         
16421     },
16422     
16423     picker : function()
16424     {
16425         return this.pickerEl;
16426     },
16427     
16428     fillMonths: function()
16429     {    
16430         var i = 0;
16431         var months = this.picker().select('>.datepicker-months td', true).first();
16432         
16433         months.dom.innerHTML = '';
16434         
16435         while (i < 12) {
16436             var month = {
16437                 tag: 'span',
16438                 cls: 'month',
16439                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16440             }
16441             
16442             months.createChild(month);
16443         }
16444         
16445     },
16446     
16447     update: function()
16448     {
16449         var _this = this;
16450         
16451         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16452             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16453         }
16454         
16455         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16456             e.removeClass('active');
16457             
16458             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16459                 e.addClass('active');
16460             }
16461         })
16462     },
16463     
16464     place: function()
16465     {
16466         if(this.isInline) return;
16467         
16468         this.picker().removeClass(['bottom', 'top']);
16469         
16470         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16471             /*
16472              * place to the top of element!
16473              *
16474              */
16475             
16476             this.picker().addClass('top');
16477             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16478             
16479             return;
16480         }
16481         
16482         this.picker().addClass('bottom');
16483         
16484         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16485     },
16486     
16487     onFocus : function()
16488     {
16489         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16490         this.show();
16491     },
16492     
16493     onBlur : function()
16494     {
16495         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16496         
16497         var d = this.inputEl().getValue();
16498         
16499         this.setValue(d);
16500                 
16501         this.hide();
16502     },
16503     
16504     show : function()
16505     {
16506         this.picker().show();
16507         this.picker().select('>.datepicker-months', true).first().show();
16508         this.update();
16509         this.place();
16510         
16511         this.fireEvent('show', this, this.date);
16512     },
16513     
16514     hide : function()
16515     {
16516         if(this.isInline) return;
16517         this.picker().hide();
16518         this.fireEvent('hide', this, this.date);
16519         
16520     },
16521     
16522     onMousedown: function(e)
16523     {
16524         e.stopPropagation();
16525         e.preventDefault();
16526     },
16527     
16528     keyup: function(e)
16529     {
16530         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16531         this.update();
16532     },
16533
16534     fireKey: function(e)
16535     {
16536         if (!this.picker().isVisible()){
16537             if (e.keyCode == 27) // allow escape to hide and re-show picker
16538                 this.show();
16539             return;
16540         }
16541         
16542         var dir;
16543         
16544         switch(e.keyCode){
16545             case 27: // escape
16546                 this.hide();
16547                 e.preventDefault();
16548                 break;
16549             case 37: // left
16550             case 39: // right
16551                 dir = e.keyCode == 37 ? -1 : 1;
16552                 
16553                 this.vIndex = this.vIndex + dir;
16554                 
16555                 if(this.vIndex < 0){
16556                     this.vIndex = 0;
16557                 }
16558                 
16559                 if(this.vIndex > 11){
16560                     this.vIndex = 11;
16561                 }
16562                 
16563                 if(isNaN(this.vIndex)){
16564                     this.vIndex = 0;
16565                 }
16566                 
16567                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16568                 
16569                 break;
16570             case 38: // up
16571             case 40: // down
16572                 
16573                 dir = e.keyCode == 38 ? -1 : 1;
16574                 
16575                 this.vIndex = this.vIndex + dir * 4;
16576                 
16577                 if(this.vIndex < 0){
16578                     this.vIndex = 0;
16579                 }
16580                 
16581                 if(this.vIndex > 11){
16582                     this.vIndex = 11;
16583                 }
16584                 
16585                 if(isNaN(this.vIndex)){
16586                     this.vIndex = 0;
16587                 }
16588                 
16589                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16590                 break;
16591                 
16592             case 13: // enter
16593                 
16594                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16595                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16596                 }
16597                 
16598                 this.hide();
16599                 e.preventDefault();
16600                 break;
16601             case 9: // tab
16602                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16603                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16604                 }
16605                 this.hide();
16606                 break;
16607             case 16: // shift
16608             case 17: // ctrl
16609             case 18: // alt
16610                 break;
16611             default :
16612                 this.hide();
16613                 
16614         }
16615     },
16616     
16617     remove: function() 
16618     {
16619         this.picker().remove();
16620     }
16621    
16622 });
16623
16624 Roo.apply(Roo.bootstrap.MonthField,  {
16625     
16626     content : {
16627         tag: 'tbody',
16628         cn: [
16629         {
16630             tag: 'tr',
16631             cn: [
16632             {
16633                 tag: 'td',
16634                 colspan: '7'
16635             }
16636             ]
16637         }
16638         ]
16639     },
16640     
16641     dates:{
16642         en: {
16643             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16644             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16645         }
16646     }
16647 });
16648
16649 Roo.apply(Roo.bootstrap.MonthField,  {
16650   
16651     template : {
16652         tag: 'div',
16653         cls: 'datepicker dropdown-menu roo-dynamic',
16654         cn: [
16655             {
16656                 tag: 'div',
16657                 cls: 'datepicker-months',
16658                 cn: [
16659                 {
16660                     tag: 'table',
16661                     cls: 'table-condensed',
16662                     cn:[
16663                         Roo.bootstrap.DateField.content
16664                     ]
16665                 }
16666                 ]
16667             }
16668         ]
16669     }
16670 });
16671
16672  
16673
16674  
16675  /*
16676  * - LGPL
16677  *
16678  * CheckBox
16679  * 
16680  */
16681
16682 /**
16683  * @class Roo.bootstrap.CheckBox
16684  * @extends Roo.bootstrap.Input
16685  * Bootstrap CheckBox class
16686  * 
16687  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16688  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16689  * @cfg {String} boxLabel The text that appears beside the checkbox
16690  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16691  * @cfg {Boolean} checked initnal the element
16692  * @cfg {Boolean} inline inline the element (default false)
16693  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16694  * 
16695  * @constructor
16696  * Create a new CheckBox
16697  * @param {Object} config The config object
16698  */
16699
16700 Roo.bootstrap.CheckBox = function(config){
16701     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16702    
16703     this.addEvents({
16704         /**
16705         * @event check
16706         * Fires when the element is checked or unchecked.
16707         * @param {Roo.bootstrap.CheckBox} this This input
16708         * @param {Boolean} checked The new checked value
16709         */
16710        check : true
16711     });
16712     
16713 };
16714
16715 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16716   
16717     inputType: 'checkbox',
16718     inputValue: 1,
16719     valueOff: 0,
16720     boxLabel: false,
16721     checked: false,
16722     weight : false,
16723     inline: false,
16724     
16725     getAutoCreate : function()
16726     {
16727         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16728         
16729         var id = Roo.id();
16730         
16731         var cfg = {};
16732         
16733         cfg.cls = 'form-group ' + this.inputType; //input-group
16734         
16735         if(this.inline){
16736             cfg.cls += ' ' + this.inputType + '-inline';
16737         }
16738         
16739         var input =  {
16740             tag: 'input',
16741             id : id,
16742             type : this.inputType,
16743             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16744             cls : 'roo-' + this.inputType, //'form-box',
16745             placeholder : this.placeholder || ''
16746             
16747         };
16748         
16749         if (this.weight) { // Validity check?
16750             cfg.cls += " " + this.inputType + "-" + this.weight;
16751         }
16752         
16753         if (this.disabled) {
16754             input.disabled=true;
16755         }
16756         
16757         if(this.checked){
16758             input.checked = this.checked;
16759         }
16760         
16761         if (this.name) {
16762             input.name = this.name;
16763         }
16764         
16765         if (this.size) {
16766             input.cls += ' input-' + this.size;
16767         }
16768         
16769         var settings=this;
16770         
16771         ['xs','sm','md','lg'].map(function(size){
16772             if (settings[size]) {
16773                 cfg.cls += ' col-' + size + '-' + settings[size];
16774             }
16775         });
16776         
16777         var inputblock = input;
16778          
16779         if (this.before || this.after) {
16780             
16781             inputblock = {
16782                 cls : 'input-group',
16783                 cn :  [] 
16784             };
16785             
16786             if (this.before) {
16787                 inputblock.cn.push({
16788                     tag :'span',
16789                     cls : 'input-group-addon',
16790                     html : this.before
16791                 });
16792             }
16793             
16794             inputblock.cn.push(input);
16795             
16796             if (this.after) {
16797                 inputblock.cn.push({
16798                     tag :'span',
16799                     cls : 'input-group-addon',
16800                     html : this.after
16801                 });
16802             }
16803             
16804         }
16805         
16806         if (align ==='left' && this.fieldLabel.length) {
16807                 Roo.log("left and has label");
16808                 cfg.cn = [
16809                     
16810                     {
16811                         tag: 'label',
16812                         'for' :  id,
16813                         cls : 'control-label col-md-' + this.labelWidth,
16814                         html : this.fieldLabel
16815                         
16816                     },
16817                     {
16818                         cls : "col-md-" + (12 - this.labelWidth), 
16819                         cn: [
16820                             inputblock
16821                         ]
16822                     }
16823                     
16824                 ];
16825         } else if ( this.fieldLabel.length) {
16826                 Roo.log(" label");
16827                 cfg.cn = [
16828                    
16829                     {
16830                         tag: this.boxLabel ? 'span' : 'label',
16831                         'for': id,
16832                         cls: 'control-label box-input-label',
16833                         //cls : 'input-group-addon',
16834                         html : this.fieldLabel
16835                         
16836                     },
16837                     
16838                     inputblock
16839                     
16840                 ];
16841
16842         } else {
16843             
16844                 Roo.log(" no label && no align");
16845                 cfg.cn = [  inputblock ] ;
16846                 
16847                 
16848         }
16849         if(this.boxLabel){
16850              var boxLabelCfg = {
16851                 tag: 'label',
16852                 //'for': id, // box label is handled by onclick - so no for...
16853                 cls: 'box-label',
16854                 html: this.boxLabel
16855             }
16856             
16857             if(this.tooltip){
16858                 boxLabelCfg.tooltip = this.tooltip;
16859             }
16860              
16861             cfg.cn.push(boxLabelCfg);
16862         }
16863         
16864         
16865        
16866         return cfg;
16867         
16868     },
16869     
16870     /**
16871      * return the real input element.
16872      */
16873     inputEl: function ()
16874     {
16875         return this.el.select('input.roo-' + this.inputType,true).first();
16876     },
16877     
16878     labelEl: function()
16879     {
16880         return this.el.select('label.control-label',true).first();
16881     },
16882     /* depricated... */
16883     
16884     label: function()
16885     {
16886         return this.labelEl();
16887     },
16888     
16889     initEvents : function()
16890     {
16891 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16892         
16893         this.inputEl().on('click', this.onClick,  this);
16894         
16895         if (this.boxLabel) { 
16896             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
16897         }
16898         
16899         this.startValue = this.getValue();
16900         
16901         if(this.groupId){
16902             Roo.bootstrap.CheckBox.register(this);
16903         }
16904     },
16905     
16906     onClick : function()
16907     {   
16908         this.setChecked(!this.checked);
16909     },
16910     
16911     setChecked : function(state,suppressEvent)
16912     {
16913         this.startValue = this.getValue();
16914         
16915         if(this.inputType == 'radio'){
16916             
16917             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16918                 e.dom.checked = false;
16919             });
16920             
16921             this.inputEl().dom.checked = true;
16922             
16923             this.inputEl().dom.value = this.inputValue;
16924             
16925             if(suppressEvent !== true){
16926                 this.fireEvent('check', this, true);
16927             }
16928             
16929             this.validate();
16930             
16931             return;
16932         }
16933         
16934         this.checked = state;
16935         
16936         this.inputEl().dom.checked = state;
16937         
16938         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16939         
16940         if(suppressEvent !== true){
16941             this.fireEvent('check', this, state);
16942         }
16943         
16944         this.validate();
16945     },
16946     
16947     getValue : function()
16948     {
16949         if(this.inputType == 'radio'){
16950             return this.getGroupValue();
16951         }
16952         
16953         return this.inputEl().getValue();
16954         
16955     },
16956     
16957     getGroupValue : function()
16958     {
16959         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16960             return '';
16961         }
16962         
16963         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16964     },
16965     
16966     setValue : function(v,suppressEvent)
16967     {
16968         if(this.inputType == 'radio'){
16969             this.setGroupValue(v, suppressEvent);
16970             return;
16971         }
16972         
16973         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16974         
16975         this.validate();
16976     },
16977     
16978     setGroupValue : function(v, suppressEvent)
16979     {
16980         this.startValue = this.getValue();
16981         
16982         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16983             e.dom.checked = false;
16984             
16985             if(e.dom.value == v){
16986                 e.dom.checked = true;
16987             }
16988         });
16989         
16990         if(suppressEvent !== true){
16991             this.fireEvent('check', this, true);
16992         }
16993
16994         this.validate();
16995         
16996         return;
16997     },
16998     
16999     validate : function()
17000     {
17001         if(
17002                 this.disabled || 
17003                 (this.inputType == 'radio' && this.validateRadio()) ||
17004                 (this.inputType == 'checkbox' && this.validateCheckbox())
17005         ){
17006             this.markValid();
17007             return true;
17008         }
17009         
17010         this.markInvalid();
17011         return false;
17012     },
17013     
17014     validateRadio : function()
17015     {
17016         var valid = false;
17017         
17018         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17019             if(!e.dom.checked){
17020                 return;
17021             }
17022             
17023             valid = true;
17024             
17025             return false;
17026         });
17027         
17028         return valid;
17029     },
17030     
17031     validateCheckbox : function()
17032     {
17033         if(!this.groupId){
17034             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17035         }
17036         
17037         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17038         
17039         if(!group){
17040             return false;
17041         }
17042         
17043         var r = false;
17044         
17045         for(var i in group){
17046             if(r){
17047                 break;
17048             }
17049             
17050             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17051         }
17052         
17053         return r;
17054     },
17055     
17056     /**
17057      * Mark this field as valid
17058      */
17059     markValid : function()
17060     {
17061         var _this = this;
17062         
17063         this.fireEvent('valid', this);
17064         
17065         if(this.inputType == 'radio'){
17066             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17067                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17068                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17069             });
17070             
17071             return;
17072         }
17073         
17074         if(!this.groupId){
17075             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17076             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17077             return;
17078         }
17079         
17080         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17081             
17082         if(!group){
17083             return;
17084         }
17085         
17086         for(var i in group){
17087             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17088             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17089         }
17090     },
17091     
17092      /**
17093      * Mark this field as invalid
17094      * @param {String} msg The validation message
17095      */
17096     markInvalid : function(msg)
17097     {
17098         var _this = this;
17099         
17100         this.fireEvent('invalid', this, msg);
17101         
17102         if(this.inputType == 'radio'){
17103             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17104                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17105                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17106             });
17107             
17108             return;
17109         }
17110         
17111         if(!this.groupId){
17112             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17113             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17114             return;
17115         }
17116         
17117         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17118             
17119         if(!group){
17120             return;
17121         }
17122         
17123         for(var i in group){
17124             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17125             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17126         }
17127         
17128     }
17129     
17130 });
17131
17132 Roo.apply(Roo.bootstrap.CheckBox, {
17133     
17134     groups: {},
17135     
17136      /**
17137     * register a CheckBox Group
17138     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17139     */
17140     register : function(checkbox)
17141     {
17142         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17143             this.groups[checkbox.groupId] = {};
17144         }
17145         
17146         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17147             return;
17148         }
17149         
17150         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17151         
17152     },
17153     /**
17154     * fetch a CheckBox Group based on the group ID
17155     * @param {string} the group ID
17156     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17157     */
17158     get: function(groupId) {
17159         if (typeof(this.groups[groupId]) == 'undefined') {
17160             return false;
17161         }
17162         
17163         return this.groups[groupId] ;
17164     }
17165     
17166     
17167 });
17168 /*
17169  * - LGPL
17170  *
17171  * Radio
17172  *
17173  *
17174  * not inline
17175  *<div class="radio">
17176   <label>
17177     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17178     Option one is this and that&mdash;be sure to include why it's great
17179   </label>
17180 </div>
17181  *
17182  *
17183  *inline
17184  *<span>
17185  *<label class="radio-inline">fieldLabel</label>
17186  *<label class="radio-inline">
17187   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17188 </label>
17189 <span>
17190  * 
17191  * 
17192  */
17193
17194 /**
17195  * @class Roo.bootstrap.Radio
17196  * @extends Roo.bootstrap.CheckBox
17197  * Bootstrap Radio class
17198
17199  * @constructor
17200  * Create a new Radio
17201  * @param {Object} config The config object
17202  */
17203
17204 Roo.bootstrap.Radio = function(config){
17205     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17206    
17207 };
17208
17209 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17210     
17211     inputType: 'radio',
17212     inputValue: '',
17213     valueOff: '',
17214     
17215     getAutoCreate : function()
17216     {
17217         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17218         align = align || 'left'; // default...
17219         
17220         
17221         
17222         var id = Roo.id();
17223         
17224         var cfg = {
17225                 tag : this.inline ? 'span' : 'div',
17226                 cls : '',
17227                 cn : []
17228         };
17229         
17230         var inline = this.inline ? ' radio-inline' : '';
17231         
17232         var lbl = {
17233                 tag: 'label' ,
17234                 // does not need for, as we wrap the input with it..
17235                 'for' : id,
17236                 cls : 'control-label box-label' + inline,
17237                 cn : []
17238         };
17239         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17240         
17241         var fieldLabel = {
17242             tag: 'label' ,
17243             //cls : 'control-label' + inline,
17244             html : this.fieldLabel,
17245             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17246         };
17247         
17248  
17249         
17250         
17251         var input =  {
17252             tag: 'input',
17253             id : id,
17254             type : this.inputType,
17255             //value : (!this.checked) ? this.valueOff : this.inputValue,
17256             value : this.inputValue,
17257             cls : 'roo-radio',
17258             placeholder : this.placeholder || '' // ?? needed????
17259             
17260         };
17261         if (this.weight) { // Validity check?
17262             input.cls += " radio-" + this.weight;
17263         }
17264         if (this.disabled) {
17265             input.disabled=true;
17266         }
17267         
17268         if(this.checked){
17269             input.checked = this.checked;
17270         }
17271         
17272         if (this.name) {
17273             input.name = this.name;
17274         }
17275         
17276         if (this.size) {
17277             input.cls += ' input-' + this.size;
17278         }
17279         
17280         //?? can span's inline have a width??
17281         
17282         var settings=this;
17283         ['xs','sm','md','lg'].map(function(size){
17284             if (settings[size]) {
17285                 cfg.cls += ' col-' + size + '-' + settings[size];
17286             }
17287         });
17288         
17289         var inputblock = input;
17290         
17291         if (this.before || this.after) {
17292             
17293             inputblock = {
17294                 cls : 'input-group',
17295                 tag : 'span',
17296                 cn :  [] 
17297             };
17298             if (this.before) {
17299                 inputblock.cn.push({
17300                     tag :'span',
17301                     cls : 'input-group-addon',
17302                     html : this.before
17303                 });
17304             }
17305             inputblock.cn.push(input);
17306             if (this.after) {
17307                 inputblock.cn.push({
17308                     tag :'span',
17309                     cls : 'input-group-addon',
17310                     html : this.after
17311                 });
17312             }
17313             
17314         };
17315         
17316         
17317         if (this.fieldLabel && this.fieldLabel.length) {
17318             cfg.cn.push(fieldLabel);
17319         }
17320        
17321         // normal bootstrap puts the input inside the label.
17322         // however with our styled version - it has to go after the input.
17323        
17324         //lbl.cn.push(inputblock);
17325         
17326         var lblwrap =  {
17327             tag: 'span',
17328             cls: 'radio' + inline,
17329             cn: [
17330                 inputblock,
17331                 lbl
17332             ]
17333         };
17334         
17335         cfg.cn.push( lblwrap);
17336         
17337         if(this.boxLabel){
17338             lbl.cn.push({
17339                 tag: 'span',
17340                 html: this.boxLabel
17341             })
17342         }
17343          
17344         
17345         return cfg;
17346         
17347     },
17348     
17349     initEvents : function()
17350     {
17351 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17352         
17353         this.inputEl().on('click', this.onClick,  this);
17354         if (this.boxLabel) {
17355             Roo.log('find label')
17356             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17357         }
17358         
17359     },
17360     
17361     inputEl: function ()
17362     {
17363         return this.el.select('input.roo-radio',true).first();
17364     },
17365     onClick : function()
17366     {   
17367         Roo.log("click");
17368         this.setChecked(true);
17369     },
17370     
17371     setChecked : function(state,suppressEvent)
17372     {
17373         if(state){
17374             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17375                 v.dom.checked = false;
17376             });
17377         }
17378         Roo.log(this.inputEl().dom);
17379         this.checked = state;
17380         this.inputEl().dom.checked = state;
17381         
17382         if(suppressEvent !== true){
17383             this.fireEvent('check', this, state);
17384         }
17385         
17386         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17387         
17388     },
17389     
17390     getGroupValue : function()
17391     {
17392         var value = '';
17393         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17394             if(v.dom.checked == true){
17395                 value = v.dom.value;
17396             }
17397         });
17398         
17399         return value;
17400     },
17401     
17402     /**
17403      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17404      * @return {Mixed} value The field value
17405      */
17406     getValue : function(){
17407         return this.getGroupValue();
17408     }
17409     
17410 });
17411
17412  
17413 //<script type="text/javascript">
17414
17415 /*
17416  * Based  Ext JS Library 1.1.1
17417  * Copyright(c) 2006-2007, Ext JS, LLC.
17418  * LGPL
17419  *
17420  */
17421  
17422 /**
17423  * @class Roo.HtmlEditorCore
17424  * @extends Roo.Component
17425  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17426  *
17427  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17428  */
17429
17430 Roo.HtmlEditorCore = function(config){
17431     
17432     
17433     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17434     
17435     
17436     this.addEvents({
17437         /**
17438          * @event initialize
17439          * Fires when the editor is fully initialized (including the iframe)
17440          * @param {Roo.HtmlEditorCore} this
17441          */
17442         initialize: true,
17443         /**
17444          * @event activate
17445          * Fires when the editor is first receives the focus. Any insertion must wait
17446          * until after this event.
17447          * @param {Roo.HtmlEditorCore} this
17448          */
17449         activate: true,
17450          /**
17451          * @event beforesync
17452          * Fires before the textarea is updated with content from the editor iframe. Return false
17453          * to cancel the sync.
17454          * @param {Roo.HtmlEditorCore} this
17455          * @param {String} html
17456          */
17457         beforesync: true,
17458          /**
17459          * @event beforepush
17460          * Fires before the iframe editor is updated with content from the textarea. Return false
17461          * to cancel the push.
17462          * @param {Roo.HtmlEditorCore} this
17463          * @param {String} html
17464          */
17465         beforepush: true,
17466          /**
17467          * @event sync
17468          * Fires when the textarea is updated with content from the editor iframe.
17469          * @param {Roo.HtmlEditorCore} this
17470          * @param {String} html
17471          */
17472         sync: true,
17473          /**
17474          * @event push
17475          * Fires when the iframe editor is updated with content from the textarea.
17476          * @param {Roo.HtmlEditorCore} this
17477          * @param {String} html
17478          */
17479         push: true,
17480         
17481         /**
17482          * @event editorevent
17483          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17484          * @param {Roo.HtmlEditorCore} this
17485          */
17486         editorevent: true
17487         
17488     });
17489     
17490     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17491     
17492     // defaults : white / black...
17493     this.applyBlacklists();
17494     
17495     
17496     
17497 };
17498
17499
17500 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17501
17502
17503      /**
17504      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17505      */
17506     
17507     owner : false,
17508     
17509      /**
17510      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17511      *                        Roo.resizable.
17512      */
17513     resizable : false,
17514      /**
17515      * @cfg {Number} height (in pixels)
17516      */   
17517     height: 300,
17518    /**
17519      * @cfg {Number} width (in pixels)
17520      */   
17521     width: 500,
17522     
17523     /**
17524      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17525      * 
17526      */
17527     stylesheets: false,
17528     
17529     // id of frame..
17530     frameId: false,
17531     
17532     // private properties
17533     validationEvent : false,
17534     deferHeight: true,
17535     initialized : false,
17536     activated : false,
17537     sourceEditMode : false,
17538     onFocus : Roo.emptyFn,
17539     iframePad:3,
17540     hideMode:'offsets',
17541     
17542     clearUp: true,
17543     
17544     // blacklist + whitelisted elements..
17545     black: false,
17546     white: false,
17547      
17548     
17549
17550     /**
17551      * Protected method that will not generally be called directly. It
17552      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17553      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17554      */
17555     getDocMarkup : function(){
17556         // body styles..
17557         var st = '';
17558         
17559         // inherit styels from page...?? 
17560         if (this.stylesheets === false) {
17561             
17562             Roo.get(document.head).select('style').each(function(node) {
17563                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17564             });
17565             
17566             Roo.get(document.head).select('link').each(function(node) { 
17567                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17568             });
17569             
17570         } else if (!this.stylesheets.length) {
17571                 // simple..
17572                 st = '<style type="text/css">' +
17573                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17574                    '</style>';
17575         } else { 
17576             
17577         }
17578         
17579         st +=  '<style type="text/css">' +
17580             'IMG { cursor: pointer } ' +
17581         '</style>';
17582
17583         
17584         return '<html><head>' + st  +
17585             //<style type="text/css">' +
17586             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17587             //'</style>' +
17588             ' </head><body class="roo-htmleditor-body"></body></html>';
17589     },
17590
17591     // private
17592     onRender : function(ct, position)
17593     {
17594         var _t = this;
17595         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17596         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17597         
17598         
17599         this.el.dom.style.border = '0 none';
17600         this.el.dom.setAttribute('tabIndex', -1);
17601         this.el.addClass('x-hidden hide');
17602         
17603         
17604         
17605         if(Roo.isIE){ // fix IE 1px bogus margin
17606             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17607         }
17608        
17609         
17610         this.frameId = Roo.id();
17611         
17612          
17613         
17614         var iframe = this.owner.wrap.createChild({
17615             tag: 'iframe',
17616             cls: 'form-control', // bootstrap..
17617             id: this.frameId,
17618             name: this.frameId,
17619             frameBorder : 'no',
17620             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17621         }, this.el
17622         );
17623         
17624         
17625         this.iframe = iframe.dom;
17626
17627          this.assignDocWin();
17628         
17629         this.doc.designMode = 'on';
17630        
17631         this.doc.open();
17632         this.doc.write(this.getDocMarkup());
17633         this.doc.close();
17634
17635         
17636         var task = { // must defer to wait for browser to be ready
17637             run : function(){
17638                 //console.log("run task?" + this.doc.readyState);
17639                 this.assignDocWin();
17640                 if(this.doc.body || this.doc.readyState == 'complete'){
17641                     try {
17642                         this.doc.designMode="on";
17643                     } catch (e) {
17644                         return;
17645                     }
17646                     Roo.TaskMgr.stop(task);
17647                     this.initEditor.defer(10, this);
17648                 }
17649             },
17650             interval : 10,
17651             duration: 10000,
17652             scope: this
17653         };
17654         Roo.TaskMgr.start(task);
17655
17656     },
17657
17658     // private
17659     onResize : function(w, h)
17660     {
17661          Roo.log('resize: ' +w + ',' + h );
17662         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17663         if(!this.iframe){
17664             return;
17665         }
17666         if(typeof w == 'number'){
17667             
17668             this.iframe.style.width = w + 'px';
17669         }
17670         if(typeof h == 'number'){
17671             
17672             this.iframe.style.height = h + 'px';
17673             if(this.doc){
17674                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17675             }
17676         }
17677         
17678     },
17679
17680     /**
17681      * Toggles the editor between standard and source edit mode.
17682      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17683      */
17684     toggleSourceEdit : function(sourceEditMode){
17685         
17686         this.sourceEditMode = sourceEditMode === true;
17687         
17688         if(this.sourceEditMode){
17689  
17690             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17691             
17692         }else{
17693             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17694             //this.iframe.className = '';
17695             this.deferFocus();
17696         }
17697         //this.setSize(this.owner.wrap.getSize());
17698         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17699     },
17700
17701     
17702   
17703
17704     /**
17705      * Protected method that will not generally be called directly. If you need/want
17706      * custom HTML cleanup, this is the method you should override.
17707      * @param {String} html The HTML to be cleaned
17708      * return {String} The cleaned HTML
17709      */
17710     cleanHtml : function(html){
17711         html = String(html);
17712         if(html.length > 5){
17713             if(Roo.isSafari){ // strip safari nonsense
17714                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17715             }
17716         }
17717         if(html == '&nbsp;'){
17718             html = '';
17719         }
17720         return html;
17721     },
17722
17723     /**
17724      * HTML Editor -> Textarea
17725      * Protected method that will not generally be called directly. Syncs the contents
17726      * of the editor iframe with the textarea.
17727      */
17728     syncValue : function(){
17729         if(this.initialized){
17730             var bd = (this.doc.body || this.doc.documentElement);
17731             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17732             var html = bd.innerHTML;
17733             if(Roo.isSafari){
17734                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17735                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17736                 if(m && m[1]){
17737                     html = '<div style="'+m[0]+'">' + html + '</div>';
17738                 }
17739             }
17740             html = this.cleanHtml(html);
17741             // fix up the special chars.. normaly like back quotes in word...
17742             // however we do not want to do this with chinese..
17743             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17744                 var cc = b.charCodeAt();
17745                 if (
17746                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17747                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17748                     (cc >= 0xf900 && cc < 0xfb00 )
17749                 ) {
17750                         return b;
17751                 }
17752                 return "&#"+cc+";" 
17753             });
17754             if(this.owner.fireEvent('beforesync', this, html) !== false){
17755                 this.el.dom.value = html;
17756                 this.owner.fireEvent('sync', this, html);
17757             }
17758         }
17759     },
17760
17761     /**
17762      * Protected method that will not generally be called directly. Pushes the value of the textarea
17763      * into the iframe editor.
17764      */
17765     pushValue : function(){
17766         if(this.initialized){
17767             var v = this.el.dom.value.trim();
17768             
17769 //            if(v.length < 1){
17770 //                v = '&#160;';
17771 //            }
17772             
17773             if(this.owner.fireEvent('beforepush', this, v) !== false){
17774                 var d = (this.doc.body || this.doc.documentElement);
17775                 d.innerHTML = v;
17776                 this.cleanUpPaste();
17777                 this.el.dom.value = d.innerHTML;
17778                 this.owner.fireEvent('push', this, v);
17779             }
17780         }
17781     },
17782
17783     // private
17784     deferFocus : function(){
17785         this.focus.defer(10, this);
17786     },
17787
17788     // doc'ed in Field
17789     focus : function(){
17790         if(this.win && !this.sourceEditMode){
17791             this.win.focus();
17792         }else{
17793             this.el.focus();
17794         }
17795     },
17796     
17797     assignDocWin: function()
17798     {
17799         var iframe = this.iframe;
17800         
17801          if(Roo.isIE){
17802             this.doc = iframe.contentWindow.document;
17803             this.win = iframe.contentWindow;
17804         } else {
17805 //            if (!Roo.get(this.frameId)) {
17806 //                return;
17807 //            }
17808 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17809 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17810             
17811             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17812                 return;
17813             }
17814             
17815             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17816             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17817         }
17818     },
17819     
17820     // private
17821     initEditor : function(){
17822         //console.log("INIT EDITOR");
17823         this.assignDocWin();
17824         
17825         
17826         
17827         this.doc.designMode="on";
17828         this.doc.open();
17829         this.doc.write(this.getDocMarkup());
17830         this.doc.close();
17831         
17832         var dbody = (this.doc.body || this.doc.documentElement);
17833         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17834         // this copies styles from the containing element into thsi one..
17835         // not sure why we need all of this..
17836         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17837         
17838         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17839         //ss['background-attachment'] = 'fixed'; // w3c
17840         dbody.bgProperties = 'fixed'; // ie
17841         //Roo.DomHelper.applyStyles(dbody, ss);
17842         Roo.EventManager.on(this.doc, {
17843             //'mousedown': this.onEditorEvent,
17844             'mouseup': this.onEditorEvent,
17845             'dblclick': this.onEditorEvent,
17846             'click': this.onEditorEvent,
17847             'keyup': this.onEditorEvent,
17848             buffer:100,
17849             scope: this
17850         });
17851         if(Roo.isGecko){
17852             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17853         }
17854         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17855             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17856         }
17857         this.initialized = true;
17858
17859         this.owner.fireEvent('initialize', this);
17860         this.pushValue();
17861     },
17862
17863     // private
17864     onDestroy : function(){
17865         
17866         
17867         
17868         if(this.rendered){
17869             
17870             //for (var i =0; i < this.toolbars.length;i++) {
17871             //    // fixme - ask toolbars for heights?
17872             //    this.toolbars[i].onDestroy();
17873            // }
17874             
17875             //this.wrap.dom.innerHTML = '';
17876             //this.wrap.remove();
17877         }
17878     },
17879
17880     // private
17881     onFirstFocus : function(){
17882         
17883         this.assignDocWin();
17884         
17885         
17886         this.activated = true;
17887          
17888     
17889         if(Roo.isGecko){ // prevent silly gecko errors
17890             this.win.focus();
17891             var s = this.win.getSelection();
17892             if(!s.focusNode || s.focusNode.nodeType != 3){
17893                 var r = s.getRangeAt(0);
17894                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17895                 r.collapse(true);
17896                 this.deferFocus();
17897             }
17898             try{
17899                 this.execCmd('useCSS', true);
17900                 this.execCmd('styleWithCSS', false);
17901             }catch(e){}
17902         }
17903         this.owner.fireEvent('activate', this);
17904     },
17905
17906     // private
17907     adjustFont: function(btn){
17908         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17909         //if(Roo.isSafari){ // safari
17910         //    adjust *= 2;
17911        // }
17912         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17913         if(Roo.isSafari){ // safari
17914             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17915             v =  (v < 10) ? 10 : v;
17916             v =  (v > 48) ? 48 : v;
17917             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17918             
17919         }
17920         
17921         
17922         v = Math.max(1, v+adjust);
17923         
17924         this.execCmd('FontSize', v  );
17925     },
17926
17927     onEditorEvent : function(e){
17928         this.owner.fireEvent('editorevent', this, e);
17929       //  this.updateToolbar();
17930         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17931     },
17932
17933     insertTag : function(tg)
17934     {
17935         // could be a bit smarter... -> wrap the current selected tRoo..
17936         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17937             
17938             range = this.createRange(this.getSelection());
17939             var wrappingNode = this.doc.createElement(tg.toLowerCase());
17940             wrappingNode.appendChild(range.extractContents());
17941             range.insertNode(wrappingNode);
17942
17943             return;
17944             
17945             
17946             
17947         }
17948         this.execCmd("formatblock",   tg);
17949         
17950     },
17951     
17952     insertText : function(txt)
17953     {
17954         
17955         
17956         var range = this.createRange();
17957         range.deleteContents();
17958                //alert(Sender.getAttribute('label'));
17959                
17960         range.insertNode(this.doc.createTextNode(txt));
17961     } ,
17962     
17963      
17964
17965     /**
17966      * Executes a Midas editor command on the editor document and performs necessary focus and
17967      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17968      * @param {String} cmd The Midas command
17969      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17970      */
17971     relayCmd : function(cmd, value){
17972         this.win.focus();
17973         this.execCmd(cmd, value);
17974         this.owner.fireEvent('editorevent', this);
17975         //this.updateToolbar();
17976         this.owner.deferFocus();
17977     },
17978
17979     /**
17980      * Executes a Midas editor command directly on the editor document.
17981      * For visual commands, you should use {@link #relayCmd} instead.
17982      * <b>This should only be called after the editor is initialized.</b>
17983      * @param {String} cmd The Midas command
17984      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17985      */
17986     execCmd : function(cmd, value){
17987         this.doc.execCommand(cmd, false, value === undefined ? null : value);
17988         this.syncValue();
17989     },
17990  
17991  
17992    
17993     /**
17994      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17995      * to insert tRoo.
17996      * @param {String} text | dom node.. 
17997      */
17998     insertAtCursor : function(text)
17999     {
18000         
18001         
18002         
18003         if(!this.activated){
18004             return;
18005         }
18006         /*
18007         if(Roo.isIE){
18008             this.win.focus();
18009             var r = this.doc.selection.createRange();
18010             if(r){
18011                 r.collapse(true);
18012                 r.pasteHTML(text);
18013                 this.syncValue();
18014                 this.deferFocus();
18015             
18016             }
18017             return;
18018         }
18019         */
18020         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18021             this.win.focus();
18022             
18023             
18024             // from jquery ui (MIT licenced)
18025             var range, node;
18026             var win = this.win;
18027             
18028             if (win.getSelection && win.getSelection().getRangeAt) {
18029                 range = win.getSelection().getRangeAt(0);
18030                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18031                 range.insertNode(node);
18032             } else if (win.document.selection && win.document.selection.createRange) {
18033                 // no firefox support
18034                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18035                 win.document.selection.createRange().pasteHTML(txt);
18036             } else {
18037                 // no firefox support
18038                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18039                 this.execCmd('InsertHTML', txt);
18040             } 
18041             
18042             this.syncValue();
18043             
18044             this.deferFocus();
18045         }
18046     },
18047  // private
18048     mozKeyPress : function(e){
18049         if(e.ctrlKey){
18050             var c = e.getCharCode(), cmd;
18051           
18052             if(c > 0){
18053                 c = String.fromCharCode(c).toLowerCase();
18054                 switch(c){
18055                     case 'b':
18056                         cmd = 'bold';
18057                         break;
18058                     case 'i':
18059                         cmd = 'italic';
18060                         break;
18061                     
18062                     case 'u':
18063                         cmd = 'underline';
18064                         break;
18065                     
18066                     case 'v':
18067                         this.cleanUpPaste.defer(100, this);
18068                         return;
18069                         
18070                 }
18071                 if(cmd){
18072                     this.win.focus();
18073                     this.execCmd(cmd);
18074                     this.deferFocus();
18075                     e.preventDefault();
18076                 }
18077                 
18078             }
18079         }
18080     },
18081
18082     // private
18083     fixKeys : function(){ // load time branching for fastest keydown performance
18084         if(Roo.isIE){
18085             return function(e){
18086                 var k = e.getKey(), r;
18087                 if(k == e.TAB){
18088                     e.stopEvent();
18089                     r = this.doc.selection.createRange();
18090                     if(r){
18091                         r.collapse(true);
18092                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18093                         this.deferFocus();
18094                     }
18095                     return;
18096                 }
18097                 
18098                 if(k == e.ENTER){
18099                     r = this.doc.selection.createRange();
18100                     if(r){
18101                         var target = r.parentElement();
18102                         if(!target || target.tagName.toLowerCase() != 'li'){
18103                             e.stopEvent();
18104                             r.pasteHTML('<br />');
18105                             r.collapse(false);
18106                             r.select();
18107                         }
18108                     }
18109                 }
18110                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18111                     this.cleanUpPaste.defer(100, this);
18112                     return;
18113                 }
18114                 
18115                 
18116             };
18117         }else if(Roo.isOpera){
18118             return function(e){
18119                 var k = e.getKey();
18120                 if(k == e.TAB){
18121                     e.stopEvent();
18122                     this.win.focus();
18123                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18124                     this.deferFocus();
18125                 }
18126                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18127                     this.cleanUpPaste.defer(100, this);
18128                     return;
18129                 }
18130                 
18131             };
18132         }else if(Roo.isSafari){
18133             return function(e){
18134                 var k = e.getKey();
18135                 
18136                 if(k == e.TAB){
18137                     e.stopEvent();
18138                     this.execCmd('InsertText','\t');
18139                     this.deferFocus();
18140                     return;
18141                 }
18142                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18143                     this.cleanUpPaste.defer(100, this);
18144                     return;
18145                 }
18146                 
18147              };
18148         }
18149     }(),
18150     
18151     getAllAncestors: function()
18152     {
18153         var p = this.getSelectedNode();
18154         var a = [];
18155         if (!p) {
18156             a.push(p); // push blank onto stack..
18157             p = this.getParentElement();
18158         }
18159         
18160         
18161         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18162             a.push(p);
18163             p = p.parentNode;
18164         }
18165         a.push(this.doc.body);
18166         return a;
18167     },
18168     lastSel : false,
18169     lastSelNode : false,
18170     
18171     
18172     getSelection : function() 
18173     {
18174         this.assignDocWin();
18175         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18176     },
18177     
18178     getSelectedNode: function() 
18179     {
18180         // this may only work on Gecko!!!
18181         
18182         // should we cache this!!!!
18183         
18184         
18185         
18186          
18187         var range = this.createRange(this.getSelection()).cloneRange();
18188         
18189         if (Roo.isIE) {
18190             var parent = range.parentElement();
18191             while (true) {
18192                 var testRange = range.duplicate();
18193                 testRange.moveToElementText(parent);
18194                 if (testRange.inRange(range)) {
18195                     break;
18196                 }
18197                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18198                     break;
18199                 }
18200                 parent = parent.parentElement;
18201             }
18202             return parent;
18203         }
18204         
18205         // is ancestor a text element.
18206         var ac =  range.commonAncestorContainer;
18207         if (ac.nodeType == 3) {
18208             ac = ac.parentNode;
18209         }
18210         
18211         var ar = ac.childNodes;
18212          
18213         var nodes = [];
18214         var other_nodes = [];
18215         var has_other_nodes = false;
18216         for (var i=0;i<ar.length;i++) {
18217             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18218                 continue;
18219             }
18220             // fullly contained node.
18221             
18222             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18223                 nodes.push(ar[i]);
18224                 continue;
18225             }
18226             
18227             // probably selected..
18228             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18229                 other_nodes.push(ar[i]);
18230                 continue;
18231             }
18232             // outer..
18233             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18234                 continue;
18235             }
18236             
18237             
18238             has_other_nodes = true;
18239         }
18240         if (!nodes.length && other_nodes.length) {
18241             nodes= other_nodes;
18242         }
18243         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18244             return false;
18245         }
18246         
18247         return nodes[0];
18248     },
18249     createRange: function(sel)
18250     {
18251         // this has strange effects when using with 
18252         // top toolbar - not sure if it's a great idea.
18253         //this.editor.contentWindow.focus();
18254         if (typeof sel != "undefined") {
18255             try {
18256                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18257             } catch(e) {
18258                 return this.doc.createRange();
18259             }
18260         } else {
18261             return this.doc.createRange();
18262         }
18263     },
18264     getParentElement: function()
18265     {
18266         
18267         this.assignDocWin();
18268         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18269         
18270         var range = this.createRange(sel);
18271          
18272         try {
18273             var p = range.commonAncestorContainer;
18274             while (p.nodeType == 3) { // text node
18275                 p = p.parentNode;
18276             }
18277             return p;
18278         } catch (e) {
18279             return null;
18280         }
18281     
18282     },
18283     /***
18284      *
18285      * Range intersection.. the hard stuff...
18286      *  '-1' = before
18287      *  '0' = hits..
18288      *  '1' = after.
18289      *         [ -- selected range --- ]
18290      *   [fail]                        [fail]
18291      *
18292      *    basically..
18293      *      if end is before start or  hits it. fail.
18294      *      if start is after end or hits it fail.
18295      *
18296      *   if either hits (but other is outside. - then it's not 
18297      *   
18298      *    
18299      **/
18300     
18301     
18302     // @see http://www.thismuchiknow.co.uk/?p=64.
18303     rangeIntersectsNode : function(range, node)
18304     {
18305         var nodeRange = node.ownerDocument.createRange();
18306         try {
18307             nodeRange.selectNode(node);
18308         } catch (e) {
18309             nodeRange.selectNodeContents(node);
18310         }
18311     
18312         var rangeStartRange = range.cloneRange();
18313         rangeStartRange.collapse(true);
18314     
18315         var rangeEndRange = range.cloneRange();
18316         rangeEndRange.collapse(false);
18317     
18318         var nodeStartRange = nodeRange.cloneRange();
18319         nodeStartRange.collapse(true);
18320     
18321         var nodeEndRange = nodeRange.cloneRange();
18322         nodeEndRange.collapse(false);
18323     
18324         return rangeStartRange.compareBoundaryPoints(
18325                  Range.START_TO_START, nodeEndRange) == -1 &&
18326                rangeEndRange.compareBoundaryPoints(
18327                  Range.START_TO_START, nodeStartRange) == 1;
18328         
18329          
18330     },
18331     rangeCompareNode : function(range, node)
18332     {
18333         var nodeRange = node.ownerDocument.createRange();
18334         try {
18335             nodeRange.selectNode(node);
18336         } catch (e) {
18337             nodeRange.selectNodeContents(node);
18338         }
18339         
18340         
18341         range.collapse(true);
18342     
18343         nodeRange.collapse(true);
18344      
18345         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18346         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18347          
18348         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18349         
18350         var nodeIsBefore   =  ss == 1;
18351         var nodeIsAfter    = ee == -1;
18352         
18353         if (nodeIsBefore && nodeIsAfter)
18354             return 0; // outer
18355         if (!nodeIsBefore && nodeIsAfter)
18356             return 1; //right trailed.
18357         
18358         if (nodeIsBefore && !nodeIsAfter)
18359             return 2;  // left trailed.
18360         // fully contined.
18361         return 3;
18362     },
18363
18364     // private? - in a new class?
18365     cleanUpPaste :  function()
18366     {
18367         // cleans up the whole document..
18368         Roo.log('cleanuppaste');
18369         
18370         this.cleanUpChildren(this.doc.body);
18371         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18372         if (clean != this.doc.body.innerHTML) {
18373             this.doc.body.innerHTML = clean;
18374         }
18375         
18376     },
18377     
18378     cleanWordChars : function(input) {// change the chars to hex code
18379         var he = Roo.HtmlEditorCore;
18380         
18381         var output = input;
18382         Roo.each(he.swapCodes, function(sw) { 
18383             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18384             
18385             output = output.replace(swapper, sw[1]);
18386         });
18387         
18388         return output;
18389     },
18390     
18391     
18392     cleanUpChildren : function (n)
18393     {
18394         if (!n.childNodes.length) {
18395             return;
18396         }
18397         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18398            this.cleanUpChild(n.childNodes[i]);
18399         }
18400     },
18401     
18402     
18403         
18404     
18405     cleanUpChild : function (node)
18406     {
18407         var ed = this;
18408         //console.log(node);
18409         if (node.nodeName == "#text") {
18410             // clean up silly Windows -- stuff?
18411             return; 
18412         }
18413         if (node.nodeName == "#comment") {
18414             node.parentNode.removeChild(node);
18415             // clean up silly Windows -- stuff?
18416             return; 
18417         }
18418         var lcname = node.tagName.toLowerCase();
18419         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18420         // whitelist of tags..
18421         
18422         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18423             // remove node.
18424             node.parentNode.removeChild(node);
18425             return;
18426             
18427         }
18428         
18429         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18430         
18431         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18432         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18433         
18434         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18435         //    remove_keep_children = true;
18436         //}
18437         
18438         if (remove_keep_children) {
18439             this.cleanUpChildren(node);
18440             // inserts everything just before this node...
18441             while (node.childNodes.length) {
18442                 var cn = node.childNodes[0];
18443                 node.removeChild(cn);
18444                 node.parentNode.insertBefore(cn, node);
18445             }
18446             node.parentNode.removeChild(node);
18447             return;
18448         }
18449         
18450         if (!node.attributes || !node.attributes.length) {
18451             this.cleanUpChildren(node);
18452             return;
18453         }
18454         
18455         function cleanAttr(n,v)
18456         {
18457             
18458             if (v.match(/^\./) || v.match(/^\//)) {
18459                 return;
18460             }
18461             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18462                 return;
18463             }
18464             if (v.match(/^#/)) {
18465                 return;
18466             }
18467 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18468             node.removeAttribute(n);
18469             
18470         }
18471         
18472         var cwhite = this.cwhite;
18473         var cblack = this.cblack;
18474             
18475         function cleanStyle(n,v)
18476         {
18477             if (v.match(/expression/)) { //XSS?? should we even bother..
18478                 node.removeAttribute(n);
18479                 return;
18480             }
18481             
18482             var parts = v.split(/;/);
18483             var clean = [];
18484             
18485             Roo.each(parts, function(p) {
18486                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18487                 if (!p.length) {
18488                     return true;
18489                 }
18490                 var l = p.split(':').shift().replace(/\s+/g,'');
18491                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18492                 
18493                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18494 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18495                     //node.removeAttribute(n);
18496                     return true;
18497                 }
18498                 //Roo.log()
18499                 // only allow 'c whitelisted system attributes'
18500                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18501 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18502                     //node.removeAttribute(n);
18503                     return true;
18504                 }
18505                 
18506                 
18507                  
18508                 
18509                 clean.push(p);
18510                 return true;
18511             });
18512             if (clean.length) { 
18513                 node.setAttribute(n, clean.join(';'));
18514             } else {
18515                 node.removeAttribute(n);
18516             }
18517             
18518         }
18519         
18520         
18521         for (var i = node.attributes.length-1; i > -1 ; i--) {
18522             var a = node.attributes[i];
18523             //console.log(a);
18524             
18525             if (a.name.toLowerCase().substr(0,2)=='on')  {
18526                 node.removeAttribute(a.name);
18527                 continue;
18528             }
18529             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18530                 node.removeAttribute(a.name);
18531                 continue;
18532             }
18533             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18534                 cleanAttr(a.name,a.value); // fixme..
18535                 continue;
18536             }
18537             if (a.name == 'style') {
18538                 cleanStyle(a.name,a.value);
18539                 continue;
18540             }
18541             /// clean up MS crap..
18542             // tecnically this should be a list of valid class'es..
18543             
18544             
18545             if (a.name == 'class') {
18546                 if (a.value.match(/^Mso/)) {
18547                     node.className = '';
18548                 }
18549                 
18550                 if (a.value.match(/body/)) {
18551                     node.className = '';
18552                 }
18553                 continue;
18554             }
18555             
18556             // style cleanup!?
18557             // class cleanup?
18558             
18559         }
18560         
18561         
18562         this.cleanUpChildren(node);
18563         
18564         
18565     },
18566     /**
18567      * Clean up MS wordisms...
18568      */
18569     cleanWord : function(node)
18570     {
18571         var _t = this;
18572         var cleanWordChildren = function()
18573         {
18574             if (!node.childNodes.length) {
18575                 return;
18576             }
18577             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18578                _t.cleanWord(node.childNodes[i]);
18579             }
18580         }
18581         
18582         
18583         if (!node) {
18584             this.cleanWord(this.doc.body);
18585             return;
18586         }
18587         if (node.nodeName == "#text") {
18588             // clean up silly Windows -- stuff?
18589             return; 
18590         }
18591         if (node.nodeName == "#comment") {
18592             node.parentNode.removeChild(node);
18593             // clean up silly Windows -- stuff?
18594             return; 
18595         }
18596         
18597         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18598             node.parentNode.removeChild(node);
18599             return;
18600         }
18601         
18602         // remove - but keep children..
18603         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18604             while (node.childNodes.length) {
18605                 var cn = node.childNodes[0];
18606                 node.removeChild(cn);
18607                 node.parentNode.insertBefore(cn, node);
18608             }
18609             node.parentNode.removeChild(node);
18610             cleanWordChildren();
18611             return;
18612         }
18613         // clean styles
18614         if (node.className.length) {
18615             
18616             var cn = node.className.split(/\W+/);
18617             var cna = [];
18618             Roo.each(cn, function(cls) {
18619                 if (cls.match(/Mso[a-zA-Z]+/)) {
18620                     return;
18621                 }
18622                 cna.push(cls);
18623             });
18624             node.className = cna.length ? cna.join(' ') : '';
18625             if (!cna.length) {
18626                 node.removeAttribute("class");
18627             }
18628         }
18629         
18630         if (node.hasAttribute("lang")) {
18631             node.removeAttribute("lang");
18632         }
18633         
18634         if (node.hasAttribute("style")) {
18635             
18636             var styles = node.getAttribute("style").split(";");
18637             var nstyle = [];
18638             Roo.each(styles, function(s) {
18639                 if (!s.match(/:/)) {
18640                     return;
18641                 }
18642                 var kv = s.split(":");
18643                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18644                     return;
18645                 }
18646                 // what ever is left... we allow.
18647                 nstyle.push(s);
18648             });
18649             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18650             if (!nstyle.length) {
18651                 node.removeAttribute('style');
18652             }
18653         }
18654         
18655         cleanWordChildren();
18656         
18657         
18658     },
18659     domToHTML : function(currentElement, depth, nopadtext) {
18660         
18661         depth = depth || 0;
18662         nopadtext = nopadtext || false;
18663     
18664         if (!currentElement) {
18665             return this.domToHTML(this.doc.body);
18666         }
18667         
18668         //Roo.log(currentElement);
18669         var j;
18670         var allText = false;
18671         var nodeName = currentElement.nodeName;
18672         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18673         
18674         if  (nodeName == '#text') {
18675             
18676             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18677         }
18678         
18679         
18680         var ret = '';
18681         if (nodeName != 'BODY') {
18682              
18683             var i = 0;
18684             // Prints the node tagName, such as <A>, <IMG>, etc
18685             if (tagName) {
18686                 var attr = [];
18687                 for(i = 0; i < currentElement.attributes.length;i++) {
18688                     // quoting?
18689                     var aname = currentElement.attributes.item(i).name;
18690                     if (!currentElement.attributes.item(i).value.length) {
18691                         continue;
18692                     }
18693                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18694                 }
18695                 
18696                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18697             } 
18698             else {
18699                 
18700                 // eack
18701             }
18702         } else {
18703             tagName = false;
18704         }
18705         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18706             return ret;
18707         }
18708         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18709             nopadtext = true;
18710         }
18711         
18712         
18713         // Traverse the tree
18714         i = 0;
18715         var currentElementChild = currentElement.childNodes.item(i);
18716         var allText = true;
18717         var innerHTML  = '';
18718         lastnode = '';
18719         while (currentElementChild) {
18720             // Formatting code (indent the tree so it looks nice on the screen)
18721             var nopad = nopadtext;
18722             if (lastnode == 'SPAN') {
18723                 nopad  = true;
18724             }
18725             // text
18726             if  (currentElementChild.nodeName == '#text') {
18727                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18728                 toadd = nopadtext ? toadd : toadd.trim();
18729                 if (!nopad && toadd.length > 80) {
18730                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18731                 }
18732                 innerHTML  += toadd;
18733                 
18734                 i++;
18735                 currentElementChild = currentElement.childNodes.item(i);
18736                 lastNode = '';
18737                 continue;
18738             }
18739             allText = false;
18740             
18741             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18742                 
18743             // Recursively traverse the tree structure of the child node
18744             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18745             lastnode = currentElementChild.nodeName;
18746             i++;
18747             currentElementChild=currentElement.childNodes.item(i);
18748         }
18749         
18750         ret += innerHTML;
18751         
18752         if (!allText) {
18753                 // The remaining code is mostly for formatting the tree
18754             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18755         }
18756         
18757         
18758         if (tagName) {
18759             ret+= "</"+tagName+">";
18760         }
18761         return ret;
18762         
18763     },
18764         
18765     applyBlacklists : function()
18766     {
18767         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18768         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18769         
18770         this.white = [];
18771         this.black = [];
18772         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18773             if (b.indexOf(tag) > -1) {
18774                 return;
18775             }
18776             this.white.push(tag);
18777             
18778         }, this);
18779         
18780         Roo.each(w, function(tag) {
18781             if (b.indexOf(tag) > -1) {
18782                 return;
18783             }
18784             if (this.white.indexOf(tag) > -1) {
18785                 return;
18786             }
18787             this.white.push(tag);
18788             
18789         }, this);
18790         
18791         
18792         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18793             if (w.indexOf(tag) > -1) {
18794                 return;
18795             }
18796             this.black.push(tag);
18797             
18798         }, this);
18799         
18800         Roo.each(b, function(tag) {
18801             if (w.indexOf(tag) > -1) {
18802                 return;
18803             }
18804             if (this.black.indexOf(tag) > -1) {
18805                 return;
18806             }
18807             this.black.push(tag);
18808             
18809         }, this);
18810         
18811         
18812         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18813         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18814         
18815         this.cwhite = [];
18816         this.cblack = [];
18817         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18818             if (b.indexOf(tag) > -1) {
18819                 return;
18820             }
18821             this.cwhite.push(tag);
18822             
18823         }, this);
18824         
18825         Roo.each(w, function(tag) {
18826             if (b.indexOf(tag) > -1) {
18827                 return;
18828             }
18829             if (this.cwhite.indexOf(tag) > -1) {
18830                 return;
18831             }
18832             this.cwhite.push(tag);
18833             
18834         }, this);
18835         
18836         
18837         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18838             if (w.indexOf(tag) > -1) {
18839                 return;
18840             }
18841             this.cblack.push(tag);
18842             
18843         }, this);
18844         
18845         Roo.each(b, function(tag) {
18846             if (w.indexOf(tag) > -1) {
18847                 return;
18848             }
18849             if (this.cblack.indexOf(tag) > -1) {
18850                 return;
18851             }
18852             this.cblack.push(tag);
18853             
18854         }, this);
18855     },
18856     
18857     setStylesheets : function(stylesheets)
18858     {
18859         if(typeof(stylesheets) == 'string'){
18860             Roo.get(this.iframe.contentDocument.head).createChild({
18861                 tag : 'link',
18862                 rel : 'stylesheet',
18863                 type : 'text/css',
18864                 href : stylesheets
18865             });
18866             
18867             return;
18868         }
18869         var _this = this;
18870      
18871         Roo.each(stylesheets, function(s) {
18872             if(!s.length){
18873                 return;
18874             }
18875             
18876             Roo.get(_this.iframe.contentDocument.head).createChild({
18877                 tag : 'link',
18878                 rel : 'stylesheet',
18879                 type : 'text/css',
18880                 href : s
18881             });
18882         });
18883
18884         
18885     },
18886     
18887     removeStylesheets : function()
18888     {
18889         var _this = this;
18890         
18891         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18892             s.remove();
18893         });
18894     }
18895     
18896     // hide stuff that is not compatible
18897     /**
18898      * @event blur
18899      * @hide
18900      */
18901     /**
18902      * @event change
18903      * @hide
18904      */
18905     /**
18906      * @event focus
18907      * @hide
18908      */
18909     /**
18910      * @event specialkey
18911      * @hide
18912      */
18913     /**
18914      * @cfg {String} fieldClass @hide
18915      */
18916     /**
18917      * @cfg {String} focusClass @hide
18918      */
18919     /**
18920      * @cfg {String} autoCreate @hide
18921      */
18922     /**
18923      * @cfg {String} inputType @hide
18924      */
18925     /**
18926      * @cfg {String} invalidClass @hide
18927      */
18928     /**
18929      * @cfg {String} invalidText @hide
18930      */
18931     /**
18932      * @cfg {String} msgFx @hide
18933      */
18934     /**
18935      * @cfg {String} validateOnBlur @hide
18936      */
18937 });
18938
18939 Roo.HtmlEditorCore.white = [
18940         'area', 'br', 'img', 'input', 'hr', 'wbr',
18941         
18942        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
18943        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
18944        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
18945        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
18946        'table',   'ul',         'xmp', 
18947        
18948        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
18949       'thead',   'tr', 
18950      
18951       'dir', 'menu', 'ol', 'ul', 'dl',
18952        
18953       'embed',  'object'
18954 ];
18955
18956
18957 Roo.HtmlEditorCore.black = [
18958     //    'embed',  'object', // enable - backend responsiblity to clean thiese
18959         'applet', // 
18960         'base',   'basefont', 'bgsound', 'blink',  'body', 
18961         'frame',  'frameset', 'head',    'html',   'ilayer', 
18962         'iframe', 'layer',  'link',     'meta',    'object',   
18963         'script', 'style' ,'title',  'xml' // clean later..
18964 ];
18965 Roo.HtmlEditorCore.clean = [
18966     'script', 'style', 'title', 'xml'
18967 ];
18968 Roo.HtmlEditorCore.remove = [
18969     'font'
18970 ];
18971 // attributes..
18972
18973 Roo.HtmlEditorCore.ablack = [
18974     'on'
18975 ];
18976     
18977 Roo.HtmlEditorCore.aclean = [ 
18978     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
18979 ];
18980
18981 // protocols..
18982 Roo.HtmlEditorCore.pwhite= [
18983         'http',  'https',  'mailto'
18984 ];
18985
18986 // white listed style attributes.
18987 Roo.HtmlEditorCore.cwhite= [
18988       //  'text-align', /// default is to allow most things..
18989       
18990          
18991 //        'font-size'//??
18992 ];
18993
18994 // black listed style attributes.
18995 Roo.HtmlEditorCore.cblack= [
18996       //  'font-size' -- this can be set by the project 
18997 ];
18998
18999
19000 Roo.HtmlEditorCore.swapCodes   =[ 
19001     [    8211, "--" ], 
19002     [    8212, "--" ], 
19003     [    8216,  "'" ],  
19004     [    8217, "'" ],  
19005     [    8220, '"' ],  
19006     [    8221, '"' ],  
19007     [    8226, "*" ],  
19008     [    8230, "..." ]
19009 ]; 
19010
19011     /*
19012  * - LGPL
19013  *
19014  * HtmlEditor
19015  * 
19016  */
19017
19018 /**
19019  * @class Roo.bootstrap.HtmlEditor
19020  * @extends Roo.bootstrap.TextArea
19021  * Bootstrap HtmlEditor class
19022
19023  * @constructor
19024  * Create a new HtmlEditor
19025  * @param {Object} config The config object
19026  */
19027
19028 Roo.bootstrap.HtmlEditor = function(config){
19029     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19030     if (!this.toolbars) {
19031         this.toolbars = [];
19032     }
19033     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19034     this.addEvents({
19035             /**
19036              * @event initialize
19037              * Fires when the editor is fully initialized (including the iframe)
19038              * @param {HtmlEditor} this
19039              */
19040             initialize: true,
19041             /**
19042              * @event activate
19043              * Fires when the editor is first receives the focus. Any insertion must wait
19044              * until after this event.
19045              * @param {HtmlEditor} this
19046              */
19047             activate: true,
19048              /**
19049              * @event beforesync
19050              * Fires before the textarea is updated with content from the editor iframe. Return false
19051              * to cancel the sync.
19052              * @param {HtmlEditor} this
19053              * @param {String} html
19054              */
19055             beforesync: true,
19056              /**
19057              * @event beforepush
19058              * Fires before the iframe editor is updated with content from the textarea. Return false
19059              * to cancel the push.
19060              * @param {HtmlEditor} this
19061              * @param {String} html
19062              */
19063             beforepush: true,
19064              /**
19065              * @event sync
19066              * Fires when the textarea is updated with content from the editor iframe.
19067              * @param {HtmlEditor} this
19068              * @param {String} html
19069              */
19070             sync: true,
19071              /**
19072              * @event push
19073              * Fires when the iframe editor is updated with content from the textarea.
19074              * @param {HtmlEditor} this
19075              * @param {String} html
19076              */
19077             push: true,
19078              /**
19079              * @event editmodechange
19080              * Fires when the editor switches edit modes
19081              * @param {HtmlEditor} this
19082              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19083              */
19084             editmodechange: true,
19085             /**
19086              * @event editorevent
19087              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19088              * @param {HtmlEditor} this
19089              */
19090             editorevent: true,
19091             /**
19092              * @event firstfocus
19093              * Fires when on first focus - needed by toolbars..
19094              * @param {HtmlEditor} this
19095              */
19096             firstfocus: true,
19097             /**
19098              * @event autosave
19099              * Auto save the htmlEditor value as a file into Events
19100              * @param {HtmlEditor} this
19101              */
19102             autosave: true,
19103             /**
19104              * @event savedpreview
19105              * preview the saved version of htmlEditor
19106              * @param {HtmlEditor} this
19107              */
19108             savedpreview: true
19109         });
19110 };
19111
19112
19113 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19114     
19115     
19116       /**
19117      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19118      */
19119     toolbars : false,
19120    
19121      /**
19122      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19123      *                        Roo.resizable.
19124      */
19125     resizable : false,
19126      /**
19127      * @cfg {Number} height (in pixels)
19128      */   
19129     height: 300,
19130    /**
19131      * @cfg {Number} width (in pixels)
19132      */   
19133     width: false,
19134     
19135     /**
19136      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19137      * 
19138      */
19139     stylesheets: false,
19140     
19141     // id of frame..
19142     frameId: false,
19143     
19144     // private properties
19145     validationEvent : false,
19146     deferHeight: true,
19147     initialized : false,
19148     activated : false,
19149     
19150     onFocus : Roo.emptyFn,
19151     iframePad:3,
19152     hideMode:'offsets',
19153     
19154     
19155     tbContainer : false,
19156     
19157     toolbarContainer :function() {
19158         return this.wrap.select('.x-html-editor-tb',true).first();
19159     },
19160
19161     /**
19162      * Protected method that will not generally be called directly. It
19163      * is called when the editor creates its toolbar. Override this method if you need to
19164      * add custom toolbar buttons.
19165      * @param {HtmlEditor} editor
19166      */
19167     createToolbar : function(){
19168         
19169         Roo.log("create toolbars");
19170         
19171         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19172         this.toolbars[0].render(this.toolbarContainer());
19173         
19174         return;
19175         
19176 //        if (!editor.toolbars || !editor.toolbars.length) {
19177 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19178 //        }
19179 //        
19180 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19181 //            editor.toolbars[i] = Roo.factory(
19182 //                    typeof(editor.toolbars[i]) == 'string' ?
19183 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19184 //                Roo.bootstrap.HtmlEditor);
19185 //            editor.toolbars[i].init(editor);
19186 //        }
19187     },
19188
19189      
19190     // private
19191     onRender : function(ct, position)
19192     {
19193        // Roo.log("Call onRender: " + this.xtype);
19194         var _t = this;
19195         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19196       
19197         this.wrap = this.inputEl().wrap({
19198             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19199         });
19200         
19201         this.editorcore.onRender(ct, position);
19202          
19203         if (this.resizable) {
19204             this.resizeEl = new Roo.Resizable(this.wrap, {
19205                 pinned : true,
19206                 wrap: true,
19207                 dynamic : true,
19208                 minHeight : this.height,
19209                 height: this.height,
19210                 handles : this.resizable,
19211                 width: this.width,
19212                 listeners : {
19213                     resize : function(r, w, h) {
19214                         _t.onResize(w,h); // -something
19215                     }
19216                 }
19217             });
19218             
19219         }
19220         this.createToolbar(this);
19221        
19222         
19223         if(!this.width && this.resizable){
19224             this.setSize(this.wrap.getSize());
19225         }
19226         if (this.resizeEl) {
19227             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19228             // should trigger onReize..
19229         }
19230         
19231     },
19232
19233     // private
19234     onResize : function(w, h)
19235     {
19236         Roo.log('resize: ' +w + ',' + h );
19237         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19238         var ew = false;
19239         var eh = false;
19240         
19241         if(this.inputEl() ){
19242             if(typeof w == 'number'){
19243                 var aw = w - this.wrap.getFrameWidth('lr');
19244                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19245                 ew = aw;
19246             }
19247             if(typeof h == 'number'){
19248                  var tbh = -11;  // fixme it needs to tool bar size!
19249                 for (var i =0; i < this.toolbars.length;i++) {
19250                     // fixme - ask toolbars for heights?
19251                     tbh += this.toolbars[i].el.getHeight();
19252                     //if (this.toolbars[i].footer) {
19253                     //    tbh += this.toolbars[i].footer.el.getHeight();
19254                     //}
19255                 }
19256               
19257                 
19258                 
19259                 
19260                 
19261                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19262                 ah -= 5; // knock a few pixes off for look..
19263                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19264                 var eh = ah;
19265             }
19266         }
19267         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19268         this.editorcore.onResize(ew,eh);
19269         
19270     },
19271
19272     /**
19273      * Toggles the editor between standard and source edit mode.
19274      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19275      */
19276     toggleSourceEdit : function(sourceEditMode)
19277     {
19278         this.editorcore.toggleSourceEdit(sourceEditMode);
19279         
19280         if(this.editorcore.sourceEditMode){
19281             Roo.log('editor - showing textarea');
19282             
19283 //            Roo.log('in');
19284 //            Roo.log(this.syncValue());
19285             this.syncValue();
19286             this.inputEl().removeClass(['hide', 'x-hidden']);
19287             this.inputEl().dom.removeAttribute('tabIndex');
19288             this.inputEl().focus();
19289         }else{
19290             Roo.log('editor - hiding textarea');
19291 //            Roo.log('out')
19292 //            Roo.log(this.pushValue()); 
19293             this.pushValue();
19294             
19295             this.inputEl().addClass(['hide', 'x-hidden']);
19296             this.inputEl().dom.setAttribute('tabIndex', -1);
19297             //this.deferFocus();
19298         }
19299          
19300         if(this.resizable){
19301             this.setSize(this.wrap.getSize());
19302         }
19303         
19304         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19305     },
19306  
19307     // private (for BoxComponent)
19308     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19309
19310     // private (for BoxComponent)
19311     getResizeEl : function(){
19312         return this.wrap;
19313     },
19314
19315     // private (for BoxComponent)
19316     getPositionEl : function(){
19317         return this.wrap;
19318     },
19319
19320     // private
19321     initEvents : function(){
19322         this.originalValue = this.getValue();
19323     },
19324
19325 //    /**
19326 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19327 //     * @method
19328 //     */
19329 //    markInvalid : Roo.emptyFn,
19330 //    /**
19331 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19332 //     * @method
19333 //     */
19334 //    clearInvalid : Roo.emptyFn,
19335
19336     setValue : function(v){
19337         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19338         this.editorcore.pushValue();
19339     },
19340
19341      
19342     // private
19343     deferFocus : function(){
19344         this.focus.defer(10, this);
19345     },
19346
19347     // doc'ed in Field
19348     focus : function(){
19349         this.editorcore.focus();
19350         
19351     },
19352       
19353
19354     // private
19355     onDestroy : function(){
19356         
19357         
19358         
19359         if(this.rendered){
19360             
19361             for (var i =0; i < this.toolbars.length;i++) {
19362                 // fixme - ask toolbars for heights?
19363                 this.toolbars[i].onDestroy();
19364             }
19365             
19366             this.wrap.dom.innerHTML = '';
19367             this.wrap.remove();
19368         }
19369     },
19370
19371     // private
19372     onFirstFocus : function(){
19373         //Roo.log("onFirstFocus");
19374         this.editorcore.onFirstFocus();
19375          for (var i =0; i < this.toolbars.length;i++) {
19376             this.toolbars[i].onFirstFocus();
19377         }
19378         
19379     },
19380     
19381     // private
19382     syncValue : function()
19383     {   
19384         this.editorcore.syncValue();
19385     },
19386     
19387     pushValue : function()
19388     {   
19389         this.editorcore.pushValue();
19390     }
19391      
19392     
19393     // hide stuff that is not compatible
19394     /**
19395      * @event blur
19396      * @hide
19397      */
19398     /**
19399      * @event change
19400      * @hide
19401      */
19402     /**
19403      * @event focus
19404      * @hide
19405      */
19406     /**
19407      * @event specialkey
19408      * @hide
19409      */
19410     /**
19411      * @cfg {String} fieldClass @hide
19412      */
19413     /**
19414      * @cfg {String} focusClass @hide
19415      */
19416     /**
19417      * @cfg {String} autoCreate @hide
19418      */
19419     /**
19420      * @cfg {String} inputType @hide
19421      */
19422     /**
19423      * @cfg {String} invalidClass @hide
19424      */
19425     /**
19426      * @cfg {String} invalidText @hide
19427      */
19428     /**
19429      * @cfg {String} msgFx @hide
19430      */
19431     /**
19432      * @cfg {String} validateOnBlur @hide
19433      */
19434 });
19435  
19436     
19437    
19438    
19439    
19440       
19441 Roo.namespace('Roo.bootstrap.htmleditor');
19442 /**
19443  * @class Roo.bootstrap.HtmlEditorToolbar1
19444  * Basic Toolbar
19445  * 
19446  * Usage:
19447  *
19448  new Roo.bootstrap.HtmlEditor({
19449     ....
19450     toolbars : [
19451         new Roo.bootstrap.HtmlEditorToolbar1({
19452             disable : { fonts: 1 , format: 1, ..., ... , ...],
19453             btns : [ .... ]
19454         })
19455     }
19456      
19457  * 
19458  * @cfg {Object} disable List of elements to disable..
19459  * @cfg {Array} btns List of additional buttons.
19460  * 
19461  * 
19462  * NEEDS Extra CSS? 
19463  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19464  */
19465  
19466 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19467 {
19468     
19469     Roo.apply(this, config);
19470     
19471     // default disabled, based on 'good practice'..
19472     this.disable = this.disable || {};
19473     Roo.applyIf(this.disable, {
19474         fontSize : true,
19475         colors : true,
19476         specialElements : true
19477     });
19478     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19479     
19480     this.editor = config.editor;
19481     this.editorcore = config.editor.editorcore;
19482     
19483     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19484     
19485     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19486     // dont call parent... till later.
19487 }
19488 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19489      
19490     bar : true,
19491     
19492     editor : false,
19493     editorcore : false,
19494     
19495     
19496     formats : [
19497         "p" ,  
19498         "h1","h2","h3","h4","h5","h6", 
19499         "pre", "code", 
19500         "abbr", "acronym", "address", "cite", "samp", "var",
19501         'div','span'
19502     ],
19503     
19504     onRender : function(ct, position)
19505     {
19506        // Roo.log("Call onRender: " + this.xtype);
19507         
19508        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19509        Roo.log(this.el);
19510        this.el.dom.style.marginBottom = '0';
19511        var _this = this;
19512        var editorcore = this.editorcore;
19513        var editor= this.editor;
19514        
19515        var children = [];
19516        var btn = function(id,cmd , toggle, handler){
19517        
19518             var  event = toggle ? 'toggle' : 'click';
19519        
19520             var a = {
19521                 size : 'sm',
19522                 xtype: 'Button',
19523                 xns: Roo.bootstrap,
19524                 glyphicon : id,
19525                 cmd : id || cmd,
19526                 enableToggle:toggle !== false,
19527                 //html : 'submit'
19528                 pressed : toggle ? false : null,
19529                 listeners : {}
19530             }
19531             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19532                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19533             }
19534             children.push(a);
19535             return a;
19536        }
19537         
19538         var style = {
19539                 xtype: 'Button',
19540                 size : 'sm',
19541                 xns: Roo.bootstrap,
19542                 glyphicon : 'font',
19543                 //html : 'submit'
19544                 menu : {
19545                     xtype: 'Menu',
19546                     xns: Roo.bootstrap,
19547                     items:  []
19548                 }
19549         };
19550         Roo.each(this.formats, function(f) {
19551             style.menu.items.push({
19552                 xtype :'MenuItem',
19553                 xns: Roo.bootstrap,
19554                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19555                 tagname : f,
19556                 listeners : {
19557                     click : function()
19558                     {
19559                         editorcore.insertTag(this.tagname);
19560                         editor.focus();
19561                     }
19562                 }
19563                 
19564             });
19565         });
19566          children.push(style);   
19567             
19568             
19569         btn('bold',false,true);
19570         btn('italic',false,true);
19571         btn('align-left', 'justifyleft',true);
19572         btn('align-center', 'justifycenter',true);
19573         btn('align-right' , 'justifyright',true);
19574         btn('link', false, false, function(btn) {
19575             //Roo.log("create link?");
19576             var url = prompt(this.createLinkText, this.defaultLinkValue);
19577             if(url && url != 'http:/'+'/'){
19578                 this.editorcore.relayCmd('createlink', url);
19579             }
19580         }),
19581         btn('list','insertunorderedlist',true);
19582         btn('pencil', false,true, function(btn){
19583                 Roo.log(this);
19584                 
19585                 this.toggleSourceEdit(btn.pressed);
19586         });
19587         /*
19588         var cog = {
19589                 xtype: 'Button',
19590                 size : 'sm',
19591                 xns: Roo.bootstrap,
19592                 glyphicon : 'cog',
19593                 //html : 'submit'
19594                 menu : {
19595                     xtype: 'Menu',
19596                     xns: Roo.bootstrap,
19597                     items:  []
19598                 }
19599         };
19600         
19601         cog.menu.items.push({
19602             xtype :'MenuItem',
19603             xns: Roo.bootstrap,
19604             html : Clean styles,
19605             tagname : f,
19606             listeners : {
19607                 click : function()
19608                 {
19609                     editorcore.insertTag(this.tagname);
19610                     editor.focus();
19611                 }
19612             }
19613             
19614         });
19615        */
19616         
19617          
19618        this.xtype = 'NavSimplebar';
19619         
19620         for(var i=0;i< children.length;i++) {
19621             
19622             this.buttons.add(this.addxtypeChild(children[i]));
19623             
19624         }
19625         
19626         editor.on('editorevent', this.updateToolbar, this);
19627     },
19628     onBtnClick : function(id)
19629     {
19630        this.editorcore.relayCmd(id);
19631        this.editorcore.focus();
19632     },
19633     
19634     /**
19635      * Protected method that will not generally be called directly. It triggers
19636      * a toolbar update by reading the markup state of the current selection in the editor.
19637      */
19638     updateToolbar: function(){
19639
19640         if(!this.editorcore.activated){
19641             this.editor.onFirstFocus(); // is this neeed?
19642             return;
19643         }
19644
19645         var btns = this.buttons; 
19646         var doc = this.editorcore.doc;
19647         btns.get('bold').setActive(doc.queryCommandState('bold'));
19648         btns.get('italic').setActive(doc.queryCommandState('italic'));
19649         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19650         
19651         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19652         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19653         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19654         
19655         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19656         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19657          /*
19658         
19659         var ans = this.editorcore.getAllAncestors();
19660         if (this.formatCombo) {
19661             
19662             
19663             var store = this.formatCombo.store;
19664             this.formatCombo.setValue("");
19665             for (var i =0; i < ans.length;i++) {
19666                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19667                     // select it..
19668                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19669                     break;
19670                 }
19671             }
19672         }
19673         
19674         
19675         
19676         // hides menus... - so this cant be on a menu...
19677         Roo.bootstrap.MenuMgr.hideAll();
19678         */
19679         Roo.bootstrap.MenuMgr.hideAll();
19680         //this.editorsyncValue();
19681     },
19682     onFirstFocus: function() {
19683         this.buttons.each(function(item){
19684            item.enable();
19685         });
19686     },
19687     toggleSourceEdit : function(sourceEditMode){
19688         
19689           
19690         if(sourceEditMode){
19691             Roo.log("disabling buttons");
19692            this.buttons.each( function(item){
19693                 if(item.cmd != 'pencil'){
19694                     item.disable();
19695                 }
19696             });
19697           
19698         }else{
19699             Roo.log("enabling buttons");
19700             if(this.editorcore.initialized){
19701                 this.buttons.each( function(item){
19702                     item.enable();
19703                 });
19704             }
19705             
19706         }
19707         Roo.log("calling toggole on editor");
19708         // tell the editor that it's been pressed..
19709         this.editor.toggleSourceEdit(sourceEditMode);
19710        
19711     }
19712 });
19713
19714
19715
19716
19717
19718 /**
19719  * @class Roo.bootstrap.Table.AbstractSelectionModel
19720  * @extends Roo.util.Observable
19721  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19722  * implemented by descendant classes.  This class should not be directly instantiated.
19723  * @constructor
19724  */
19725 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19726     this.locked = false;
19727     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19728 };
19729
19730
19731 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19732     /** @ignore Called by the grid automatically. Do not call directly. */
19733     init : function(grid){
19734         this.grid = grid;
19735         this.initEvents();
19736     },
19737
19738     /**
19739      * Locks the selections.
19740      */
19741     lock : function(){
19742         this.locked = true;
19743     },
19744
19745     /**
19746      * Unlocks the selections.
19747      */
19748     unlock : function(){
19749         this.locked = false;
19750     },
19751
19752     /**
19753      * Returns true if the selections are locked.
19754      * @return {Boolean}
19755      */
19756     isLocked : function(){
19757         return this.locked;
19758     }
19759 });
19760 /**
19761  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19762  * @class Roo.bootstrap.Table.RowSelectionModel
19763  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19764  * It supports multiple selections and keyboard selection/navigation. 
19765  * @constructor
19766  * @param {Object} config
19767  */
19768
19769 Roo.bootstrap.Table.RowSelectionModel = function(config){
19770     Roo.apply(this, config);
19771     this.selections = new Roo.util.MixedCollection(false, function(o){
19772         return o.id;
19773     });
19774
19775     this.last = false;
19776     this.lastActive = false;
19777
19778     this.addEvents({
19779         /**
19780              * @event selectionchange
19781              * Fires when the selection changes
19782              * @param {SelectionModel} this
19783              */
19784             "selectionchange" : true,
19785         /**
19786              * @event afterselectionchange
19787              * Fires after the selection changes (eg. by key press or clicking)
19788              * @param {SelectionModel} this
19789              */
19790             "afterselectionchange" : true,
19791         /**
19792              * @event beforerowselect
19793              * Fires when a row is selected being selected, return false to cancel.
19794              * @param {SelectionModel} this
19795              * @param {Number} rowIndex The selected index
19796              * @param {Boolean} keepExisting False if other selections will be cleared
19797              */
19798             "beforerowselect" : true,
19799         /**
19800              * @event rowselect
19801              * Fires when a row is selected.
19802              * @param {SelectionModel} this
19803              * @param {Number} rowIndex The selected index
19804              * @param {Roo.data.Record} r The record
19805              */
19806             "rowselect" : true,
19807         /**
19808              * @event rowdeselect
19809              * Fires when a row is deselected.
19810              * @param {SelectionModel} this
19811              * @param {Number} rowIndex The selected index
19812              */
19813         "rowdeselect" : true
19814     });
19815     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19816     this.locked = false;
19817 };
19818
19819 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19820     /**
19821      * @cfg {Boolean} singleSelect
19822      * True to allow selection of only one row at a time (defaults to false)
19823      */
19824     singleSelect : false,
19825
19826     // private
19827     initEvents : function(){
19828
19829         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19830             this.grid.on("mousedown", this.handleMouseDown, this);
19831         }else{ // allow click to work like normal
19832             this.grid.on("rowclick", this.handleDragableRowClick, this);
19833         }
19834
19835         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19836             "up" : function(e){
19837                 if(!e.shiftKey){
19838                     this.selectPrevious(e.shiftKey);
19839                 }else if(this.last !== false && this.lastActive !== false){
19840                     var last = this.last;
19841                     this.selectRange(this.last,  this.lastActive-1);
19842                     this.grid.getView().focusRow(this.lastActive);
19843                     if(last !== false){
19844                         this.last = last;
19845                     }
19846                 }else{
19847                     this.selectFirstRow();
19848                 }
19849                 this.fireEvent("afterselectionchange", this);
19850             },
19851             "down" : function(e){
19852                 if(!e.shiftKey){
19853                     this.selectNext(e.shiftKey);
19854                 }else if(this.last !== false && this.lastActive !== false){
19855                     var last = this.last;
19856                     this.selectRange(this.last,  this.lastActive+1);
19857                     this.grid.getView().focusRow(this.lastActive);
19858                     if(last !== false){
19859                         this.last = last;
19860                     }
19861                 }else{
19862                     this.selectFirstRow();
19863                 }
19864                 this.fireEvent("afterselectionchange", this);
19865             },
19866             scope: this
19867         });
19868
19869         var view = this.grid.view;
19870         view.on("refresh", this.onRefresh, this);
19871         view.on("rowupdated", this.onRowUpdated, this);
19872         view.on("rowremoved", this.onRemove, this);
19873     },
19874
19875     // private
19876     onRefresh : function(){
19877         var ds = this.grid.dataSource, i, v = this.grid.view;
19878         var s = this.selections;
19879         s.each(function(r){
19880             if((i = ds.indexOfId(r.id)) != -1){
19881                 v.onRowSelect(i);
19882             }else{
19883                 s.remove(r);
19884             }
19885         });
19886     },
19887
19888     // private
19889     onRemove : function(v, index, r){
19890         this.selections.remove(r);
19891     },
19892
19893     // private
19894     onRowUpdated : function(v, index, r){
19895         if(this.isSelected(r)){
19896             v.onRowSelect(index);
19897         }
19898     },
19899
19900     /**
19901      * Select records.
19902      * @param {Array} records The records to select
19903      * @param {Boolean} keepExisting (optional) True to keep existing selections
19904      */
19905     selectRecords : function(records, keepExisting){
19906         if(!keepExisting){
19907             this.clearSelections();
19908         }
19909         var ds = this.grid.dataSource;
19910         for(var i = 0, len = records.length; i < len; i++){
19911             this.selectRow(ds.indexOf(records[i]), true);
19912         }
19913     },
19914
19915     /**
19916      * Gets the number of selected rows.
19917      * @return {Number}
19918      */
19919     getCount : function(){
19920         return this.selections.length;
19921     },
19922
19923     /**
19924      * Selects the first row in the grid.
19925      */
19926     selectFirstRow : function(){
19927         this.selectRow(0);
19928     },
19929
19930     /**
19931      * Select the last row.
19932      * @param {Boolean} keepExisting (optional) True to keep existing selections
19933      */
19934     selectLastRow : function(keepExisting){
19935         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19936     },
19937
19938     /**
19939      * Selects the row immediately following the last selected row.
19940      * @param {Boolean} keepExisting (optional) True to keep existing selections
19941      */
19942     selectNext : function(keepExisting){
19943         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19944             this.selectRow(this.last+1, keepExisting);
19945             this.grid.getView().focusRow(this.last);
19946         }
19947     },
19948
19949     /**
19950      * Selects the row that precedes the last selected row.
19951      * @param {Boolean} keepExisting (optional) True to keep existing selections
19952      */
19953     selectPrevious : function(keepExisting){
19954         if(this.last){
19955             this.selectRow(this.last-1, keepExisting);
19956             this.grid.getView().focusRow(this.last);
19957         }
19958     },
19959
19960     /**
19961      * Returns the selected records
19962      * @return {Array} Array of selected records
19963      */
19964     getSelections : function(){
19965         return [].concat(this.selections.items);
19966     },
19967
19968     /**
19969      * Returns the first selected record.
19970      * @return {Record}
19971      */
19972     getSelected : function(){
19973         return this.selections.itemAt(0);
19974     },
19975
19976
19977     /**
19978      * Clears all selections.
19979      */
19980     clearSelections : function(fast){
19981         if(this.locked) return;
19982         if(fast !== true){
19983             var ds = this.grid.dataSource;
19984             var s = this.selections;
19985             s.each(function(r){
19986                 this.deselectRow(ds.indexOfId(r.id));
19987             }, this);
19988             s.clear();
19989         }else{
19990             this.selections.clear();
19991         }
19992         this.last = false;
19993     },
19994
19995
19996     /**
19997      * Selects all rows.
19998      */
19999     selectAll : function(){
20000         if(this.locked) return;
20001         this.selections.clear();
20002         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20003             this.selectRow(i, true);
20004         }
20005     },
20006
20007     /**
20008      * Returns True if there is a selection.
20009      * @return {Boolean}
20010      */
20011     hasSelection : function(){
20012         return this.selections.length > 0;
20013     },
20014
20015     /**
20016      * Returns True if the specified row is selected.
20017      * @param {Number/Record} record The record or index of the record to check
20018      * @return {Boolean}
20019      */
20020     isSelected : function(index){
20021         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20022         return (r && this.selections.key(r.id) ? true : false);
20023     },
20024
20025     /**
20026      * Returns True if the specified record id is selected.
20027      * @param {String} id The id of record to check
20028      * @return {Boolean}
20029      */
20030     isIdSelected : function(id){
20031         return (this.selections.key(id) ? true : false);
20032     },
20033
20034     // private
20035     handleMouseDown : function(e, t){
20036         var view = this.grid.getView(), rowIndex;
20037         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20038             return;
20039         };
20040         if(e.shiftKey && this.last !== false){
20041             var last = this.last;
20042             this.selectRange(last, rowIndex, e.ctrlKey);
20043             this.last = last; // reset the last
20044             view.focusRow(rowIndex);
20045         }else{
20046             var isSelected = this.isSelected(rowIndex);
20047             if(e.button !== 0 && isSelected){
20048                 view.focusRow(rowIndex);
20049             }else if(e.ctrlKey && isSelected){
20050                 this.deselectRow(rowIndex);
20051             }else if(!isSelected){
20052                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20053                 view.focusRow(rowIndex);
20054             }
20055         }
20056         this.fireEvent("afterselectionchange", this);
20057     },
20058     // private
20059     handleDragableRowClick :  function(grid, rowIndex, e) 
20060     {
20061         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20062             this.selectRow(rowIndex, false);
20063             grid.view.focusRow(rowIndex);
20064              this.fireEvent("afterselectionchange", this);
20065         }
20066     },
20067     
20068     /**
20069      * Selects multiple rows.
20070      * @param {Array} rows Array of the indexes of the row to select
20071      * @param {Boolean} keepExisting (optional) True to keep existing selections
20072      */
20073     selectRows : function(rows, keepExisting){
20074         if(!keepExisting){
20075             this.clearSelections();
20076         }
20077         for(var i = 0, len = rows.length; i < len; i++){
20078             this.selectRow(rows[i], true);
20079         }
20080     },
20081
20082     /**
20083      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20084      * @param {Number} startRow The index of the first row in the range
20085      * @param {Number} endRow The index of the last row in the range
20086      * @param {Boolean} keepExisting (optional) True to retain existing selections
20087      */
20088     selectRange : function(startRow, endRow, keepExisting){
20089         if(this.locked) return;
20090         if(!keepExisting){
20091             this.clearSelections();
20092         }
20093         if(startRow <= endRow){
20094             for(var i = startRow; i <= endRow; i++){
20095                 this.selectRow(i, true);
20096             }
20097         }else{
20098             for(var i = startRow; i >= endRow; i--){
20099                 this.selectRow(i, true);
20100             }
20101         }
20102     },
20103
20104     /**
20105      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20106      * @param {Number} startRow The index of the first row in the range
20107      * @param {Number} endRow The index of the last row in the range
20108      */
20109     deselectRange : function(startRow, endRow, preventViewNotify){
20110         if(this.locked) return;
20111         for(var i = startRow; i <= endRow; i++){
20112             this.deselectRow(i, preventViewNotify);
20113         }
20114     },
20115
20116     /**
20117      * Selects a row.
20118      * @param {Number} row The index of the row to select
20119      * @param {Boolean} keepExisting (optional) True to keep existing selections
20120      */
20121     selectRow : function(index, keepExisting, preventViewNotify){
20122         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20123         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20124             if(!keepExisting || this.singleSelect){
20125                 this.clearSelections();
20126             }
20127             var r = this.grid.dataSource.getAt(index);
20128             this.selections.add(r);
20129             this.last = this.lastActive = index;
20130             if(!preventViewNotify){
20131                 this.grid.getView().onRowSelect(index);
20132             }
20133             this.fireEvent("rowselect", this, index, r);
20134             this.fireEvent("selectionchange", this);
20135         }
20136     },
20137
20138     /**
20139      * Deselects a row.
20140      * @param {Number} row The index of the row to deselect
20141      */
20142     deselectRow : function(index, preventViewNotify){
20143         if(this.locked) return;
20144         if(this.last == index){
20145             this.last = false;
20146         }
20147         if(this.lastActive == index){
20148             this.lastActive = false;
20149         }
20150         var r = this.grid.dataSource.getAt(index);
20151         this.selections.remove(r);
20152         if(!preventViewNotify){
20153             this.grid.getView().onRowDeselect(index);
20154         }
20155         this.fireEvent("rowdeselect", this, index);
20156         this.fireEvent("selectionchange", this);
20157     },
20158
20159     // private
20160     restoreLast : function(){
20161         if(this._last){
20162             this.last = this._last;
20163         }
20164     },
20165
20166     // private
20167     acceptsNav : function(row, col, cm){
20168         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20169     },
20170
20171     // private
20172     onEditorKey : function(field, e){
20173         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20174         if(k == e.TAB){
20175             e.stopEvent();
20176             ed.completeEdit();
20177             if(e.shiftKey){
20178                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20179             }else{
20180                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20181             }
20182         }else if(k == e.ENTER && !e.ctrlKey){
20183             e.stopEvent();
20184             ed.completeEdit();
20185             if(e.shiftKey){
20186                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20187             }else{
20188                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20189             }
20190         }else if(k == e.ESC){
20191             ed.cancelEdit();
20192         }
20193         if(newCell){
20194             g.startEditing(newCell[0], newCell[1]);
20195         }
20196     }
20197 });/*
20198  * Based on:
20199  * Ext JS Library 1.1.1
20200  * Copyright(c) 2006-2007, Ext JS, LLC.
20201  *
20202  * Originally Released Under LGPL - original licence link has changed is not relivant.
20203  *
20204  * Fork - LGPL
20205  * <script type="text/javascript">
20206  */
20207  
20208 /**
20209  * @class Roo.bootstrap.PagingToolbar
20210  * @extends Roo.Row
20211  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20212  * @constructor
20213  * Create a new PagingToolbar
20214  * @param {Object} config The config object
20215  */
20216 Roo.bootstrap.PagingToolbar = function(config)
20217 {
20218     // old args format still supported... - xtype is prefered..
20219         // created from xtype...
20220     var ds = config.dataSource;
20221     this.toolbarItems = [];
20222     if (config.items) {
20223         this.toolbarItems = config.items;
20224 //        config.items = [];
20225     }
20226     
20227     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20228     this.ds = ds;
20229     this.cursor = 0;
20230     if (ds) { 
20231         this.bind(ds);
20232     }
20233     
20234     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20235     
20236 };
20237
20238 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20239     /**
20240      * @cfg {Roo.data.Store} dataSource
20241      * The underlying data store providing the paged data
20242      */
20243     /**
20244      * @cfg {String/HTMLElement/Element} container
20245      * container The id or element that will contain the toolbar
20246      */
20247     /**
20248      * @cfg {Boolean} displayInfo
20249      * True to display the displayMsg (defaults to false)
20250      */
20251     /**
20252      * @cfg {Number} pageSize
20253      * The number of records to display per page (defaults to 20)
20254      */
20255     pageSize: 20,
20256     /**
20257      * @cfg {String} displayMsg
20258      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20259      */
20260     displayMsg : 'Displaying {0} - {1} of {2}',
20261     /**
20262      * @cfg {String} emptyMsg
20263      * The message to display when no records are found (defaults to "No data to display")
20264      */
20265     emptyMsg : 'No data to display',
20266     /**
20267      * Customizable piece of the default paging text (defaults to "Page")
20268      * @type String
20269      */
20270     beforePageText : "Page",
20271     /**
20272      * Customizable piece of the default paging text (defaults to "of %0")
20273      * @type String
20274      */
20275     afterPageText : "of {0}",
20276     /**
20277      * Customizable piece of the default paging text (defaults to "First Page")
20278      * @type String
20279      */
20280     firstText : "First Page",
20281     /**
20282      * Customizable piece of the default paging text (defaults to "Previous Page")
20283      * @type String
20284      */
20285     prevText : "Previous Page",
20286     /**
20287      * Customizable piece of the default paging text (defaults to "Next Page")
20288      * @type String
20289      */
20290     nextText : "Next Page",
20291     /**
20292      * Customizable piece of the default paging text (defaults to "Last Page")
20293      * @type String
20294      */
20295     lastText : "Last Page",
20296     /**
20297      * Customizable piece of the default paging text (defaults to "Refresh")
20298      * @type String
20299      */
20300     refreshText : "Refresh",
20301
20302     buttons : false,
20303     // private
20304     onRender : function(ct, position) 
20305     {
20306         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20307         this.navgroup.parentId = this.id;
20308         this.navgroup.onRender(this.el, null);
20309         // add the buttons to the navgroup
20310         
20311         if(this.displayInfo){
20312             Roo.log(this.el.select('ul.navbar-nav',true).first());
20313             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20314             this.displayEl = this.el.select('.x-paging-info', true).first();
20315 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20316 //            this.displayEl = navel.el.select('span',true).first();
20317         }
20318         
20319         var _this = this;
20320         
20321         if(this.buttons){
20322             Roo.each(_this.buttons, function(e){
20323                Roo.factory(e).onRender(_this.el, null);
20324             });
20325         }
20326             
20327         Roo.each(_this.toolbarItems, function(e) {
20328             _this.navgroup.addItem(e);
20329         });
20330         
20331         
20332         this.first = this.navgroup.addItem({
20333             tooltip: this.firstText,
20334             cls: "prev",
20335             icon : 'fa fa-backward',
20336             disabled: true,
20337             preventDefault: true,
20338             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20339         });
20340         
20341         this.prev =  this.navgroup.addItem({
20342             tooltip: this.prevText,
20343             cls: "prev",
20344             icon : 'fa fa-step-backward',
20345             disabled: true,
20346             preventDefault: true,
20347             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20348         });
20349     //this.addSeparator();
20350         
20351         
20352         var field = this.navgroup.addItem( {
20353             tagtype : 'span',
20354             cls : 'x-paging-position',
20355             
20356             html : this.beforePageText  +
20357                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20358                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20359          } ); //?? escaped?
20360         
20361         this.field = field.el.select('input', true).first();
20362         this.field.on("keydown", this.onPagingKeydown, this);
20363         this.field.on("focus", function(){this.dom.select();});
20364     
20365     
20366         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20367         //this.field.setHeight(18);
20368         //this.addSeparator();
20369         this.next = this.navgroup.addItem({
20370             tooltip: this.nextText,
20371             cls: "next",
20372             html : ' <i class="fa fa-step-forward">',
20373             disabled: true,
20374             preventDefault: true,
20375             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20376         });
20377         this.last = this.navgroup.addItem({
20378             tooltip: this.lastText,
20379             icon : 'fa fa-forward',
20380             cls: "next",
20381             disabled: true,
20382             preventDefault: true,
20383             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20384         });
20385     //this.addSeparator();
20386         this.loading = this.navgroup.addItem({
20387             tooltip: this.refreshText,
20388             icon: 'fa fa-refresh',
20389             preventDefault: true,
20390             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20391         });
20392
20393     },
20394
20395     // private
20396     updateInfo : function(){
20397         if(this.displayEl){
20398             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20399             var msg = count == 0 ?
20400                 this.emptyMsg :
20401                 String.format(
20402                     this.displayMsg,
20403                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20404                 );
20405             this.displayEl.update(msg);
20406         }
20407     },
20408
20409     // private
20410     onLoad : function(ds, r, o){
20411        this.cursor = o.params ? o.params.start : 0;
20412        var d = this.getPageData(),
20413             ap = d.activePage,
20414             ps = d.pages;
20415         
20416        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20417        this.field.dom.value = ap;
20418        this.first.setDisabled(ap == 1);
20419        this.prev.setDisabled(ap == 1);
20420        this.next.setDisabled(ap == ps);
20421        this.last.setDisabled(ap == ps);
20422        this.loading.enable();
20423        this.updateInfo();
20424     },
20425
20426     // private
20427     getPageData : function(){
20428         var total = this.ds.getTotalCount();
20429         return {
20430             total : total,
20431             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20432             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20433         };
20434     },
20435
20436     // private
20437     onLoadError : function(){
20438         this.loading.enable();
20439     },
20440
20441     // private
20442     onPagingKeydown : function(e){
20443         var k = e.getKey();
20444         var d = this.getPageData();
20445         if(k == e.RETURN){
20446             var v = this.field.dom.value, pageNum;
20447             if(!v || isNaN(pageNum = parseInt(v, 10))){
20448                 this.field.dom.value = d.activePage;
20449                 return;
20450             }
20451             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20452             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20453             e.stopEvent();
20454         }
20455         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))
20456         {
20457           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20458           this.field.dom.value = pageNum;
20459           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20460           e.stopEvent();
20461         }
20462         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20463         {
20464           var v = this.field.dom.value, pageNum; 
20465           var increment = (e.shiftKey) ? 10 : 1;
20466           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20467             increment *= -1;
20468           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20469             this.field.dom.value = d.activePage;
20470             return;
20471           }
20472           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20473           {
20474             this.field.dom.value = parseInt(v, 10) + increment;
20475             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20476             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20477           }
20478           e.stopEvent();
20479         }
20480     },
20481
20482     // private
20483     beforeLoad : function(){
20484         if(this.loading){
20485             this.loading.disable();
20486         }
20487     },
20488
20489     // private
20490     onClick : function(which){
20491         
20492         var ds = this.ds;
20493         if (!ds) {
20494             return;
20495         }
20496         
20497         switch(which){
20498             case "first":
20499                 ds.load({params:{start: 0, limit: this.pageSize}});
20500             break;
20501             case "prev":
20502                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20503             break;
20504             case "next":
20505                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20506             break;
20507             case "last":
20508                 var total = ds.getTotalCount();
20509                 var extra = total % this.pageSize;
20510                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20511                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20512             break;
20513             case "refresh":
20514                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20515             break;
20516         }
20517     },
20518
20519     /**
20520      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20521      * @param {Roo.data.Store} store The data store to unbind
20522      */
20523     unbind : function(ds){
20524         ds.un("beforeload", this.beforeLoad, this);
20525         ds.un("load", this.onLoad, this);
20526         ds.un("loadexception", this.onLoadError, this);
20527         ds.un("remove", this.updateInfo, this);
20528         ds.un("add", this.updateInfo, this);
20529         this.ds = undefined;
20530     },
20531
20532     /**
20533      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20534      * @param {Roo.data.Store} store The data store to bind
20535      */
20536     bind : function(ds){
20537         ds.on("beforeload", this.beforeLoad, this);
20538         ds.on("load", this.onLoad, this);
20539         ds.on("loadexception", this.onLoadError, this);
20540         ds.on("remove", this.updateInfo, this);
20541         ds.on("add", this.updateInfo, this);
20542         this.ds = ds;
20543     }
20544 });/*
20545  * - LGPL
20546  *
20547  * element
20548  * 
20549  */
20550
20551 /**
20552  * @class Roo.bootstrap.MessageBar
20553  * @extends Roo.bootstrap.Component
20554  * Bootstrap MessageBar class
20555  * @cfg {String} html contents of the MessageBar
20556  * @cfg {String} weight (info | success | warning | danger) default info
20557  * @cfg {String} beforeClass insert the bar before the given class
20558  * @cfg {Boolean} closable (true | false) default false
20559  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20560  * 
20561  * @constructor
20562  * Create a new Element
20563  * @param {Object} config The config object
20564  */
20565
20566 Roo.bootstrap.MessageBar = function(config){
20567     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20568 };
20569
20570 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20571     
20572     html: '',
20573     weight: 'info',
20574     closable: false,
20575     fixed: false,
20576     beforeClass: 'bootstrap-sticky-wrap',
20577     
20578     getAutoCreate : function(){
20579         
20580         var cfg = {
20581             tag: 'div',
20582             cls: 'alert alert-dismissable alert-' + this.weight,
20583             cn: [
20584                 {
20585                     tag: 'span',
20586                     cls: 'message',
20587                     html: this.html || ''
20588                 }
20589             ]
20590         }
20591         
20592         if(this.fixed){
20593             cfg.cls += ' alert-messages-fixed';
20594         }
20595         
20596         if(this.closable){
20597             cfg.cn.push({
20598                 tag: 'button',
20599                 cls: 'close',
20600                 html: 'x'
20601             });
20602         }
20603         
20604         return cfg;
20605     },
20606     
20607     onRender : function(ct, position)
20608     {
20609         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20610         
20611         if(!this.el){
20612             var cfg = Roo.apply({},  this.getAutoCreate());
20613             cfg.id = Roo.id();
20614             
20615             if (this.cls) {
20616                 cfg.cls += ' ' + this.cls;
20617             }
20618             if (this.style) {
20619                 cfg.style = this.style;
20620             }
20621             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20622             
20623             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20624         }
20625         
20626         this.el.select('>button.close').on('click', this.hide, this);
20627         
20628     },
20629     
20630     show : function()
20631     {
20632         if (!this.rendered) {
20633             this.render();
20634         }
20635         
20636         this.el.show();
20637         
20638         this.fireEvent('show', this);
20639         
20640     },
20641     
20642     hide : function()
20643     {
20644         if (!this.rendered) {
20645             this.render();
20646         }
20647         
20648         this.el.hide();
20649         
20650         this.fireEvent('hide', this);
20651     },
20652     
20653     update : function()
20654     {
20655 //        var e = this.el.dom.firstChild;
20656 //        
20657 //        if(this.closable){
20658 //            e = e.nextSibling;
20659 //        }
20660 //        
20661 //        e.data = this.html || '';
20662
20663         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20664     }
20665    
20666 });
20667
20668  
20669
20670      /*
20671  * - LGPL
20672  *
20673  * Graph
20674  * 
20675  */
20676
20677
20678 /**
20679  * @class Roo.bootstrap.Graph
20680  * @extends Roo.bootstrap.Component
20681  * Bootstrap Graph class
20682 > Prameters
20683  -sm {number} sm 4
20684  -md {number} md 5
20685  @cfg {String} graphtype  bar | vbar | pie
20686  @cfg {number} g_x coodinator | centre x (pie)
20687  @cfg {number} g_y coodinator | centre y (pie)
20688  @cfg {number} g_r radius (pie)
20689  @cfg {number} g_height height of the chart (respected by all elements in the set)
20690  @cfg {number} g_width width of the chart (respected by all elements in the set)
20691  @cfg {Object} title The title of the chart
20692     
20693  -{Array}  values
20694  -opts (object) options for the chart 
20695      o {
20696      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20697      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20698      o vgutter (number)
20699      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.
20700      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20701      o to
20702      o stretch (boolean)
20703      o }
20704  -opts (object) options for the pie
20705      o{
20706      o cut
20707      o startAngle (number)
20708      o endAngle (number)
20709      } 
20710  *
20711  * @constructor
20712  * Create a new Input
20713  * @param {Object} config The config object
20714  */
20715
20716 Roo.bootstrap.Graph = function(config){
20717     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20718     
20719     this.addEvents({
20720         // img events
20721         /**
20722          * @event click
20723          * The img click event for the img.
20724          * @param {Roo.EventObject} e
20725          */
20726         "click" : true
20727     });
20728 };
20729
20730 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20731     
20732     sm: 4,
20733     md: 5,
20734     graphtype: 'bar',
20735     g_height: 250,
20736     g_width: 400,
20737     g_x: 50,
20738     g_y: 50,
20739     g_r: 30,
20740     opts:{
20741         //g_colors: this.colors,
20742         g_type: 'soft',
20743         g_gutter: '20%'
20744
20745     },
20746     title : false,
20747
20748     getAutoCreate : function(){
20749         
20750         var cfg = {
20751             tag: 'div',
20752             html : null
20753         }
20754         
20755         
20756         return  cfg;
20757     },
20758
20759     onRender : function(ct,position){
20760         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20761         this.raphael = Raphael(this.el.dom);
20762         
20763                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20764                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20765                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20766                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20767                 /*
20768                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20769                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20770                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20771                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20772                 
20773                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20774                 r.barchart(330, 10, 300, 220, data1);
20775                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20776                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20777                 */
20778                 
20779                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20780                 // r.barchart(30, 30, 560, 250,  xdata, {
20781                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20782                 //     axis : "0 0 1 1",
20783                 //     axisxlabels :  xdata
20784                 //     //yvalues : cols,
20785                    
20786                 // });
20787 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20788 //        
20789 //        this.load(null,xdata,{
20790 //                axis : "0 0 1 1",
20791 //                axisxlabels :  xdata
20792 //                });
20793
20794     },
20795
20796     load : function(graphtype,xdata,opts){
20797         this.raphael.clear();
20798         if(!graphtype) {
20799             graphtype = this.graphtype;
20800         }
20801         if(!opts){
20802             opts = this.opts;
20803         }
20804         var r = this.raphael,
20805             fin = function () {
20806                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20807             },
20808             fout = function () {
20809                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20810             },
20811             pfin = function() {
20812                 this.sector.stop();
20813                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20814
20815                 if (this.label) {
20816                     this.label[0].stop();
20817                     this.label[0].attr({ r: 7.5 });
20818                     this.label[1].attr({ "font-weight": 800 });
20819                 }
20820             },
20821             pfout = function() {
20822                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20823
20824                 if (this.label) {
20825                     this.label[0].animate({ r: 5 }, 500, "bounce");
20826                     this.label[1].attr({ "font-weight": 400 });
20827                 }
20828             };
20829
20830         switch(graphtype){
20831             case 'bar':
20832                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20833                 break;
20834             case 'hbar':
20835                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20836                 break;
20837             case 'pie':
20838 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20839 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20840 //            
20841                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20842                 
20843                 break;
20844
20845         }
20846         
20847         if(this.title){
20848             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20849         }
20850         
20851     },
20852     
20853     setTitle: function(o)
20854     {
20855         this.title = o;
20856     },
20857     
20858     initEvents: function() {
20859         
20860         if(!this.href){
20861             this.el.on('click', this.onClick, this);
20862         }
20863     },
20864     
20865     onClick : function(e)
20866     {
20867         Roo.log('img onclick');
20868         this.fireEvent('click', this, e);
20869     }
20870    
20871 });
20872
20873  
20874 /*
20875  * - LGPL
20876  *
20877  * numberBox
20878  * 
20879  */
20880 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20881
20882 /**
20883  * @class Roo.bootstrap.dash.NumberBox
20884  * @extends Roo.bootstrap.Component
20885  * Bootstrap NumberBox class
20886  * @cfg {String} headline Box headline
20887  * @cfg {String} content Box content
20888  * @cfg {String} icon Box icon
20889  * @cfg {String} footer Footer text
20890  * @cfg {String} fhref Footer href
20891  * 
20892  * @constructor
20893  * Create a new NumberBox
20894  * @param {Object} config The config object
20895  */
20896
20897
20898 Roo.bootstrap.dash.NumberBox = function(config){
20899     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20900     
20901 };
20902
20903 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
20904     
20905     headline : '',
20906     content : '',
20907     icon : '',
20908     footer : '',
20909     fhref : '',
20910     ficon : '',
20911     
20912     getAutoCreate : function(){
20913         
20914         var cfg = {
20915             tag : 'div',
20916             cls : 'small-box ',
20917             cn : [
20918                 {
20919                     tag : 'div',
20920                     cls : 'inner',
20921                     cn :[
20922                         {
20923                             tag : 'h3',
20924                             cls : 'roo-headline',
20925                             html : this.headline
20926                         },
20927                         {
20928                             tag : 'p',
20929                             cls : 'roo-content',
20930                             html : this.content
20931                         }
20932                     ]
20933                 }
20934             ]
20935         }
20936         
20937         if(this.icon){
20938             cfg.cn.push({
20939                 tag : 'div',
20940                 cls : 'icon',
20941                 cn :[
20942                     {
20943                         tag : 'i',
20944                         cls : 'ion ' + this.icon
20945                     }
20946                 ]
20947             });
20948         }
20949         
20950         if(this.footer){
20951             var footer = {
20952                 tag : 'a',
20953                 cls : 'small-box-footer',
20954                 href : this.fhref || '#',
20955                 html : this.footer
20956             };
20957             
20958             cfg.cn.push(footer);
20959             
20960         }
20961         
20962         return  cfg;
20963     },
20964
20965     onRender : function(ct,position){
20966         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20967
20968
20969        
20970                 
20971     },
20972
20973     setHeadline: function (value)
20974     {
20975         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20976     },
20977     
20978     setFooter: function (value, href)
20979     {
20980         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20981         
20982         if(href){
20983             this.el.select('a.small-box-footer',true).first().attr('href', href);
20984         }
20985         
20986     },
20987
20988     setContent: function (value)
20989     {
20990         this.el.select('.roo-content',true).first().dom.innerHTML = value;
20991     },
20992
20993     initEvents: function() 
20994     {   
20995         
20996     }
20997     
20998 });
20999
21000  
21001 /*
21002  * - LGPL
21003  *
21004  * TabBox
21005  * 
21006  */
21007 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21008
21009 /**
21010  * @class Roo.bootstrap.dash.TabBox
21011  * @extends Roo.bootstrap.Component
21012  * Bootstrap TabBox class
21013  * @cfg {String} title Title of the TabBox
21014  * @cfg {String} icon Icon of the TabBox
21015  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21016  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21017  * 
21018  * @constructor
21019  * Create a new TabBox
21020  * @param {Object} config The config object
21021  */
21022
21023
21024 Roo.bootstrap.dash.TabBox = function(config){
21025     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21026     this.addEvents({
21027         // raw events
21028         /**
21029          * @event addpane
21030          * When a pane is added
21031          * @param {Roo.bootstrap.dash.TabPane} pane
21032          */
21033         "addpane" : true,
21034         /**
21035          * @event activatepane
21036          * When a pane is activated
21037          * @param {Roo.bootstrap.dash.TabPane} pane
21038          */
21039         "activatepane" : true
21040         
21041          
21042     });
21043     
21044     this.panes = [];
21045 };
21046
21047 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21048
21049     title : '',
21050     icon : false,
21051     showtabs : true,
21052     tabScrollable : false,
21053     
21054     getChildContainer : function()
21055     {
21056         return this.el.select('.tab-content', true).first();
21057     },
21058     
21059     getAutoCreate : function(){
21060         
21061         var header = {
21062             tag: 'li',
21063             cls: 'pull-left header',
21064             html: this.title,
21065             cn : []
21066         };
21067         
21068         if(this.icon){
21069             header.cn.push({
21070                 tag: 'i',
21071                 cls: 'fa ' + this.icon
21072             });
21073         }
21074         
21075         var h = {
21076             tag: 'ul',
21077             cls: 'nav nav-tabs pull-right',
21078             cn: [
21079                 header
21080             ]
21081         };
21082         
21083         if(this.tabScrollable){
21084             h = {
21085                 tag: 'div',
21086                 cls: 'tab-header',
21087                 cn: [
21088                     {
21089                         tag: 'ul',
21090                         cls: 'nav nav-tabs pull-right',
21091                         cn: [
21092                             header
21093                         ]
21094                     }
21095                 ]
21096             }
21097         }
21098         
21099         var cfg = {
21100             tag: 'div',
21101             cls: 'nav-tabs-custom',
21102             cn: [
21103                 h,
21104                 {
21105                     tag: 'div',
21106                     cls: 'tab-content no-padding',
21107                     cn: []
21108                 }
21109             ]
21110         }
21111
21112         return  cfg;
21113     },
21114     initEvents : function()
21115     {
21116         //Roo.log('add add pane handler');
21117         this.on('addpane', this.onAddPane, this);
21118     },
21119      /**
21120      * Updates the box title
21121      * @param {String} html to set the title to.
21122      */
21123     setTitle : function(value)
21124     {
21125         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21126     },
21127     onAddPane : function(pane)
21128     {
21129         this.panes.push(pane);
21130         //Roo.log('addpane');
21131         //Roo.log(pane);
21132         // tabs are rendere left to right..
21133         if(!this.showtabs){
21134             return;
21135         }
21136         
21137         var ctr = this.el.select('.nav-tabs', true).first();
21138          
21139          
21140         var existing = ctr.select('.nav-tab',true);
21141         var qty = existing.getCount();;
21142         
21143         
21144         var tab = ctr.createChild({
21145             tag : 'li',
21146             cls : 'nav-tab' + (qty ? '' : ' active'),
21147             cn : [
21148                 {
21149                     tag : 'a',
21150                     href:'#',
21151                     html : pane.title
21152                 }
21153             ]
21154         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21155         pane.tab = tab;
21156         
21157         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21158         if (!qty) {
21159             pane.el.addClass('active');
21160         }
21161         
21162                 
21163     },
21164     onTabClick : function(ev,un,ob,pane)
21165     {
21166         //Roo.log('tab - prev default');
21167         ev.preventDefault();
21168         
21169         
21170         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21171         pane.tab.addClass('active');
21172         //Roo.log(pane.title);
21173         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21174         // technically we should have a deactivate event.. but maybe add later.
21175         // and it should not de-activate the selected tab...
21176         this.fireEvent('activatepane', pane);
21177         pane.el.addClass('active');
21178         pane.fireEvent('activate');
21179         
21180         
21181     },
21182     
21183     getActivePane : function()
21184     {
21185         var r = false;
21186         Roo.each(this.panes, function(p) {
21187             if(p.el.hasClass('active')){
21188                 r = p;
21189                 return false;
21190             }
21191             
21192             return;
21193         });
21194         
21195         return r;
21196     }
21197     
21198     
21199 });
21200
21201  
21202 /*
21203  * - LGPL
21204  *
21205  * Tab pane
21206  * 
21207  */
21208 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21209 /**
21210  * @class Roo.bootstrap.TabPane
21211  * @extends Roo.bootstrap.Component
21212  * Bootstrap TabPane class
21213  * @cfg {Boolean} active (false | true) Default false
21214  * @cfg {String} title title of panel
21215
21216  * 
21217  * @constructor
21218  * Create a new TabPane
21219  * @param {Object} config The config object
21220  */
21221
21222 Roo.bootstrap.dash.TabPane = function(config){
21223     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21224     
21225     this.addEvents({
21226         // raw events
21227         /**
21228          * @event activate
21229          * When a pane is activated
21230          * @param {Roo.bootstrap.dash.TabPane} pane
21231          */
21232         "activate" : true
21233          
21234     });
21235 };
21236
21237 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21238     
21239     active : false,
21240     title : '',
21241     
21242     // the tabBox that this is attached to.
21243     tab : false,
21244      
21245     getAutoCreate : function() 
21246     {
21247         var cfg = {
21248             tag: 'div',
21249             cls: 'tab-pane'
21250         }
21251         
21252         if(this.active){
21253             cfg.cls += ' active';
21254         }
21255         
21256         return cfg;
21257     },
21258     initEvents  : function()
21259     {
21260         //Roo.log('trigger add pane handler');
21261         this.parent().fireEvent('addpane', this)
21262     },
21263     
21264      /**
21265      * Updates the tab title 
21266      * @param {String} html to set the title to.
21267      */
21268     setTitle: function(str)
21269     {
21270         if (!this.tab) {
21271             return;
21272         }
21273         this.title = str;
21274         this.tab.select('a', true).first().dom.innerHTML = str;
21275         
21276     }
21277     
21278     
21279     
21280 });
21281
21282  
21283
21284
21285  /*
21286  * - LGPL
21287  *
21288  * menu
21289  * 
21290  */
21291 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21292
21293 /**
21294  * @class Roo.bootstrap.menu.Menu
21295  * @extends Roo.bootstrap.Component
21296  * Bootstrap Menu class - container for Menu
21297  * @cfg {String} html Text of the menu
21298  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21299  * @cfg {String} icon Font awesome icon
21300  * @cfg {String} pos Menu align to (top | bottom) default bottom
21301  * 
21302  * 
21303  * @constructor
21304  * Create a new Menu
21305  * @param {Object} config The config object
21306  */
21307
21308
21309 Roo.bootstrap.menu.Menu = function(config){
21310     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21311     
21312     this.addEvents({
21313         /**
21314          * @event beforeshow
21315          * Fires before this menu is displayed
21316          * @param {Roo.bootstrap.menu.Menu} this
21317          */
21318         beforeshow : true,
21319         /**
21320          * @event beforehide
21321          * Fires before this menu is hidden
21322          * @param {Roo.bootstrap.menu.Menu} this
21323          */
21324         beforehide : true,
21325         /**
21326          * @event show
21327          * Fires after this menu is displayed
21328          * @param {Roo.bootstrap.menu.Menu} this
21329          */
21330         show : true,
21331         /**
21332          * @event hide
21333          * Fires after this menu is hidden
21334          * @param {Roo.bootstrap.menu.Menu} this
21335          */
21336         hide : true,
21337         /**
21338          * @event click
21339          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21340          * @param {Roo.bootstrap.menu.Menu} this
21341          * @param {Roo.EventObject} e
21342          */
21343         click : true
21344     });
21345     
21346 };
21347
21348 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21349     
21350     submenu : false,
21351     html : '',
21352     weight : 'default',
21353     icon : false,
21354     pos : 'bottom',
21355     
21356     
21357     getChildContainer : function() {
21358         if(this.isSubMenu){
21359             return this.el;
21360         }
21361         
21362         return this.el.select('ul.dropdown-menu', true).first();  
21363     },
21364     
21365     getAutoCreate : function()
21366     {
21367         var text = [
21368             {
21369                 tag : 'span',
21370                 cls : 'roo-menu-text',
21371                 html : this.html
21372             }
21373         ];
21374         
21375         if(this.icon){
21376             text.unshift({
21377                 tag : 'i',
21378                 cls : 'fa ' + this.icon
21379             })
21380         }
21381         
21382         
21383         var cfg = {
21384             tag : 'div',
21385             cls : 'btn-group',
21386             cn : [
21387                 {
21388                     tag : 'button',
21389                     cls : 'dropdown-button btn btn-' + this.weight,
21390                     cn : text
21391                 },
21392                 {
21393                     tag : 'button',
21394                     cls : 'dropdown-toggle btn btn-' + this.weight,
21395                     cn : [
21396                         {
21397                             tag : 'span',
21398                             cls : 'caret'
21399                         }
21400                     ]
21401                 },
21402                 {
21403                     tag : 'ul',
21404                     cls : 'dropdown-menu'
21405                 }
21406             ]
21407             
21408         };
21409         
21410         if(this.pos == 'top'){
21411             cfg.cls += ' dropup';
21412         }
21413         
21414         if(this.isSubMenu){
21415             cfg = {
21416                 tag : 'ul',
21417                 cls : 'dropdown-menu'
21418             }
21419         }
21420         
21421         return cfg;
21422     },
21423     
21424     onRender : function(ct, position)
21425     {
21426         this.isSubMenu = ct.hasClass('dropdown-submenu');
21427         
21428         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21429     },
21430     
21431     initEvents : function() 
21432     {
21433         if(this.isSubMenu){
21434             return;
21435         }
21436         
21437         this.hidden = true;
21438         
21439         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21440         this.triggerEl.on('click', this.onTriggerPress, this);
21441         
21442         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21443         this.buttonEl.on('click', this.onClick, this);
21444         
21445     },
21446     
21447     list : function()
21448     {
21449         if(this.isSubMenu){
21450             return this.el;
21451         }
21452         
21453         return this.el.select('ul.dropdown-menu', true).first();
21454     },
21455     
21456     onClick : function(e)
21457     {
21458         this.fireEvent("click", this, e);
21459     },
21460     
21461     onTriggerPress  : function(e)
21462     {   
21463         if (this.isVisible()) {
21464             this.hide();
21465         } else {
21466             this.show();
21467         }
21468     },
21469     
21470     isVisible : function(){
21471         return !this.hidden;
21472     },
21473     
21474     show : function()
21475     {
21476         this.fireEvent("beforeshow", this);
21477         
21478         this.hidden = false;
21479         this.el.addClass('open');
21480         
21481         Roo.get(document).on("mouseup", this.onMouseUp, this);
21482         
21483         this.fireEvent("show", this);
21484         
21485         
21486     },
21487     
21488     hide : function()
21489     {
21490         this.fireEvent("beforehide", this);
21491         
21492         this.hidden = true;
21493         this.el.removeClass('open');
21494         
21495         Roo.get(document).un("mouseup", this.onMouseUp);
21496         
21497         this.fireEvent("hide", this);
21498     },
21499     
21500     onMouseUp : function()
21501     {
21502         this.hide();
21503     }
21504     
21505 });
21506
21507  
21508  /*
21509  * - LGPL
21510  *
21511  * menu item
21512  * 
21513  */
21514 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21515
21516 /**
21517  * @class Roo.bootstrap.menu.Item
21518  * @extends Roo.bootstrap.Component
21519  * Bootstrap MenuItem class
21520  * @cfg {Boolean} submenu (true | false) default false
21521  * @cfg {String} html text of the item
21522  * @cfg {String} href the link
21523  * @cfg {Boolean} disable (true | false) default false
21524  * @cfg {Boolean} preventDefault (true | false) default true
21525  * @cfg {String} icon Font awesome icon
21526  * @cfg {String} pos Submenu align to (left | right) default right 
21527  * 
21528  * 
21529  * @constructor
21530  * Create a new Item
21531  * @param {Object} config The config object
21532  */
21533
21534
21535 Roo.bootstrap.menu.Item = function(config){
21536     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21537     this.addEvents({
21538         /**
21539          * @event mouseover
21540          * Fires when the mouse is hovering over this menu
21541          * @param {Roo.bootstrap.menu.Item} this
21542          * @param {Roo.EventObject} e
21543          */
21544         mouseover : true,
21545         /**
21546          * @event mouseout
21547          * Fires when the mouse exits this menu
21548          * @param {Roo.bootstrap.menu.Item} this
21549          * @param {Roo.EventObject} e
21550          */
21551         mouseout : true,
21552         // raw events
21553         /**
21554          * @event click
21555          * The raw click event for the entire grid.
21556          * @param {Roo.EventObject} e
21557          */
21558         click : true
21559     });
21560 };
21561
21562 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21563     
21564     submenu : false,
21565     href : '',
21566     html : '',
21567     preventDefault: true,
21568     disable : false,
21569     icon : false,
21570     pos : 'right',
21571     
21572     getAutoCreate : function()
21573     {
21574         var text = [
21575             {
21576                 tag : 'span',
21577                 cls : 'roo-menu-item-text',
21578                 html : this.html
21579             }
21580         ];
21581         
21582         if(this.icon){
21583             text.unshift({
21584                 tag : 'i',
21585                 cls : 'fa ' + this.icon
21586             })
21587         }
21588         
21589         var cfg = {
21590             tag : 'li',
21591             cn : [
21592                 {
21593                     tag : 'a',
21594                     href : this.href || '#',
21595                     cn : text
21596                 }
21597             ]
21598         };
21599         
21600         if(this.disable){
21601             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21602         }
21603         
21604         if(this.submenu){
21605             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21606             
21607             if(this.pos == 'left'){
21608                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21609             }
21610         }
21611         
21612         return cfg;
21613     },
21614     
21615     initEvents : function() 
21616     {
21617         this.el.on('mouseover', this.onMouseOver, this);
21618         this.el.on('mouseout', this.onMouseOut, this);
21619         
21620         this.el.select('a', true).first().on('click', this.onClick, this);
21621         
21622     },
21623     
21624     onClick : function(e)
21625     {
21626         if(this.preventDefault){
21627             e.preventDefault();
21628         }
21629         
21630         this.fireEvent("click", this, e);
21631     },
21632     
21633     onMouseOver : function(e)
21634     {
21635         if(this.submenu && this.pos == 'left'){
21636             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21637         }
21638         
21639         this.fireEvent("mouseover", this, e);
21640     },
21641     
21642     onMouseOut : function(e)
21643     {
21644         this.fireEvent("mouseout", this, e);
21645     }
21646 });
21647
21648  
21649
21650  /*
21651  * - LGPL
21652  *
21653  * menu separator
21654  * 
21655  */
21656 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21657
21658 /**
21659  * @class Roo.bootstrap.menu.Separator
21660  * @extends Roo.bootstrap.Component
21661  * Bootstrap Separator class
21662  * 
21663  * @constructor
21664  * Create a new Separator
21665  * @param {Object} config The config object
21666  */
21667
21668
21669 Roo.bootstrap.menu.Separator = function(config){
21670     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21671 };
21672
21673 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21674     
21675     getAutoCreate : function(){
21676         var cfg = {
21677             tag : 'li',
21678             cls: 'divider'
21679         };
21680         
21681         return cfg;
21682     }
21683    
21684 });
21685
21686  
21687
21688  /*
21689  * - LGPL
21690  *
21691  * Tooltip
21692  * 
21693  */
21694
21695 /**
21696  * @class Roo.bootstrap.Tooltip
21697  * Bootstrap Tooltip class
21698  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21699  * to determine which dom element triggers the tooltip.
21700  * 
21701  * It needs to add support for additional attributes like tooltip-position
21702  * 
21703  * @constructor
21704  * Create a new Toolti
21705  * @param {Object} config The config object
21706  */
21707
21708 Roo.bootstrap.Tooltip = function(config){
21709     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21710 };
21711
21712 Roo.apply(Roo.bootstrap.Tooltip, {
21713     /**
21714      * @function init initialize tooltip monitoring.
21715      * @static
21716      */
21717     currentEl : false,
21718     currentTip : false,
21719     currentRegion : false,
21720     
21721     //  init : delay?
21722     
21723     init : function()
21724     {
21725         Roo.get(document).on('mouseover', this.enter ,this);
21726         Roo.get(document).on('mouseout', this.leave, this);
21727          
21728         
21729         this.currentTip = new Roo.bootstrap.Tooltip();
21730     },
21731     
21732     enter : function(ev)
21733     {
21734         var dom = ev.getTarget();
21735         //Roo.log(['enter',dom]);
21736         var el = Roo.fly(dom);
21737         if (this.currentEl) {
21738             //Roo.log(dom);
21739             //Roo.log(this.currentEl);
21740             //Roo.log(this.currentEl.contains(dom));
21741             if (this.currentEl == el) {
21742                 return;
21743             }
21744             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21745                 return;
21746             }
21747
21748         }
21749         
21750         
21751         
21752         if (this.currentTip.el) {
21753             this.currentTip.el.hide(); // force hiding...
21754         }    
21755         //Roo.log(el);
21756         if (!el.attr('tooltip')) { // parents who have tip?
21757             return;
21758         }
21759         this.currentEl = el;
21760         this.currentTip.bind(el);
21761         this.currentRegion = Roo.lib.Region.getRegion(dom);
21762         this.currentTip.enter();
21763         
21764     },
21765     leave : function(ev)
21766     {
21767         var dom = ev.getTarget();
21768         //Roo.log(['leave',dom]);
21769         if (!this.currentEl) {
21770             return;
21771         }
21772         
21773         
21774         if (dom != this.currentEl.dom) {
21775             return;
21776         }
21777         var xy = ev.getXY();
21778         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21779             return;
21780         }
21781         // only activate leave if mouse cursor is outside... bounding box..
21782         
21783         
21784         
21785         
21786         if (this.currentTip) {
21787             this.currentTip.leave();
21788         }
21789         //Roo.log('clear currentEl');
21790         this.currentEl = false;
21791         
21792         
21793     },
21794     alignment : {
21795         'left' : ['r-l', [-2,0], 'right'],
21796         'right' : ['l-r', [2,0], 'left'],
21797         'bottom' : ['t-b', [0,2], 'top'],
21798         'top' : [ 'b-t', [0,-2], 'bottom']
21799     }
21800     
21801 });
21802
21803
21804 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21805     
21806     
21807     bindEl : false,
21808     
21809     delay : null, // can be { show : 300 , hide: 500}
21810     
21811     timeout : null,
21812     
21813     hoverState : null, //???
21814     
21815     placement : 'bottom', 
21816     
21817     getAutoCreate : function(){
21818     
21819         var cfg = {
21820            cls : 'tooltip',
21821            role : 'tooltip',
21822            cn : [
21823                 {
21824                     cls : 'tooltip-arrow'
21825                 },
21826                 {
21827                     cls : 'tooltip-inner'
21828                 }
21829            ]
21830         };
21831         
21832         return cfg;
21833     },
21834     bind : function(el)
21835     {
21836         this.bindEl = el;
21837     },
21838       
21839     
21840     enter : function () {
21841        
21842         if (this.timeout != null) {
21843             clearTimeout(this.timeout);
21844         }
21845         
21846         this.hoverState = 'in';
21847          //Roo.log("enter - show");
21848         if (!this.delay || !this.delay.show) {
21849             this.show();
21850             return;
21851         }
21852         var _t = this;
21853         this.timeout = setTimeout(function () {
21854             if (_t.hoverState == 'in') {
21855                 _t.show();
21856             }
21857         }, this.delay.show);
21858     },
21859     leave : function()
21860     {
21861         clearTimeout(this.timeout);
21862     
21863         this.hoverState = 'out';
21864          if (!this.delay || !this.delay.hide) {
21865             this.hide();
21866             return 
21867         }
21868        
21869         var _t = this;
21870         this.timeout = setTimeout(function () {
21871             //Roo.log("leave - timeout");
21872             
21873             if (_t.hoverState == 'out') {
21874                 _t.hide();
21875                 Roo.bootstrap.Tooltip.currentEl = false;
21876             }
21877         }, delay)
21878     },
21879     
21880     show : function ()
21881     {
21882         if (!this.el) {
21883             this.render(document.body);
21884         }
21885         // set content.
21886         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21887         this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21888         
21889         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21890         
21891         var placement = typeof this.placement == 'function' ?
21892             this.placement.call(this, this.el, on_el) :
21893             this.placement;
21894             
21895         var autoToken = /\s?auto?\s?/i;
21896         var autoPlace = autoToken.test(placement);
21897         if (autoPlace) {
21898             placement = placement.replace(autoToken, '') || 'top';
21899         }
21900         
21901         //this.el.detach()
21902         //this.el.setXY([0,0]);
21903         this.el.show();
21904         //this.el.dom.style.display='block';
21905         this.el.addClass(placement);
21906         
21907         //this.el.appendTo(on_el);
21908         
21909         var p = this.getPosition();
21910         var box = this.el.getBox();
21911         
21912         if (autoPlace) {
21913             // fixme..
21914         }
21915         var align = Roo.bootstrap.Tooltip.alignment[placement];
21916         this.el.alignTo(this.bindEl, align[0],align[1]);
21917         //var arrow = this.el.select('.arrow',true).first();
21918         //arrow.set(align[2], 
21919         
21920         this.el.addClass('in fade');
21921         this.hoverState = null;
21922         
21923         if (this.el.hasClass('fade')) {
21924             // fade it?
21925         }
21926         
21927     },
21928     hide : function()
21929     {
21930          
21931         if (!this.el) {
21932             return;
21933         }
21934         //this.el.setXY([0,0]);
21935         this.el.removeClass('in');
21936         //this.el.hide();
21937         
21938     }
21939     
21940 });
21941  
21942
21943  /*
21944  * - LGPL
21945  *
21946  * Location Picker
21947  * 
21948  */
21949
21950 /**
21951  * @class Roo.bootstrap.LocationPicker
21952  * @extends Roo.bootstrap.Component
21953  * Bootstrap LocationPicker class
21954  * @cfg {Number} latitude Position when init default 0
21955  * @cfg {Number} longitude Position when init default 0
21956  * @cfg {Number} zoom default 15
21957  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21958  * @cfg {Boolean} mapTypeControl default false
21959  * @cfg {Boolean} disableDoubleClickZoom default false
21960  * @cfg {Boolean} scrollwheel default true
21961  * @cfg {Boolean} streetViewControl default false
21962  * @cfg {Number} radius default 0
21963  * @cfg {String} locationName
21964  * @cfg {Boolean} draggable default true
21965  * @cfg {Boolean} enableAutocomplete default false
21966  * @cfg {Boolean} enableReverseGeocode default true
21967  * @cfg {String} markerTitle
21968  * 
21969  * @constructor
21970  * Create a new LocationPicker
21971  * @param {Object} config The config object
21972  */
21973
21974
21975 Roo.bootstrap.LocationPicker = function(config){
21976     
21977     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21978     
21979     this.addEvents({
21980         /**
21981          * @event initial
21982          * Fires when the picker initialized.
21983          * @param {Roo.bootstrap.LocationPicker} this
21984          * @param {Google Location} location
21985          */
21986         initial : true,
21987         /**
21988          * @event positionchanged
21989          * Fires when the picker position changed.
21990          * @param {Roo.bootstrap.LocationPicker} this
21991          * @param {Google Location} location
21992          */
21993         positionchanged : true,
21994         /**
21995          * @event resize
21996          * Fires when the map resize.
21997          * @param {Roo.bootstrap.LocationPicker} this
21998          */
21999         resize : true,
22000         /**
22001          * @event show
22002          * Fires when the map show.
22003          * @param {Roo.bootstrap.LocationPicker} this
22004          */
22005         show : true,
22006         /**
22007          * @event hide
22008          * Fires when the map hide.
22009          * @param {Roo.bootstrap.LocationPicker} this
22010          */
22011         hide : true,
22012         /**
22013          * @event mapClick
22014          * Fires when click the map.
22015          * @param {Roo.bootstrap.LocationPicker} this
22016          * @param {Map event} e
22017          */
22018         mapClick : true,
22019         /**
22020          * @event mapRightClick
22021          * Fires when right click the map.
22022          * @param {Roo.bootstrap.LocationPicker} this
22023          * @param {Map event} e
22024          */
22025         mapRightClick : true,
22026         /**
22027          * @event markerClick
22028          * Fires when click the marker.
22029          * @param {Roo.bootstrap.LocationPicker} this
22030          * @param {Map event} e
22031          */
22032         markerClick : true,
22033         /**
22034          * @event markerRightClick
22035          * Fires when right click the marker.
22036          * @param {Roo.bootstrap.LocationPicker} this
22037          * @param {Map event} e
22038          */
22039         markerRightClick : true,
22040         /**
22041          * @event OverlayViewDraw
22042          * Fires when OverlayView Draw
22043          * @param {Roo.bootstrap.LocationPicker} this
22044          */
22045         OverlayViewDraw : true,
22046         /**
22047          * @event OverlayViewOnAdd
22048          * Fires when OverlayView Draw
22049          * @param {Roo.bootstrap.LocationPicker} this
22050          */
22051         OverlayViewOnAdd : true,
22052         /**
22053          * @event OverlayViewOnRemove
22054          * Fires when OverlayView Draw
22055          * @param {Roo.bootstrap.LocationPicker} this
22056          */
22057         OverlayViewOnRemove : true,
22058         /**
22059          * @event OverlayViewShow
22060          * Fires when OverlayView Draw
22061          * @param {Roo.bootstrap.LocationPicker} this
22062          * @param {Pixel} cpx
22063          */
22064         OverlayViewShow : true,
22065         /**
22066          * @event OverlayViewHide
22067          * Fires when OverlayView Draw
22068          * @param {Roo.bootstrap.LocationPicker} this
22069          */
22070         OverlayViewHide : true
22071     });
22072         
22073 };
22074
22075 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22076     
22077     gMapContext: false,
22078     
22079     latitude: 0,
22080     longitude: 0,
22081     zoom: 15,
22082     mapTypeId: false,
22083     mapTypeControl: false,
22084     disableDoubleClickZoom: false,
22085     scrollwheel: true,
22086     streetViewControl: false,
22087     radius: 0,
22088     locationName: '',
22089     draggable: true,
22090     enableAutocomplete: false,
22091     enableReverseGeocode: true,
22092     markerTitle: '',
22093     
22094     getAutoCreate: function()
22095     {
22096
22097         var cfg = {
22098             tag: 'div',
22099             cls: 'roo-location-picker'
22100         };
22101         
22102         return cfg
22103     },
22104     
22105     initEvents: function(ct, position)
22106     {       
22107         if(!this.el.getWidth() || this.isApplied()){
22108             return;
22109         }
22110         
22111         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22112         
22113         this.initial();
22114     },
22115     
22116     initial: function()
22117     {
22118         if(!this.mapTypeId){
22119             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22120         }
22121         
22122         this.gMapContext = this.GMapContext();
22123         
22124         this.initOverlayView();
22125         
22126         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22127         
22128         var _this = this;
22129                 
22130         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22131             _this.setPosition(_this.gMapContext.marker.position);
22132         });
22133         
22134         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22135             _this.fireEvent('mapClick', this, event);
22136             
22137         });
22138
22139         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22140             _this.fireEvent('mapRightClick', this, event);
22141             
22142         });
22143         
22144         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22145             _this.fireEvent('markerClick', this, event);
22146             
22147         });
22148
22149         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22150             _this.fireEvent('markerRightClick', this, event);
22151             
22152         });
22153         
22154         this.setPosition(this.gMapContext.location);
22155         
22156         this.fireEvent('initial', this, this.gMapContext.location);
22157     },
22158     
22159     initOverlayView: function()
22160     {
22161         var _this = this;
22162         
22163         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22164             
22165             draw: function()
22166             {
22167                 _this.fireEvent('OverlayViewDraw', _this);
22168             },
22169             
22170             onAdd: function()
22171             {
22172                 _this.fireEvent('OverlayViewOnAdd', _this);
22173             },
22174             
22175             onRemove: function()
22176             {
22177                 _this.fireEvent('OverlayViewOnRemove', _this);
22178             },
22179             
22180             show: function(cpx)
22181             {
22182                 _this.fireEvent('OverlayViewShow', _this, cpx);
22183             },
22184             
22185             hide: function()
22186             {
22187                 _this.fireEvent('OverlayViewHide', _this);
22188             }
22189             
22190         });
22191     },
22192     
22193     fromLatLngToContainerPixel: function(event)
22194     {
22195         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22196     },
22197     
22198     isApplied: function() 
22199     {
22200         return this.getGmapContext() == false ? false : true;
22201     },
22202     
22203     getGmapContext: function() 
22204     {
22205         return this.gMapContext
22206     },
22207     
22208     GMapContext: function() 
22209     {
22210         var position = new google.maps.LatLng(this.latitude, this.longitude);
22211         
22212         var _map = new google.maps.Map(this.el.dom, {
22213             center: position,
22214             zoom: this.zoom,
22215             mapTypeId: this.mapTypeId,
22216             mapTypeControl: this.mapTypeControl,
22217             disableDoubleClickZoom: this.disableDoubleClickZoom,
22218             scrollwheel: this.scrollwheel,
22219             streetViewControl: this.streetViewControl,
22220             locationName: this.locationName,
22221             draggable: this.draggable,
22222             enableAutocomplete: this.enableAutocomplete,
22223             enableReverseGeocode: this.enableReverseGeocode
22224         });
22225         
22226         var _marker = new google.maps.Marker({
22227             position: position,
22228             map: _map,
22229             title: this.markerTitle,
22230             draggable: this.draggable
22231         });
22232         
22233         return {
22234             map: _map,
22235             marker: _marker,
22236             circle: null,
22237             location: position,
22238             radius: this.radius,
22239             locationName: this.locationName,
22240             addressComponents: {
22241                 formatted_address: null,
22242                 addressLine1: null,
22243                 addressLine2: null,
22244                 streetName: null,
22245                 streetNumber: null,
22246                 city: null,
22247                 district: null,
22248                 state: null,
22249                 stateOrProvince: null
22250             },
22251             settings: this,
22252             domContainer: this.el.dom,
22253             geodecoder: new google.maps.Geocoder()
22254         };
22255     },
22256     
22257     drawCircle: function(center, radius, options) 
22258     {
22259         if (this.gMapContext.circle != null) {
22260             this.gMapContext.circle.setMap(null);
22261         }
22262         if (radius > 0) {
22263             radius *= 1;
22264             options = Roo.apply({}, options, {
22265                 strokeColor: "#0000FF",
22266                 strokeOpacity: .35,
22267                 strokeWeight: 2,
22268                 fillColor: "#0000FF",
22269                 fillOpacity: .2
22270             });
22271             
22272             options.map = this.gMapContext.map;
22273             options.radius = radius;
22274             options.center = center;
22275             this.gMapContext.circle = new google.maps.Circle(options);
22276             return this.gMapContext.circle;
22277         }
22278         
22279         return null;
22280     },
22281     
22282     setPosition: function(location) 
22283     {
22284         this.gMapContext.location = location;
22285         this.gMapContext.marker.setPosition(location);
22286         this.gMapContext.map.panTo(location);
22287         this.drawCircle(location, this.gMapContext.radius, {});
22288         
22289         var _this = this;
22290         
22291         if (this.gMapContext.settings.enableReverseGeocode) {
22292             this.gMapContext.geodecoder.geocode({
22293                 latLng: this.gMapContext.location
22294             }, function(results, status) {
22295                 
22296                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22297                     _this.gMapContext.locationName = results[0].formatted_address;
22298                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22299                     
22300                     _this.fireEvent('positionchanged', this, location);
22301                 }
22302             });
22303             
22304             return;
22305         }
22306         
22307         this.fireEvent('positionchanged', this, location);
22308     },
22309     
22310     resize: function()
22311     {
22312         google.maps.event.trigger(this.gMapContext.map, "resize");
22313         
22314         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22315         
22316         this.fireEvent('resize', this);
22317     },
22318     
22319     setPositionByLatLng: function(latitude, longitude)
22320     {
22321         this.setPosition(new google.maps.LatLng(latitude, longitude));
22322     },
22323     
22324     getCurrentPosition: function() 
22325     {
22326         return {
22327             latitude: this.gMapContext.location.lat(),
22328             longitude: this.gMapContext.location.lng()
22329         };
22330     },
22331     
22332     getAddressName: function() 
22333     {
22334         return this.gMapContext.locationName;
22335     },
22336     
22337     getAddressComponents: function() 
22338     {
22339         return this.gMapContext.addressComponents;
22340     },
22341     
22342     address_component_from_google_geocode: function(address_components) 
22343     {
22344         var result = {};
22345         
22346         for (var i = 0; i < address_components.length; i++) {
22347             var component = address_components[i];
22348             if (component.types.indexOf("postal_code") >= 0) {
22349                 result.postalCode = component.short_name;
22350             } else if (component.types.indexOf("street_number") >= 0) {
22351                 result.streetNumber = component.short_name;
22352             } else if (component.types.indexOf("route") >= 0) {
22353                 result.streetName = component.short_name;
22354             } else if (component.types.indexOf("neighborhood") >= 0) {
22355                 result.city = component.short_name;
22356             } else if (component.types.indexOf("locality") >= 0) {
22357                 result.city = component.short_name;
22358             } else if (component.types.indexOf("sublocality") >= 0) {
22359                 result.district = component.short_name;
22360             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22361                 result.stateOrProvince = component.short_name;
22362             } else if (component.types.indexOf("country") >= 0) {
22363                 result.country = component.short_name;
22364             }
22365         }
22366         
22367         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22368         result.addressLine2 = "";
22369         return result;
22370     },
22371     
22372     setZoomLevel: function(zoom)
22373     {
22374         this.gMapContext.map.setZoom(zoom);
22375     },
22376     
22377     show: function()
22378     {
22379         if(!this.el){
22380             return;
22381         }
22382         
22383         this.el.show();
22384         
22385         this.resize();
22386         
22387         this.fireEvent('show', this);
22388     },
22389     
22390     hide: function()
22391     {
22392         if(!this.el){
22393             return;
22394         }
22395         
22396         this.el.hide();
22397         
22398         this.fireEvent('hide', this);
22399     }
22400     
22401 });
22402
22403 Roo.apply(Roo.bootstrap.LocationPicker, {
22404     
22405     OverlayView : function(map, options)
22406     {
22407         options = options || {};
22408         
22409         this.setMap(map);
22410     }
22411     
22412     
22413 });/*
22414  * - LGPL
22415  *
22416  * Alert
22417  * 
22418  */
22419
22420 /**
22421  * @class Roo.bootstrap.Alert
22422  * @extends Roo.bootstrap.Component
22423  * Bootstrap Alert class
22424  * @cfg {String} title The title of alert
22425  * @cfg {String} html The content of alert
22426  * @cfg {String} weight (  success | info | warning | danger )
22427  * @cfg {String} faicon font-awesomeicon
22428  * 
22429  * @constructor
22430  * Create a new alert
22431  * @param {Object} config The config object
22432  */
22433
22434
22435 Roo.bootstrap.Alert = function(config){
22436     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22437     
22438 };
22439
22440 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22441     
22442     title: '',
22443     html: '',
22444     weight: false,
22445     faicon: false,
22446     
22447     getAutoCreate : function()
22448     {
22449         
22450         var cfg = {
22451             tag : 'div',
22452             cls : 'alert',
22453             cn : [
22454                 {
22455                     tag : 'i',
22456                     cls : 'roo-alert-icon'
22457                     
22458                 },
22459                 {
22460                     tag : 'b',
22461                     cls : 'roo-alert-title',
22462                     html : this.title
22463                 },
22464                 {
22465                     tag : 'span',
22466                     cls : 'roo-alert-text',
22467                     html : this.html
22468                 }
22469             ]
22470         };
22471         
22472         if(this.faicon){
22473             cfg.cn[0].cls += ' fa ' + this.faicon;
22474         }
22475         
22476         if(this.weight){
22477             cfg.cls += ' alert-' + this.weight;
22478         }
22479         
22480         return cfg;
22481     },
22482     
22483     initEvents: function() 
22484     {
22485         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22486     },
22487     
22488     setTitle : function(str)
22489     {
22490         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22491     },
22492     
22493     setText : function(str)
22494     {
22495         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22496     },
22497     
22498     setWeight : function(weight)
22499     {
22500         if(this.weight){
22501             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22502         }
22503         
22504         this.weight = weight;
22505         
22506         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22507     },
22508     
22509     setIcon : function(icon)
22510     {
22511         if(this.faicon){
22512             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22513         }
22514         
22515         this.faicon = icon
22516         
22517         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22518     },
22519     
22520     hide: function() 
22521     {
22522         this.el.hide();   
22523     },
22524     
22525     show: function() 
22526     {  
22527         this.el.show();   
22528     }
22529     
22530 });
22531
22532