Roo/bootstrap/Popover.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 };
32
33 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
34     
35     
36     allowDomMove : false, // to stop relocations in parent onRender...
37     
38     cls : false,
39     
40     style : false,
41     
42     autoCreate : false,
43     
44     tooltip : null,
45     /**
46      * Initialize Events for the element
47      */
48     initEvents : function() { },
49     
50     xattr : false,
51     
52     parentId : false,
53     
54     can_build_overlaid : true,
55     
56     container_method : false,
57     
58     dataId : false,
59     
60     name : false,
61     
62     parent: function() {
63         // returns the parent component..
64         return Roo.ComponentMgr.get(this.parentId)
65         
66         
67     },
68     
69     // private
70     onRender : function(ct, position)
71     {
72        // Roo.log("Call onRender: " + this.xtype);
73         
74         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
75         
76         if(this.el){
77             if (this.el.attr('xtype')) {
78                 this.el.attr('xtypex', this.el.attr('xtype'));
79                 this.el.dom.removeAttribute('xtype');
80                 
81                 this.initEvents();
82             }
83             
84             return;
85         }
86         
87          
88         
89         var cfg = Roo.apply({},  this.getAutoCreate());
90         cfg.id = Roo.id();
91         
92         // fill in the extra attributes 
93         if (this.xattr && typeof(this.xattr) =='object') {
94             for (var i in this.xattr) {
95                 cfg[i] = this.xattr[i];
96             }
97         }
98         
99         if(this.dataId){
100             cfg.dataId = this.dataId;
101         }
102         
103         if (this.cls) {
104             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
105         }
106         
107         if (this.style) { // fixme needs to support more complex style data.
108             cfg.style = this.style;
109         }
110         
111         if(this.name){
112             cfg.name = this.name;
113         }
114         
115        
116         
117         this.el = ct.createChild(cfg, position);
118         
119         if (this.tooltip) {
120             this.tooltipEl().attr('tooltip', this.tooltip);
121         }
122         
123         if(this.tabIndex !== undefined){
124             this.el.dom.setAttribute('tabIndex', this.tabIndex);
125         }
126         this.initEvents();
127         
128         
129     },
130     /**
131      * Fetch the element to add children to
132      * @return {Roo.Element} defaults to this.el
133      */
134     getChildContainer : function()
135     {
136         return this.el;
137     },
138     /**
139      * Fetch the element to display the tooltip on.
140      * @return {Roo.Element} defaults to this.el
141      */
142     tooltipEl : function()
143     {
144         return this.el;
145     },
146         
147     addxtype  : function(tree,cntr)
148     {
149         var cn = this;
150         
151         cn = Roo.factory(tree);
152            
153         cn.parentType = this.xtype; //??
154         cn.parentId = this.id;
155         
156         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
157         if (typeof(cn.container_method) == 'string') {
158             cntr = cn.container_method;
159         }
160         
161         
162         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
163         
164         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
165         
166         var build_from_html =  Roo.XComponent.build_from_html;
167           
168         var is_body  = (tree.xtype == 'Body') ;
169           
170         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
171           
172         var self_cntr_el = Roo.get(this[cntr](false));
173         
174         // do not try and build conditional elements 
175         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
176             return false;
177         }
178         
179         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
180             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
181                 return this.addxtypeChild(tree,cntr);
182             }
183             
184             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
185                 
186             if(echild){
187                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
188             }
189             
190             Roo.log('skipping render');
191             return cn;
192             
193         }
194         
195         var ret = false;
196         
197         while (true) {
198             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
199             
200             if (!echild) {
201                 break;
202             }
203             
204             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
205                 break;
206             }
207             
208             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
209         }
210         return ret;
211     },
212     
213     addxtypeChild : function (tree, cntr)
214     {
215         Roo.debug && Roo.log('addxtypeChild:' + cntr);
216         var cn = this;
217         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
218         
219         
220         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
221                     (typeof(tree['flexy:foreach']) != 'undefined');
222           
223         
224         
225          skip_children = false;
226         // render the element if it's not BODY.
227         if (tree.xtype != 'Body') {
228            
229             cn = Roo.factory(tree);
230            
231             cn.parentType = this.xtype; //??
232             cn.parentId = this.id;
233             
234             var build_from_html =  Roo.XComponent.build_from_html;
235             
236             
237             // does the container contain child eleemnts with 'xtype' attributes.
238             // that match this xtype..
239             // note - when we render we create these as well..
240             // so we should check to see if body has xtype set.
241             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
242                
243                 var self_cntr_el = Roo.get(this[cntr](false));
244                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
245                 
246                 
247                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
248                 // and are not displayed -this causes this to use up the wrong element when matching.
249                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
250                 
251                 
252                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
253                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
254                   
255                   
256                   
257                     cn.el = echild;
258                   //  Roo.log("GOT");
259                     //echild.dom.removeAttribute('xtype');
260                 } else {
261                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
262                     Roo.debug && Roo.log(self_cntr_el);
263                     Roo.debug && Roo.log(echild);
264                     Roo.debug && Roo.log(cn);
265                 }
266             }
267            
268             
269            
270             // if object has flexy:if - then it may or may not be rendered.
271             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
272                 // skip a flexy if element.
273                 Roo.debug && Roo.log('skipping render');
274                 Roo.debug && Roo.log(tree);
275                 if (!cn.el) {
276                     Roo.debug && Roo.log('skipping all children');
277                     skip_children = true;
278                 }
279                 
280              } else {
281                  
282                 // actually if flexy:foreach is found, we really want to create 
283                 // multiple copies here...
284                 //Roo.log('render');
285                 //Roo.log(this[cntr]());
286                 cn.render(this[cntr](true));
287              }
288             // then add the element..
289         }
290         
291         
292         // handle the kids..
293         
294         var nitems = [];
295         /*
296         if (typeof (tree.menu) != 'undefined') {
297             tree.menu.parentType = cn.xtype;
298             tree.menu.triggerEl = cn.el;
299             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
300             
301         }
302         */
303         if (!tree.items || !tree.items.length) {
304             cn.items = nitems;
305             return cn;
306         }
307         var items = tree.items;
308         delete tree.items;
309         
310         //Roo.log(items.length);
311             // add the items..
312         if (!skip_children) {    
313             for(var i =0;i < items.length;i++) {
314                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
315             }
316         }
317         
318         cn.items = nitems;
319         
320         return cn;
321     }
322     
323     
324     
325     
326 });
327
328  /*
329  * - LGPL
330  *
331  * Body
332  * 
333  */
334
335 /**
336  * @class Roo.bootstrap.Body
337  * @extends Roo.bootstrap.Component
338  * Bootstrap Body class
339  * 
340  * @constructor
341  * Create a new body
342  * @param {Object} config The config object
343  */
344
345 Roo.bootstrap.Body = function(config){
346     Roo.bootstrap.Body.superclass.constructor.call(this, config);
347     this.el = Roo.get(document.body);
348     if (this.cls && this.cls.length) {
349         Roo.get(document.body).addClass(this.cls);
350     }
351 };
352
353 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
354       
355         autoCreate : {
356         cls: 'container'
357     },
358     onRender : function(ct, position)
359     {
360        /* Roo.log("Roo.bootstrap.Body - onRender");
361         if (this.cls && this.cls.length) {
362             Roo.get(document.body).addClass(this.cls);
363         }
364         // style??? xttr???
365         */
366     }
367     
368     
369  
370    
371 });
372
373  /*
374  * - LGPL
375  *
376  * button group
377  * 
378  */
379
380
381 /**
382  * @class Roo.bootstrap.ButtonGroup
383  * @extends Roo.bootstrap.Component
384  * Bootstrap ButtonGroup class
385  * @cfg {String} size lg | sm | xs (default empty normal)
386  * @cfg {String} align vertical | justified  (default none)
387  * @cfg {String} direction up | down (default down)
388  * @cfg {Boolean} toolbar false | true
389  * @cfg {Boolean} btn true | false
390  * 
391  * 
392  * @constructor
393  * Create a new Input
394  * @param {Object} config The config object
395  */
396
397 Roo.bootstrap.ButtonGroup = function(config){
398     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
399 };
400
401 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
402     
403     size: '',
404     align: '',
405     direction: '',
406     toolbar: false,
407     btn: true,
408
409     getAutoCreate : function(){
410         var cfg = {
411             cls: 'btn-group',
412             html : null
413         }
414         
415         cfg.html = this.html || cfg.html;
416         
417         if (this.toolbar) {
418             cfg = {
419                 cls: 'btn-toolbar',
420                 html: null
421             }
422             
423             return cfg;
424         }
425         
426         if (['vertical','justified'].indexOf(this.align)!==-1) {
427             cfg.cls = 'btn-group-' + this.align;
428             
429             if (this.align == 'justified') {
430                 console.log(this.items);
431             }
432         }
433         
434         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
435             cfg.cls += ' btn-group-' + this.size;
436         }
437         
438         if (this.direction == 'up') {
439             cfg.cls += ' dropup' ;
440         }
441         
442         return cfg;
443     }
444    
445 });
446
447  /*
448  * - LGPL
449  *
450  * button
451  * 
452  */
453
454 /**
455  * @class Roo.bootstrap.Button
456  * @extends Roo.bootstrap.Component
457  * Bootstrap Button class
458  * @cfg {String} html The button content
459  * @cfg {String} weight (  primary | success | info | warning | danger | link ) default 
460  * @cfg {String} size ( lg | sm | xs)
461  * @cfg {String} tag ( a | input | submit)
462  * @cfg {String} href empty or href
463  * @cfg {Boolean} disabled default false;
464  * @cfg {Boolean} isClose default false;
465  * @cfg {String} glyphicon (| adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out)
466  * @cfg {String} badge text for badge
467  * @cfg {String} theme default 
468  * @cfg {Boolean} inverse 
469  * @cfg {Boolean} toggle 
470  * @cfg {String} ontext text for on toggle state
471  * @cfg {String} offtext text for off toggle state
472  * @cfg {Boolean} defaulton 
473  * @cfg {Boolean} preventDefault  default true
474  * @cfg {Boolean} removeClass remove the standard class..
475  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
476  * 
477  * @constructor
478  * Create a new button
479  * @param {Object} config The config object
480  */
481
482
483 Roo.bootstrap.Button = function(config){
484     Roo.bootstrap.Button.superclass.constructor.call(this, config);
485     this.addEvents({
486         // raw events
487         /**
488          * @event click
489          * When a butotn is pressed
490          * @param {Roo.EventObject} e
491          */
492         "click" : true,
493          /**
494          * @event toggle
495          * After the button has been toggles
496          * @param {Roo.EventObject} e
497          * @param {boolean} pressed (also available as button.pressed)
498          */
499         "toggle" : true
500     });
501 };
502
503 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
504     html: false,
505     active: false,
506     weight: '',
507     size: '',
508     tag: 'button',
509     href: '',
510     disabled: false,
511     isClose: false,
512     glyphicon: '',
513     badge: '',
514     theme: 'default',
515     inverse: false,
516     
517     toggle: false,
518     ontext: 'ON',
519     offtext: 'OFF',
520     defaulton: true,
521     preventDefault: true,
522     removeClass: false,
523     name: false,
524     target: false,
525     
526     
527     pressed : null,
528      
529     
530     getAutoCreate : function(){
531         
532         var cfg = {
533             tag : 'button',
534             cls : 'roo-button',
535             html: ''
536         };
537         
538         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
539             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
540             this.tag = 'button';
541         } else {
542             cfg.tag = this.tag;
543         }
544         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
545         
546         if (this.toggle == true) {
547             cfg={
548                 tag: 'div',
549                 cls: 'slider-frame roo-button',
550                 cn: [
551                     {
552                         tag: 'span',
553                         'data-on-text':'ON',
554                         'data-off-text':'OFF',
555                         cls: 'slider-button',
556                         html: this.offtext
557                     }
558                 ]
559             };
560             
561             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
562                 cfg.cls += ' '+this.weight;
563             }
564             
565             return cfg;
566         }
567         
568         if (this.isClose) {
569             cfg.cls += ' close';
570             
571             cfg["aria-hidden"] = true;
572             
573             cfg.html = "&times;";
574             
575             return cfg;
576         }
577         
578          
579         if (this.theme==='default') {
580             cfg.cls = 'btn roo-button';
581             
582             //if (this.parentType != 'Navbar') {
583             this.weight = this.weight.length ?  this.weight : 'default';
584             //}
585             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
586                 
587                 cfg.cls += ' btn-' + this.weight;
588             }
589         } else if (this.theme==='glow') {
590             
591             cfg.tag = 'a';
592             cfg.cls = 'btn-glow roo-button';
593             
594             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
595                 
596                 cfg.cls += ' ' + this.weight;
597             }
598         }
599    
600         
601         if (this.inverse) {
602             this.cls += ' inverse';
603         }
604         
605         
606         if (this.active) {
607             cfg.cls += ' active';
608         }
609         
610         if (this.disabled) {
611             cfg.disabled = 'disabled';
612         }
613         
614         if (this.items) {
615             Roo.log('changing to ul' );
616             cfg.tag = 'ul';
617             this.glyphicon = 'caret';
618         }
619         
620         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
621          
622         //gsRoo.log(this.parentType);
623         if (this.parentType === 'Navbar' && !this.parent().bar) {
624             Roo.log('changing to li?');
625             
626             cfg.tag = 'li';
627             
628             cfg.cls = '';
629             cfg.cn =  [{
630                 tag : 'a',
631                 cls : 'roo-button',
632                 html : this.html,
633                 href : this.href || '#'
634             }];
635             if (this.menu) {
636                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
637                 cfg.cls += ' dropdown';
638             }   
639             
640             delete cfg.html;
641             
642         }
643         
644        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
645         
646         if (this.glyphicon) {
647             cfg.html = ' ' + cfg.html;
648             
649             cfg.cn = [
650                 {
651                     tag: 'span',
652                     cls: 'glyphicon glyphicon-' + this.glyphicon
653                 }
654             ];
655         }
656         
657         if (this.badge) {
658             cfg.html += ' ';
659             
660             cfg.tag = 'a';
661             
662 //            cfg.cls='btn roo-button';
663             
664             cfg.href=this.href;
665             
666             var value = cfg.html;
667             
668             if(this.glyphicon){
669                 value = {
670                             tag: 'span',
671                             cls: 'glyphicon glyphicon-' + this.glyphicon,
672                             html: this.html
673                         };
674                 
675             }
676             
677             cfg.cn = [
678                 value,
679                 {
680                     tag: 'span',
681                     cls: 'badge',
682                     html: this.badge
683                 }
684             ];
685             
686             cfg.html='';
687         }
688         
689         if (this.menu) {
690             cfg.cls += ' dropdown';
691             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
692         }
693         
694         if (cfg.tag !== 'a' && this.href !== '') {
695             throw "Tag must be a to set href.";
696         } else if (this.href.length > 0) {
697             cfg.href = this.href;
698         }
699         
700         if(this.removeClass){
701             cfg.cls = '';
702         }
703         
704         if(this.target){
705             cfg.target = this.target;
706         }
707         
708         return cfg;
709     },
710     initEvents: function() {
711        // Roo.log('init events?');
712 //        Roo.log(this.el.dom);
713         // add the menu...
714         
715         if (typeof (this.menu) != 'undefined') {
716             this.menu.parentType = this.xtype;
717             this.menu.triggerEl = this.el;
718             this.addxtype(Roo.apply({}, this.menu));
719         }
720
721
722        if (this.el.hasClass('roo-button')) {
723             this.el.on('click', this.onClick, this);
724        } else {
725             this.el.select('.roo-button').on('click', this.onClick, this);
726        }
727        
728        if(this.removeClass){
729            this.el.on('click', this.onClick, this);
730        }
731        
732        this.el.enableDisplayMode();
733         
734     },
735     onClick : function(e)
736     {
737         if (this.disabled) {
738             return;
739         }
740         
741         
742         Roo.log('button on click ');
743         if(this.preventDefault){
744             e.preventDefault();
745         }
746         if (this.pressed === true || this.pressed === false) {
747             this.pressed = !this.pressed;
748             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
749             this.fireEvent('toggle', this, e, this.pressed);
750         }
751         
752         
753         this.fireEvent('click', this, e);
754     },
755     
756     /**
757      * Enables this button
758      */
759     enable : function()
760     {
761         this.disabled = false;
762         this.el.removeClass('disabled');
763     },
764     
765     /**
766      * Disable this button
767      */
768     disable : function()
769     {
770         this.disabled = true;
771         this.el.addClass('disabled');
772     },
773      /**
774      * sets the active state on/off, 
775      * @param {Boolean} state (optional) Force a particular state
776      */
777     setActive : function(v) {
778         
779         this.el[v ? 'addClass' : 'removeClass']('active');
780     },
781      /**
782      * toggles the current active state 
783      */
784     toggleActive : function()
785     {
786        var active = this.el.hasClass('active');
787        this.setActive(!active);
788        
789         
790     },
791     setText : function(str)
792     {
793         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
794     },
795     getText : function()
796     {
797         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
798     },
799     hide: function() {
800        
801      
802         this.el.hide();   
803     },
804     show: function() {
805        
806         this.el.show();   
807     }
808     
809     
810 });
811
812  /*
813  * - LGPL
814  *
815  * column
816  * 
817  */
818
819 /**
820  * @class Roo.bootstrap.Column
821  * @extends Roo.bootstrap.Component
822  * Bootstrap Column class
823  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
824  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
825  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
826  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
827  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
828  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
829  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
830  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
831  *
832  * 
833  * @cfg {Boolean} hidden (true|false) hide the element
834  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
835  * @cfg {String} fa (ban|check|...) font awesome icon
836  * @cfg {Number} fasize (1|2|....) font awsome size
837
838  * @cfg {String} icon (info-sign|check|...) glyphicon name
839
840  * @cfg {String} html content of column.
841  * 
842  * @constructor
843  * Create a new Column
844  * @param {Object} config The config object
845  */
846
847 Roo.bootstrap.Column = function(config){
848     Roo.bootstrap.Column.superclass.constructor.call(this, config);
849 };
850
851 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
852     
853     xs: false,
854     sm: false,
855     md: false,
856     lg: false,
857     xsoff: false,
858     smoff: false,
859     mdoff: false,
860     lgoff: false,
861     html: '',
862     offset: 0,
863     alert: false,
864     fa: false,
865     icon : false,
866     hidden : false,
867     fasize : 1,
868     
869     getAutoCreate : function(){
870         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
871         
872         cfg = {
873             tag: 'div',
874             cls: 'column'
875         };
876         
877         var settings=this;
878         ['xs','sm','md','lg'].map(function(size){
879             //Roo.log( size + ':' + settings[size]);
880             
881             if (settings[size+'off'] !== false) {
882                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
883             }
884             
885             if (settings[size] === false) {
886                 return;
887             }
888             Roo.log(settings[size]);
889             if (!settings[size]) { // 0 = hidden
890                 cfg.cls += ' hidden-' + size;
891                 return;
892             }
893             cfg.cls += ' col-' + size + '-' + settings[size];
894             
895         });
896         
897         if (this.hidden) {
898             cfg.cls += ' hidden';
899         }
900         
901         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
902             cfg.cls +=' alert alert-' + this.alert;
903         }
904         
905         
906         if (this.html.length) {
907             cfg.html = this.html;
908         }
909         if (this.fa) {
910             var fasize = '';
911             if (this.fasize > 1) {
912                 fasize = ' fa-' + this.fasize + 'x';
913             }
914             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
915             
916             
917         }
918         if (this.icon) {
919             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
920         }
921         
922         return cfg;
923     }
924    
925 });
926
927  
928
929  /*
930  * - LGPL
931  *
932  * page container.
933  * 
934  */
935
936
937 /**
938  * @class Roo.bootstrap.Container
939  * @extends Roo.bootstrap.Component
940  * Bootstrap Container class
941  * @cfg {Boolean} jumbotron is it a jumbotron element
942  * @cfg {String} html content of element
943  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
944  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
945  * @cfg {String} header content of header (for panel)
946  * @cfg {String} footer content of footer (for panel)
947  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
948  * @cfg {String} tag (header|aside|section) type of HTML tag.
949  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
950  * @cfg {String} fa (ban|check|...) font awesome icon
951  * @cfg {String} icon (info-sign|check|...) glyphicon name
952  * @cfg {Boolean} hidden (true|false) hide the element
953
954  *     
955  * @constructor
956  * Create a new Container
957  * @param {Object} config The config object
958  */
959
960 Roo.bootstrap.Container = function(config){
961     Roo.bootstrap.Container.superclass.constructor.call(this, config);
962 };
963
964 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
965     
966     jumbotron : false,
967     well: '',
968     panel : '',
969     header: '',
970     footer : '',
971     sticky: '',
972     tag : false,
973     alert : false,
974     fa: false,
975     icon : false,
976   
977      
978     getChildContainer : function() {
979         
980         if(!this.el){
981             return false;
982         }
983         
984         if (this.panel.length) {
985             return this.el.select('.panel-body',true).first();
986         }
987         
988         return this.el;
989     },
990     
991     
992     getAutoCreate : function(){
993         
994         var cfg = {
995             tag : this.tag || 'div',
996             html : '',
997             cls : ''
998         };
999         if (this.jumbotron) {
1000             cfg.cls = 'jumbotron';
1001         }
1002         
1003         
1004         
1005         // - this is applied by the parent..
1006         //if (this.cls) {
1007         //    cfg.cls = this.cls + '';
1008         //}
1009         
1010         if (this.sticky.length) {
1011             
1012             var bd = Roo.get(document.body);
1013             if (!bd.hasClass('bootstrap-sticky')) {
1014                 bd.addClass('bootstrap-sticky');
1015                 Roo.select('html',true).setStyle('height', '100%');
1016             }
1017              
1018             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1019         }
1020         
1021         
1022         if (this.well.length) {
1023             switch (this.well) {
1024                 case 'lg':
1025                 case 'sm':
1026                     cfg.cls +=' well well-' +this.well;
1027                     break;
1028                 default:
1029                     cfg.cls +=' well';
1030                     break;
1031             }
1032         }
1033         
1034         if (this.hidden) {
1035             cfg.cls += ' hidden';
1036         }
1037         
1038         
1039         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1040             cfg.cls +=' alert alert-' + this.alert;
1041         }
1042         
1043         var body = cfg;
1044         
1045         if (this.panel.length) {
1046             cfg.cls += ' panel panel-' + this.panel;
1047             cfg.cn = [];
1048             if (this.header.length) {
1049                 cfg.cn.push({
1050                     
1051                     cls : 'panel-heading',
1052                     cn : [{
1053                         tag: 'h3',
1054                         cls : 'panel-title',
1055                         html : this.header
1056                     }]
1057                     
1058                 });
1059             }
1060             body = false;
1061             cfg.cn.push({
1062                 cls : 'panel-body',
1063                 html : this.html
1064             });
1065             
1066             
1067             if (this.footer.length) {
1068                 cfg.cn.push({
1069                     cls : 'panel-footer',
1070                     html : this.footer
1071                     
1072                 });
1073             }
1074             
1075         }
1076         
1077         if (body) {
1078             body.html = this.html || cfg.html;
1079             // prefix with the icons..
1080             if (this.fa) {
1081                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1082             }
1083             if (this.icon) {
1084                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1085             }
1086             
1087             
1088         }
1089         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1090             cfg.cls =  'container';
1091         }
1092         
1093         return cfg;
1094     },
1095     
1096     titleEl : function()
1097     {
1098         if(!this.el || !this.panel.length || !this.header.length){
1099             return;
1100         }
1101         
1102         return this.el.select('.panel-title',true).first();
1103     },
1104     
1105     setTitle : function(v)
1106     {
1107         var titleEl = this.titleEl();
1108         
1109         if(!titleEl){
1110             return;
1111         }
1112         
1113         titleEl.dom.innerHTML = v;
1114     },
1115     
1116     getTitle : function()
1117     {
1118         
1119         var titleEl = this.titleEl();
1120         
1121         if(!titleEl){
1122             return '';
1123         }
1124         
1125         return titleEl.dom.innerHTML;
1126     },
1127     
1128     show : function() {
1129         this.el.removeClass('hidden');
1130     },
1131     hide: function() {
1132         if (!this.el.hasClass('hidden')) {
1133             this.el.addClass('hidden');
1134         }
1135         
1136     }
1137    
1138 });
1139
1140  /*
1141  * - LGPL
1142  *
1143  * image
1144  * 
1145  */
1146
1147
1148 /**
1149  * @class Roo.bootstrap.Img
1150  * @extends Roo.bootstrap.Component
1151  * Bootstrap Img class
1152  * @cfg {Boolean} imgResponsive false | true
1153  * @cfg {String} border rounded | circle | thumbnail
1154  * @cfg {String} src image source
1155  * @cfg {String} alt image alternative text
1156  * @cfg {String} href a tag href
1157  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1158  * 
1159  * @constructor
1160  * Create a new Input
1161  * @param {Object} config The config object
1162  */
1163
1164 Roo.bootstrap.Img = function(config){
1165     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1166     
1167     this.addEvents({
1168         // img events
1169         /**
1170          * @event click
1171          * The img click event for the img.
1172          * @param {Roo.EventObject} e
1173          */
1174         "click" : true
1175     });
1176 };
1177
1178 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1179     
1180     imgResponsive: true,
1181     border: '',
1182     src: '',
1183     href: false,
1184     target: false,
1185
1186     getAutoCreate : function(){
1187         
1188         var cfg = {
1189             tag: 'img',
1190             cls: (this.imgResponsive) ? 'img-responsive' : '',
1191             html : null
1192         }
1193         
1194         cfg.html = this.html || cfg.html;
1195         
1196         cfg.src = this.src || cfg.src;
1197         
1198         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1199             cfg.cls += ' img-' + this.border;
1200         }
1201         
1202         if(this.alt){
1203             cfg.alt = this.alt;
1204         }
1205         
1206         if(this.href){
1207             var a = {
1208                 tag: 'a',
1209                 href: this.href,
1210                 cn: [
1211                     cfg
1212                 ]
1213             }
1214             
1215             if(this.target){
1216                 a.target = this.target;
1217             }
1218             
1219         }
1220         
1221         
1222         return (this.href) ? a : cfg;
1223     },
1224     
1225     initEvents: function() {
1226         
1227         if(!this.href){
1228             this.el.on('click', this.onClick, this);
1229         }
1230     },
1231     
1232     onClick : function(e)
1233     {
1234         Roo.log('img onclick');
1235         this.fireEvent('click', this, e);
1236     }
1237    
1238 });
1239
1240  /*
1241  * - LGPL
1242  *
1243  * image
1244  * 
1245  */
1246
1247
1248 /**
1249  * @class Roo.bootstrap.Link
1250  * @extends Roo.bootstrap.Component
1251  * Bootstrap Link Class
1252  * @cfg {String} alt image alternative text
1253  * @cfg {String} href a tag href
1254  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1255  * @cfg {String} html the content of the link.
1256  * @cfg {String} anchor name for the anchor link
1257
1258  * @cfg {Boolean} preventDefault (true | false) default false
1259
1260  * 
1261  * @constructor
1262  * Create a new Input
1263  * @param {Object} config The config object
1264  */
1265
1266 Roo.bootstrap.Link = function(config){
1267     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1268     
1269     this.addEvents({
1270         // img events
1271         /**
1272          * @event click
1273          * The img click event for the img.
1274          * @param {Roo.EventObject} e
1275          */
1276         "click" : true
1277     });
1278 };
1279
1280 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1281     
1282     href: false,
1283     target: false,
1284     preventDefault: false,
1285     anchor : false,
1286     alt : false,
1287
1288     getAutoCreate : function()
1289     {
1290         
1291         var cfg = {
1292             tag: 'a'
1293         };
1294         // anchor's do not require html/href...
1295         if (this.anchor === false) {
1296             cfg.html = this.html || 'html-missing';
1297             cfg.href = this.href || '#';
1298         } else {
1299             cfg.name = this.anchor;
1300             if (this.html !== false) {
1301                 cfg.html = this.html;
1302             }
1303             if (this.href !== false) {
1304                 cfg.href = this.href;
1305             }
1306         }
1307         
1308         if(this.alt !== false){
1309             cfg.alt = this.alt;
1310         }
1311         
1312         
1313         if(this.target !== false) {
1314             cfg.target = this.target;
1315         }
1316         
1317         return cfg;
1318     },
1319     
1320     initEvents: function() {
1321         
1322         if(!this.href || this.preventDefault){
1323             this.el.on('click', this.onClick, this);
1324         }
1325     },
1326     
1327     onClick : function(e)
1328     {
1329         if(this.preventDefault){
1330             e.preventDefault();
1331         }
1332         //Roo.log('img onclick');
1333         this.fireEvent('click', this, e);
1334     }
1335    
1336 });
1337
1338  /*
1339  * - LGPL
1340  *
1341  * header
1342  * 
1343  */
1344
1345 /**
1346  * @class Roo.bootstrap.Header
1347  * @extends Roo.bootstrap.Component
1348  * Bootstrap Header class
1349  * @cfg {String} html content of header
1350  * @cfg {Number} level (1|2|3|4|5|6) default 1
1351  * 
1352  * @constructor
1353  * Create a new Header
1354  * @param {Object} config The config object
1355  */
1356
1357
1358 Roo.bootstrap.Header  = function(config){
1359     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1360 };
1361
1362 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1363     
1364     //href : false,
1365     html : false,
1366     level : 1,
1367     
1368     
1369     
1370     getAutoCreate : function(){
1371         
1372         var cfg = {
1373             tag: 'h' + (1 *this.level),
1374             html: this.html || 'fill in html'
1375         } ;
1376         
1377         return cfg;
1378     }
1379    
1380 });
1381
1382  
1383
1384  /*
1385  * Based on:
1386  * Ext JS Library 1.1.1
1387  * Copyright(c) 2006-2007, Ext JS, LLC.
1388  *
1389  * Originally Released Under LGPL - original licence link has changed is not relivant.
1390  *
1391  * Fork - LGPL
1392  * <script type="text/javascript">
1393  */
1394  
1395 /**
1396  * @class Roo.bootstrap.MenuMgr
1397  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1398  * @singleton
1399  */
1400 Roo.bootstrap.MenuMgr = function(){
1401    var menus, active, groups = {}, attached = false, lastShow = new Date();
1402
1403    // private - called when first menu is created
1404    function init(){
1405        menus = {};
1406        active = new Roo.util.MixedCollection();
1407        Roo.get(document).addKeyListener(27, function(){
1408            if(active.length > 0){
1409                hideAll();
1410            }
1411        });
1412    }
1413
1414    // private
1415    function hideAll(){
1416        if(active && active.length > 0){
1417            var c = active.clone();
1418            c.each(function(m){
1419                m.hide();
1420            });
1421        }
1422    }
1423
1424    // private
1425    function onHide(m){
1426        active.remove(m);
1427        if(active.length < 1){
1428            Roo.get(document).un("mouseup", onMouseDown);
1429             
1430            attached = false;
1431        }
1432    }
1433
1434    // private
1435    function onShow(m){
1436        var last = active.last();
1437        lastShow = new Date();
1438        active.add(m);
1439        if(!attached){
1440           Roo.get(document).on("mouseup", onMouseDown);
1441            
1442            attached = true;
1443        }
1444        if(m.parentMenu){
1445           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1446           m.parentMenu.activeChild = m;
1447        }else if(last && last.isVisible()){
1448           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1449        }
1450    }
1451
1452    // private
1453    function onBeforeHide(m){
1454        if(m.activeChild){
1455            m.activeChild.hide();
1456        }
1457        if(m.autoHideTimer){
1458            clearTimeout(m.autoHideTimer);
1459            delete m.autoHideTimer;
1460        }
1461    }
1462
1463    // private
1464    function onBeforeShow(m){
1465        var pm = m.parentMenu;
1466        if(!pm && !m.allowOtherMenus){
1467            hideAll();
1468        }else if(pm && pm.activeChild && active != m){
1469            pm.activeChild.hide();
1470        }
1471    }
1472
1473    // private
1474    function onMouseDown(e){
1475         Roo.log("on MouseDown");
1476         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1477            hideAll();
1478         }
1479         
1480         
1481    }
1482
1483    // private
1484    function onBeforeCheck(mi, state){
1485        if(state){
1486            var g = groups[mi.group];
1487            for(var i = 0, l = g.length; i < l; i++){
1488                if(g[i] != mi){
1489                    g[i].setChecked(false);
1490                }
1491            }
1492        }
1493    }
1494
1495    return {
1496
1497        /**
1498         * Hides all menus that are currently visible
1499         */
1500        hideAll : function(){
1501             hideAll();  
1502        },
1503
1504        // private
1505        register : function(menu){
1506            if(!menus){
1507                init();
1508            }
1509            menus[menu.id] = menu;
1510            menu.on("beforehide", onBeforeHide);
1511            menu.on("hide", onHide);
1512            menu.on("beforeshow", onBeforeShow);
1513            menu.on("show", onShow);
1514            var g = menu.group;
1515            if(g && menu.events["checkchange"]){
1516                if(!groups[g]){
1517                    groups[g] = [];
1518                }
1519                groups[g].push(menu);
1520                menu.on("checkchange", onCheck);
1521            }
1522        },
1523
1524         /**
1525          * Returns a {@link Roo.menu.Menu} object
1526          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1527          * be used to generate and return a new Menu instance.
1528          */
1529        get : function(menu){
1530            if(typeof menu == "string"){ // menu id
1531                return menus[menu];
1532            }else if(menu.events){  // menu instance
1533                return menu;
1534            }
1535            /*else if(typeof menu.length == 'number'){ // array of menu items?
1536                return new Roo.bootstrap.Menu({items:menu});
1537            }else{ // otherwise, must be a config
1538                return new Roo.bootstrap.Menu(menu);
1539            }
1540            */
1541            return false;
1542        },
1543
1544        // private
1545        unregister : function(menu){
1546            delete menus[menu.id];
1547            menu.un("beforehide", onBeforeHide);
1548            menu.un("hide", onHide);
1549            menu.un("beforeshow", onBeforeShow);
1550            menu.un("show", onShow);
1551            var g = menu.group;
1552            if(g && menu.events["checkchange"]){
1553                groups[g].remove(menu);
1554                menu.un("checkchange", onCheck);
1555            }
1556        },
1557
1558        // private
1559        registerCheckable : function(menuItem){
1560            var g = menuItem.group;
1561            if(g){
1562                if(!groups[g]){
1563                    groups[g] = [];
1564                }
1565                groups[g].push(menuItem);
1566                menuItem.on("beforecheckchange", onBeforeCheck);
1567            }
1568        },
1569
1570        // private
1571        unregisterCheckable : function(menuItem){
1572            var g = menuItem.group;
1573            if(g){
1574                groups[g].remove(menuItem);
1575                menuItem.un("beforecheckchange", onBeforeCheck);
1576            }
1577        }
1578    };
1579 }();/*
1580  * - LGPL
1581  *
1582  * menu
1583  * 
1584  */
1585
1586 /**
1587  * @class Roo.bootstrap.Menu
1588  * @extends Roo.bootstrap.Component
1589  * Bootstrap Menu class - container for MenuItems
1590  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1591  * 
1592  * @constructor
1593  * Create a new Menu
1594  * @param {Object} config The config object
1595  */
1596
1597
1598 Roo.bootstrap.Menu = function(config){
1599     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1600     if (this.registerMenu) {
1601         Roo.bootstrap.MenuMgr.register(this);
1602     }
1603     this.addEvents({
1604         /**
1605          * @event beforeshow
1606          * Fires before this menu is displayed
1607          * @param {Roo.menu.Menu} this
1608          */
1609         beforeshow : true,
1610         /**
1611          * @event beforehide
1612          * Fires before this menu is hidden
1613          * @param {Roo.menu.Menu} this
1614          */
1615         beforehide : true,
1616         /**
1617          * @event show
1618          * Fires after this menu is displayed
1619          * @param {Roo.menu.Menu} this
1620          */
1621         show : true,
1622         /**
1623          * @event hide
1624          * Fires after this menu is hidden
1625          * @param {Roo.menu.Menu} this
1626          */
1627         hide : true,
1628         /**
1629          * @event click
1630          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1631          * @param {Roo.menu.Menu} this
1632          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1633          * @param {Roo.EventObject} e
1634          */
1635         click : true,
1636         /**
1637          * @event mouseover
1638          * Fires when the mouse is hovering over this menu
1639          * @param {Roo.menu.Menu} this
1640          * @param {Roo.EventObject} e
1641          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1642          */
1643         mouseover : true,
1644         /**
1645          * @event mouseout
1646          * Fires when the mouse exits this menu
1647          * @param {Roo.menu.Menu} this
1648          * @param {Roo.EventObject} e
1649          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1650          */
1651         mouseout : true,
1652         /**
1653          * @event itemclick
1654          * Fires when a menu item contained in this menu is clicked
1655          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1656          * @param {Roo.EventObject} e
1657          */
1658         itemclick: true
1659     });
1660     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1661 };
1662
1663 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1664     
1665    /// html : false,
1666     //align : '',
1667     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1668     type: false,
1669     /**
1670      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1671      */
1672     registerMenu : true,
1673     
1674     menuItems :false, // stores the menu items..
1675     
1676     hidden:true,
1677     
1678     parentMenu : false,
1679     
1680     getChildContainer : function() {
1681         return this.el;  
1682     },
1683     
1684     getAutoCreate : function(){
1685          
1686         //if (['right'].indexOf(this.align)!==-1) {
1687         //    cfg.cn[1].cls += ' pull-right'
1688         //}
1689         
1690         
1691         var cfg = {
1692             tag : 'ul',
1693             cls : 'dropdown-menu' ,
1694             style : 'z-index:1000'
1695             
1696         }
1697         
1698         if (this.type === 'submenu') {
1699             cfg.cls = 'submenu active';
1700         }
1701         if (this.type === 'treeview') {
1702             cfg.cls = 'treeview-menu';
1703         }
1704         
1705         return cfg;
1706     },
1707     initEvents : function() {
1708         
1709        // Roo.log("ADD event");
1710        // Roo.log(this.triggerEl.dom);
1711         this.triggerEl.on('click', this.onTriggerPress, this);
1712         this.triggerEl.addClass('dropdown-toggle');
1713         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1714
1715         this.el.on("mouseover", this.onMouseOver, this);
1716         this.el.on("mouseout", this.onMouseOut, this);
1717         
1718         
1719     },
1720     findTargetItem : function(e){
1721         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1722         if(!t){
1723             return false;
1724         }
1725         //Roo.log(t);         Roo.log(t.id);
1726         if(t && t.id){
1727             //Roo.log(this.menuitems);
1728             return this.menuitems.get(t.id);
1729             
1730             //return this.items.get(t.menuItemId);
1731         }
1732         
1733         return false;
1734     },
1735     onClick : function(e){
1736         Roo.log("menu.onClick");
1737         var t = this.findTargetItem(e);
1738         if(!t || t.isContainer){
1739             return;
1740         }
1741         Roo.log(e);
1742         /*
1743         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1744             if(t == this.activeItem && t.shouldDeactivate(e)){
1745                 this.activeItem.deactivate();
1746                 delete this.activeItem;
1747                 return;
1748             }
1749             if(t.canActivate){
1750                 this.setActiveItem(t, true);
1751             }
1752             return;
1753             
1754             
1755         }
1756         */
1757        
1758         Roo.log('pass click event');
1759         
1760         t.onClick(e);
1761         
1762         this.fireEvent("click", this, t, e);
1763         
1764         this.hide();
1765     },
1766      onMouseOver : function(e){
1767         var t  = this.findTargetItem(e);
1768         //Roo.log(t);
1769         //if(t){
1770         //    if(t.canActivate && !t.disabled){
1771         //        this.setActiveItem(t, true);
1772         //    }
1773         //}
1774         
1775         this.fireEvent("mouseover", this, e, t);
1776     },
1777     isVisible : function(){
1778         return !this.hidden;
1779     },
1780      onMouseOut : function(e){
1781         var t  = this.findTargetItem(e);
1782         
1783         //if(t ){
1784         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1785         //        this.activeItem.deactivate();
1786         //        delete this.activeItem;
1787         //    }
1788         //}
1789         this.fireEvent("mouseout", this, e, t);
1790     },
1791     
1792     
1793     /**
1794      * Displays this menu relative to another element
1795      * @param {String/HTMLElement/Roo.Element} element The element to align to
1796      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1797      * the element (defaults to this.defaultAlign)
1798      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1799      */
1800     show : function(el, pos, parentMenu){
1801         this.parentMenu = parentMenu;
1802         if(!this.el){
1803             this.render();
1804         }
1805         this.fireEvent("beforeshow", this);
1806         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1807     },
1808      /**
1809      * Displays this menu at a specific xy position
1810      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1811      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1812      */
1813     showAt : function(xy, parentMenu, /* private: */_e){
1814         this.parentMenu = parentMenu;
1815         if(!this.el){
1816             this.render();
1817         }
1818         if(_e !== false){
1819             this.fireEvent("beforeshow", this);
1820             
1821             //xy = this.el.adjustForConstraints(xy);
1822         }
1823         //this.el.setXY(xy);
1824         //this.el.show();
1825         this.hideMenuItems();
1826         this.hidden = false;
1827         this.triggerEl.addClass('open');
1828         this.focus();
1829         this.fireEvent("show", this);
1830     },
1831     
1832     focus : function(){
1833         return;
1834         if(!this.hidden){
1835             this.doFocus.defer(50, this);
1836         }
1837     },
1838
1839     doFocus : function(){
1840         if(!this.hidden){
1841             this.focusEl.focus();
1842         }
1843     },
1844
1845     /**
1846      * Hides this menu and optionally all parent menus
1847      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1848      */
1849     hide : function(deep){
1850         
1851         this.hideMenuItems();
1852         if(this.el && this.isVisible()){
1853             this.fireEvent("beforehide", this);
1854             if(this.activeItem){
1855                 this.activeItem.deactivate();
1856                 this.activeItem = null;
1857             }
1858             this.triggerEl.removeClass('open');;
1859             this.hidden = true;
1860             this.fireEvent("hide", this);
1861         }
1862         if(deep === true && this.parentMenu){
1863             this.parentMenu.hide(true);
1864         }
1865     },
1866     
1867     onTriggerPress  : function(e)
1868     {
1869         
1870         Roo.log('trigger press');
1871         //Roo.log(e.getTarget());
1872        // Roo.log(this.triggerEl.dom);
1873         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1874             return;
1875         }
1876         if (this.isVisible()) {
1877             Roo.log('hide');
1878             this.hide();
1879         } else {
1880             this.show(this.triggerEl, false, false);
1881         }
1882         
1883         
1884     },
1885     
1886          
1887        
1888     
1889     hideMenuItems : function()
1890     {
1891         //$(backdrop).remove()
1892         Roo.select('.open',true).each(function(aa) {
1893             
1894             aa.removeClass('open');
1895           //var parent = getParent($(this))
1896           //var relatedTarget = { relatedTarget: this }
1897           
1898            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1899           //if (e.isDefaultPrevented()) return
1900            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1901         })
1902     },
1903     addxtypeChild : function (tree, cntr) {
1904         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1905           
1906         this.menuitems.add(comp);
1907         return comp;
1908
1909     },
1910     getEl : function()
1911     {
1912         Roo.log(this.el);
1913         return this.el;
1914     }
1915 });
1916
1917  
1918  /*
1919  * - LGPL
1920  *
1921  * menu item
1922  * 
1923  */
1924
1925
1926 /**
1927  * @class Roo.bootstrap.MenuItem
1928  * @extends Roo.bootstrap.Component
1929  * Bootstrap MenuItem class
1930  * @cfg {String} html the menu label
1931  * @cfg {String} href the link
1932  * @cfg {Boolean} preventDefault (true | false) default true
1933  * @cfg {Boolean} isContainer (true | false) default false
1934  * 
1935  * 
1936  * @constructor
1937  * Create a new MenuItem
1938  * @param {Object} config The config object
1939  */
1940
1941
1942 Roo.bootstrap.MenuItem = function(config){
1943     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1944     this.addEvents({
1945         // raw events
1946         /**
1947          * @event click
1948          * The raw click event for the entire grid.
1949          * @param {Roo.EventObject} e
1950          */
1951         "click" : true
1952     });
1953 };
1954
1955 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1956     
1957     href : false,
1958     html : false,
1959     preventDefault: true,
1960     isContainer : false,
1961     
1962     getAutoCreate : function(){
1963         
1964         if(this.isContainer){
1965             return {
1966                 tag: 'li',
1967                 cls: 'dropdown-menu-item'
1968             };
1969         }
1970         
1971         var cfg= {
1972             tag: 'li',
1973             cls: 'dropdown-menu-item',
1974             cn: [
1975                     {
1976                         tag : 'a',
1977                         href : '#',
1978                         html : 'Link'
1979                     }
1980                 ]
1981         };
1982         if (this.parent().type == 'treeview') {
1983             cfg.cls = 'treeview-menu';
1984         }
1985         
1986         cfg.cn[0].href = this.href || cfg.cn[0].href ;
1987         cfg.cn[0].html = this.html || cfg.cn[0].html ;
1988         return cfg;
1989     },
1990     
1991     initEvents: function() {
1992         
1993         //this.el.select('a').on('click', this.onClick, this);
1994         
1995     },
1996     onClick : function(e)
1997     {
1998         Roo.log('item on click ');
1999         //if(this.preventDefault){
2000         //    e.preventDefault();
2001         //}
2002         //this.parent().hideMenuItems();
2003         
2004         this.fireEvent('click', this, e);
2005     },
2006     getEl : function()
2007     {
2008         return this.el;
2009     }
2010 });
2011
2012  
2013
2014  /*
2015  * - LGPL
2016  *
2017  * menu separator
2018  * 
2019  */
2020
2021
2022 /**
2023  * @class Roo.bootstrap.MenuSeparator
2024  * @extends Roo.bootstrap.Component
2025  * Bootstrap MenuSeparator class
2026  * 
2027  * @constructor
2028  * Create a new MenuItem
2029  * @param {Object} config The config object
2030  */
2031
2032
2033 Roo.bootstrap.MenuSeparator = function(config){
2034     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2035 };
2036
2037 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2038     
2039     getAutoCreate : function(){
2040         var cfg = {
2041             cls: 'divider',
2042             tag : 'li'
2043         };
2044         
2045         return cfg;
2046     }
2047    
2048 });
2049
2050  
2051
2052  
2053 /*
2054 <div class="modal fade">
2055   <div class="modal-dialog">
2056     <div class="modal-content">
2057       <div class="modal-header">
2058         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
2059         <h4 class="modal-title">Modal title</h4>
2060       </div>
2061       <div class="modal-body">
2062         <p>One fine body&hellip;</p>
2063       </div>
2064       <div class="modal-footer">
2065         <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
2066         <button type="button" class="btn btn-primary">Save changes</button>
2067       </div>
2068     </div><!-- /.modal-content -->
2069   </div><!-- /.modal-dialog -->
2070 </div><!-- /.modal -->
2071 */
2072 /*
2073  * - LGPL
2074  *
2075  * page contgainer.
2076  * 
2077  */
2078
2079 /**
2080  * @class Roo.bootstrap.Modal
2081  * @extends Roo.bootstrap.Component
2082  * Bootstrap Modal class
2083  * @cfg {String} title Title of dialog
2084  * @cfg {Boolean} specificTitle default false
2085  * @cfg {Array} buttons Array of buttons or standard button set..
2086  * @cfg {String} buttonPosition (left|right|center) default right
2087  * @cfg {Boolean} animate default true
2088  * @cfg {Boolean} allow_close default true
2089  * 
2090  * @constructor
2091  * Create a new Modal Dialog
2092  * @param {Object} config The config object
2093  */
2094
2095 Roo.bootstrap.Modal = function(config){
2096     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2097     this.addEvents({
2098         // raw events
2099         /**
2100          * @event btnclick
2101          * The raw btnclick event for the button
2102          * @param {Roo.EventObject} e
2103          */
2104         "btnclick" : true
2105     });
2106     this.buttons = this.buttons || [];
2107 };
2108
2109 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2110     
2111     title : 'test dialog',
2112    
2113     buttons : false,
2114     
2115     // set on load...
2116     body:  false,
2117     
2118     specificTitle: false,
2119     
2120     buttonPosition: 'right',
2121     
2122     allow_close : true,
2123     
2124     animate : true,
2125     
2126     onRender : function(ct, position)
2127     {
2128         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2129      
2130         if(!this.el){
2131             var cfg = Roo.apply({},  this.getAutoCreate());
2132             cfg.id = Roo.id();
2133             //if(!cfg.name){
2134             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2135             //}
2136             //if (!cfg.name.length) {
2137             //    delete cfg.name;
2138            // }
2139             if (this.cls) {
2140                 cfg.cls += ' ' + this.cls;
2141             }
2142             if (this.style) {
2143                 cfg.style = this.style;
2144             }
2145             this.el = Roo.get(document.body).createChild(cfg, position);
2146         }
2147         //var type = this.el.dom.type;
2148         
2149         if(this.tabIndex !== undefined){
2150             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2151         }
2152         
2153         
2154         
2155         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2156         this.maskEl.enableDisplayMode("block");
2157         this.maskEl.hide();
2158         //this.el.addClass("x-dlg-modal");
2159     
2160         if (this.buttons.length) {
2161             Roo.each(this.buttons, function(bb) {
2162                 b = Roo.apply({}, bb);
2163                 b.xns = b.xns || Roo.bootstrap;
2164                 b.xtype = b.xtype || 'Button';
2165                 if (typeof(b.listeners) == 'undefined') {
2166                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2167                 }
2168                 
2169                 var btn = Roo.factory(b);
2170                 
2171                 btn.onRender(this.el.select('.modal-footer div').first());
2172                 
2173             },this);
2174         }
2175         // render the children.
2176         var nitems = [];
2177         
2178         if(typeof(this.items) != 'undefined'){
2179             var items = this.items;
2180             delete this.items;
2181
2182             for(var i =0;i < items.length;i++) {
2183                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2184             }
2185         }
2186         
2187         this.items = nitems;
2188         
2189         this.body = this.el.select('.modal-body',true).first();
2190         this.close = this.el.select('.modal-header .close', true).first();
2191         this.footer = this.el.select('.modal-footer',true).first();
2192         this.initEvents();
2193         //this.el.addClass([this.fieldClass, this.cls]);
2194         
2195     },
2196     getAutoCreate : function(){
2197         
2198         
2199         var bdy = {
2200                 cls : 'modal-body',
2201                 html : this.html || ''
2202         };
2203         
2204         var title = {
2205             tag: 'h4',
2206             cls : 'modal-title',
2207             html : this.title
2208         };
2209         
2210         if(this.specificTitle){
2211             title = this.title;
2212             
2213         };
2214         
2215         var header = [];
2216         if (this.allow_close) {
2217             header.push({
2218                 tag: 'button',
2219                 cls : 'close',
2220                 html : '&times'
2221             });
2222         }
2223         header.push(title);
2224         
2225         var modal = {
2226             cls: "modal",
2227             style : 'display: none',
2228             cn : [
2229                 {
2230                     cls: "modal-dialog",
2231                     cn : [
2232                         {
2233                             cls : "modal-content",
2234                             cn : [
2235                                 {
2236                                     cls : 'modal-header',
2237                                     cn : header
2238                                 },
2239                                 bdy,
2240                                 {
2241                                     cls : 'modal-footer',
2242                                     cn : [
2243                                         {
2244                                             tag: 'div',
2245                                             cls: 'btn-' + this.buttonPosition
2246                                         }
2247                                     ]
2248                                     
2249                                 }
2250                                 
2251                                 
2252                             ]
2253                             
2254                         }
2255                     ]
2256                         
2257                 }
2258             ]
2259         };
2260         
2261         if(this.animate){
2262             modal.cls += ' fade';
2263         }
2264         
2265         return modal;
2266           
2267     },
2268     getChildContainer : function() {
2269          
2270          return this.el.select('.modal-body',true).first();
2271         
2272     },
2273     getButtonContainer : function() {
2274          return this.el.select('.modal-footer div',true).first();
2275         
2276     },
2277     initEvents : function()
2278     {
2279         this.el.select('.modal-header .close').on('click', this.hide, this);
2280 //        
2281 //        this.addxtype(this);
2282     },
2283     show : function() {
2284         
2285         if (!this.rendered) {
2286             this.render();
2287         }
2288         
2289         this.el.setStyle('display', 'block');
2290         
2291         if(this.animate){
2292             var _this = this;
2293             (function(){ _this.el.addClass('in'); }).defer(50);
2294         }else{
2295             this.el.addClass('in');
2296         }
2297         
2298         Roo.get(document.body).addClass("x-body-masked");
2299         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2300         this.maskEl.show();
2301         this.el.setStyle('zIndex', '10001');
2302        
2303         this.fireEvent('show', this);
2304         
2305         
2306     },
2307     hide : function()
2308     {
2309         this.maskEl.hide();
2310         Roo.get(document.body).removeClass("x-body-masked");
2311         this.el.removeClass('in');
2312         
2313         if(this.animate){
2314             var _this = this;
2315             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2316         }else{
2317             this.el.setStyle('display', 'none');
2318         }
2319         
2320         this.fireEvent('hide', this);
2321     },
2322     
2323     addButton : function(str, cb)
2324     {
2325          
2326         
2327         var b = Roo.apply({}, { html : str } );
2328         b.xns = b.xns || Roo.bootstrap;
2329         b.xtype = b.xtype || 'Button';
2330         if (typeof(b.listeners) == 'undefined') {
2331             b.listeners = { click : cb.createDelegate(this)  };
2332         }
2333         
2334         var btn = Roo.factory(b);
2335            
2336         btn.onRender(this.el.select('.modal-footer div').first());
2337         
2338         return btn;   
2339        
2340     },
2341     
2342     setDefaultButton : function(btn)
2343     {
2344         //this.el.select('.modal-footer').()
2345     },
2346     resizeTo: function(w,h)
2347     {
2348         // skip..
2349     },
2350     setContentSize  : function(w, h)
2351     {
2352         
2353     },
2354     onButtonClick: function(btn,e)
2355     {
2356         //Roo.log([a,b,c]);
2357         this.fireEvent('btnclick', btn.name, e);
2358     },
2359     setTitle: function(str) {
2360         this.el.select('.modal-title',true).first().dom.innerHTML = str;
2361         
2362     }
2363 });
2364
2365
2366 Roo.apply(Roo.bootstrap.Modal,  {
2367     /**
2368          * Button config that displays a single OK button
2369          * @type Object
2370          */
2371         OK :  [{
2372             name : 'ok',
2373             weight : 'primary',
2374             html : 'OK'
2375         }], 
2376         /**
2377          * Button config that displays Yes and No buttons
2378          * @type Object
2379          */
2380         YESNO : [
2381             {
2382                 name  : 'no',
2383                 html : 'No'
2384             },
2385             {
2386                 name  :'yes',
2387                 weight : 'primary',
2388                 html : 'Yes'
2389             }
2390         ],
2391         
2392         /**
2393          * Button config that displays OK and Cancel buttons
2394          * @type Object
2395          */
2396         OKCANCEL : [
2397             {
2398                name : 'cancel',
2399                 html : 'Cancel'
2400             },
2401             {
2402                 name : 'ok',
2403                 weight : 'primary',
2404                 html : 'OK'
2405             }
2406         ],
2407         /**
2408          * Button config that displays Yes, No and Cancel buttons
2409          * @type Object
2410          */
2411         YESNOCANCEL : [
2412             {
2413                 name : 'yes',
2414                 weight : 'primary',
2415                 html : 'Yes'
2416             },
2417             {
2418                 name : 'no',
2419                 html : 'No'
2420             },
2421             {
2422                 name : 'cancel',
2423                 html : 'Cancel'
2424             }
2425         ]
2426 });
2427  /*
2428  * - LGPL
2429  *
2430  * messagebox - can be used as a replace
2431  * 
2432  */
2433 /**
2434  * @class Roo.MessageBox
2435  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2436  * Example usage:
2437  *<pre><code>
2438 // Basic alert:
2439 Roo.Msg.alert('Status', 'Changes saved successfully.');
2440
2441 // Prompt for user data:
2442 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2443     if (btn == 'ok'){
2444         // process text value...
2445     }
2446 });
2447
2448 // Show a dialog using config options:
2449 Roo.Msg.show({
2450    title:'Save Changes?',
2451    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2452    buttons: Roo.Msg.YESNOCANCEL,
2453    fn: processResult,
2454    animEl: 'elId'
2455 });
2456 </code></pre>
2457  * @singleton
2458  */
2459 Roo.bootstrap.MessageBox = function(){
2460     var dlg, opt, mask, waitTimer;
2461     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2462     var buttons, activeTextEl, bwidth;
2463
2464     
2465     // private
2466     var handleButton = function(button){
2467         dlg.hide();
2468         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2469     };
2470
2471     // private
2472     var handleHide = function(){
2473         if(opt && opt.cls){
2474             dlg.el.removeClass(opt.cls);
2475         }
2476         //if(waitTimer){
2477         //    Roo.TaskMgr.stop(waitTimer);
2478         //    waitTimer = null;
2479         //}
2480     };
2481
2482     // private
2483     var updateButtons = function(b){
2484         var width = 0;
2485         if(!b){
2486             buttons["ok"].hide();
2487             buttons["cancel"].hide();
2488             buttons["yes"].hide();
2489             buttons["no"].hide();
2490             //dlg.footer.dom.style.display = 'none';
2491             return width;
2492         }
2493         dlg.footer.dom.style.display = '';
2494         for(var k in buttons){
2495             if(typeof buttons[k] != "function"){
2496                 if(b[k]){
2497                     buttons[k].show();
2498                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2499                     width += buttons[k].el.getWidth()+15;
2500                 }else{
2501                     buttons[k].hide();
2502                 }
2503             }
2504         }
2505         return width;
2506     };
2507
2508     // private
2509     var handleEsc = function(d, k, e){
2510         if(opt && opt.closable !== false){
2511             dlg.hide();
2512         }
2513         if(e){
2514             e.stopEvent();
2515         }
2516     };
2517
2518     return {
2519         /**
2520          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2521          * @return {Roo.BasicDialog} The BasicDialog element
2522          */
2523         getDialog : function(){
2524            if(!dlg){
2525                 dlg = new Roo.bootstrap.Modal( {
2526                     //draggable: true,
2527                     //resizable:false,
2528                     //constraintoviewport:false,
2529                     //fixedcenter:true,
2530                     //collapsible : false,
2531                     //shim:true,
2532                     //modal: true,
2533                   //  width:400,
2534                   //  height:100,
2535                     //buttonAlign:"center",
2536                     closeClick : function(){
2537                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2538                             handleButton("no");
2539                         }else{
2540                             handleButton("cancel");
2541                         }
2542                     }
2543                 });
2544                 dlg.render();
2545                 dlg.on("hide", handleHide);
2546                 mask = dlg.mask;
2547                 //dlg.addKeyListener(27, handleEsc);
2548                 buttons = {};
2549                 this.buttons = buttons;
2550                 var bt = this.buttonText;
2551                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2552                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2553                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2554                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2555                 Roo.log(buttons)
2556                 bodyEl = dlg.body.createChild({
2557
2558                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2559                         '<textarea class="roo-mb-textarea"></textarea>' +
2560                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2561                 });
2562                 msgEl = bodyEl.dom.firstChild;
2563                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2564                 textboxEl.enableDisplayMode();
2565                 textboxEl.addKeyListener([10,13], function(){
2566                     if(dlg.isVisible() && opt && opt.buttons){
2567                         if(opt.buttons.ok){
2568                             handleButton("ok");
2569                         }else if(opt.buttons.yes){
2570                             handleButton("yes");
2571                         }
2572                     }
2573                 });
2574                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2575                 textareaEl.enableDisplayMode();
2576                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2577                 progressEl.enableDisplayMode();
2578                 var pf = progressEl.dom.firstChild;
2579                 if (pf) {
2580                     pp = Roo.get(pf.firstChild);
2581                     pp.setHeight(pf.offsetHeight);
2582                 }
2583                 
2584             }
2585             return dlg;
2586         },
2587
2588         /**
2589          * Updates the message box body text
2590          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2591          * the XHTML-compliant non-breaking space character '&amp;#160;')
2592          * @return {Roo.MessageBox} This message box
2593          */
2594         updateText : function(text){
2595             if(!dlg.isVisible() && !opt.width){
2596                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2597             }
2598             msgEl.innerHTML = text || '&#160;';
2599       
2600             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2601             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2602             var w = Math.max(
2603                     Math.min(opt.width || cw , this.maxWidth), 
2604                     Math.max(opt.minWidth || this.minWidth, bwidth)
2605             );
2606             if(opt.prompt){
2607                 activeTextEl.setWidth(w);
2608             }
2609             if(dlg.isVisible()){
2610                 dlg.fixedcenter = false;
2611             }
2612             // to big, make it scroll. = But as usual stupid IE does not support
2613             // !important..
2614             
2615             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2616                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2617                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2618             } else {
2619                 bodyEl.dom.style.height = '';
2620                 bodyEl.dom.style.overflowY = '';
2621             }
2622             if (cw > w) {
2623                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2624             } else {
2625                 bodyEl.dom.style.overflowX = '';
2626             }
2627             
2628             dlg.setContentSize(w, bodyEl.getHeight());
2629             if(dlg.isVisible()){
2630                 dlg.fixedcenter = true;
2631             }
2632             return this;
2633         },
2634
2635         /**
2636          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2637          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2638          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2639          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2640          * @return {Roo.MessageBox} This message box
2641          */
2642         updateProgress : function(value, text){
2643             if(text){
2644                 this.updateText(text);
2645             }
2646             if (pp) { // weird bug on my firefox - for some reason this is not defined
2647                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2648             }
2649             return this;
2650         },        
2651
2652         /**
2653          * Returns true if the message box is currently displayed
2654          * @return {Boolean} True if the message box is visible, else false
2655          */
2656         isVisible : function(){
2657             return dlg && dlg.isVisible();  
2658         },
2659
2660         /**
2661          * Hides the message box if it is displayed
2662          */
2663         hide : function(){
2664             if(this.isVisible()){
2665                 dlg.hide();
2666             }  
2667         },
2668
2669         /**
2670          * Displays a new message box, or reinitializes an existing message box, based on the config options
2671          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2672          * The following config object properties are supported:
2673          * <pre>
2674 Property    Type             Description
2675 ----------  ---------------  ------------------------------------------------------------------------------------
2676 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2677                                    closes (defaults to undefined)
2678 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2679                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2680 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2681                                    progress and wait dialogs will ignore this property and always hide the
2682                                    close button as they can only be closed programmatically.
2683 cls               String           A custom CSS class to apply to the message box element
2684 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2685                                    displayed (defaults to 75)
2686 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2687                                    function will be btn (the name of the button that was clicked, if applicable,
2688                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2689                                    Progress and wait dialogs will ignore this option since they do not respond to
2690                                    user actions and can only be closed programmatically, so any required function
2691                                    should be called by the same code after it closes the dialog.
2692 icon              String           A CSS class that provides a background image to be used as an icon for
2693                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2694 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2695 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2696 modal             Boolean          False to allow user interaction with the page while the message box is
2697                                    displayed (defaults to true)
2698 msg               String           A string that will replace the existing message box body text (defaults
2699                                    to the XHTML-compliant non-breaking space character '&#160;')
2700 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2701 progress          Boolean          True to display a progress bar (defaults to false)
2702 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2703 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2704 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2705 title             String           The title text
2706 value             String           The string value to set into the active textbox element if displayed
2707 wait              Boolean          True to display a progress bar (defaults to false)
2708 width             Number           The width of the dialog in pixels
2709 </pre>
2710          *
2711          * Example usage:
2712          * <pre><code>
2713 Roo.Msg.show({
2714    title: 'Address',
2715    msg: 'Please enter your address:',
2716    width: 300,
2717    buttons: Roo.MessageBox.OKCANCEL,
2718    multiline: true,
2719    fn: saveAddress,
2720    animEl: 'addAddressBtn'
2721 });
2722 </code></pre>
2723          * @param {Object} config Configuration options
2724          * @return {Roo.MessageBox} This message box
2725          */
2726         show : function(options)
2727         {
2728             
2729             // this causes nightmares if you show one dialog after another
2730             // especially on callbacks..
2731              
2732             if(this.isVisible()){
2733                 
2734                 this.hide();
2735                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2736                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2737                 Roo.log("New Dialog Message:" +  options.msg )
2738                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2739                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2740                 
2741             }
2742             var d = this.getDialog();
2743             opt = options;
2744             d.setTitle(opt.title || "&#160;");
2745             d.close.setDisplayed(opt.closable !== false);
2746             activeTextEl = textboxEl;
2747             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2748             if(opt.prompt){
2749                 if(opt.multiline){
2750                     textboxEl.hide();
2751                     textareaEl.show();
2752                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2753                         opt.multiline : this.defaultTextHeight);
2754                     activeTextEl = textareaEl;
2755                 }else{
2756                     textboxEl.show();
2757                     textareaEl.hide();
2758                 }
2759             }else{
2760                 textboxEl.hide();
2761                 textareaEl.hide();
2762             }
2763             progressEl.setDisplayed(opt.progress === true);
2764             this.updateProgress(0);
2765             activeTextEl.dom.value = opt.value || "";
2766             if(opt.prompt){
2767                 dlg.setDefaultButton(activeTextEl);
2768             }else{
2769                 var bs = opt.buttons;
2770                 var db = null;
2771                 if(bs && bs.ok){
2772                     db = buttons["ok"];
2773                 }else if(bs && bs.yes){
2774                     db = buttons["yes"];
2775                 }
2776                 dlg.setDefaultButton(db);
2777             }
2778             bwidth = updateButtons(opt.buttons);
2779             this.updateText(opt.msg);
2780             if(opt.cls){
2781                 d.el.addClass(opt.cls);
2782             }
2783             d.proxyDrag = opt.proxyDrag === true;
2784             d.modal = opt.modal !== false;
2785             d.mask = opt.modal !== false ? mask : false;
2786             if(!d.isVisible()){
2787                 // force it to the end of the z-index stack so it gets a cursor in FF
2788                 document.body.appendChild(dlg.el.dom);
2789                 d.animateTarget = null;
2790                 d.show(options.animEl);
2791             }
2792             return this;
2793         },
2794
2795         /**
2796          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2797          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2798          * and closing the message box when the process is complete.
2799          * @param {String} title The title bar text
2800          * @param {String} msg The message box body text
2801          * @return {Roo.MessageBox} This message box
2802          */
2803         progress : function(title, msg){
2804             this.show({
2805                 title : title,
2806                 msg : msg,
2807                 buttons: false,
2808                 progress:true,
2809                 closable:false,
2810                 minWidth: this.minProgressWidth,
2811                 modal : true
2812             });
2813             return this;
2814         },
2815
2816         /**
2817          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2818          * If a callback function is passed it will be called after the user clicks the button, and the
2819          * id of the button that was clicked will be passed as the only parameter to the callback
2820          * (could also be the top-right close button).
2821          * @param {String} title The title bar text
2822          * @param {String} msg The message box body text
2823          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2824          * @param {Object} scope (optional) The scope of the callback function
2825          * @return {Roo.MessageBox} This message box
2826          */
2827         alert : function(title, msg, fn, scope){
2828             this.show({
2829                 title : title,
2830                 msg : msg,
2831                 buttons: this.OK,
2832                 fn: fn,
2833                 scope : scope,
2834                 modal : true
2835             });
2836             return this;
2837         },
2838
2839         /**
2840          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2841          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2842          * You are responsible for closing the message box when the process is complete.
2843          * @param {String} msg The message box body text
2844          * @param {String} title (optional) The title bar text
2845          * @return {Roo.MessageBox} This message box
2846          */
2847         wait : function(msg, title){
2848             this.show({
2849                 title : title,
2850                 msg : msg,
2851                 buttons: false,
2852                 closable:false,
2853                 progress:true,
2854                 modal:true,
2855                 width:300,
2856                 wait:true
2857             });
2858             waitTimer = Roo.TaskMgr.start({
2859                 run: function(i){
2860                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2861                 },
2862                 interval: 1000
2863             });
2864             return this;
2865         },
2866
2867         /**
2868          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2869          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2870          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2871          * @param {String} title The title bar text
2872          * @param {String} msg The message box body text
2873          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2874          * @param {Object} scope (optional) The scope of the callback function
2875          * @return {Roo.MessageBox} This message box
2876          */
2877         confirm : function(title, msg, fn, scope){
2878             this.show({
2879                 title : title,
2880                 msg : msg,
2881                 buttons: this.YESNO,
2882                 fn: fn,
2883                 scope : scope,
2884                 modal : true
2885             });
2886             return this;
2887         },
2888
2889         /**
2890          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2891          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2892          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2893          * (could also be the top-right close button) and the text that was entered will be passed as the two
2894          * parameters to the callback.
2895          * @param {String} title The title bar text
2896          * @param {String} msg The message box body text
2897          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2898          * @param {Object} scope (optional) The scope of the callback function
2899          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2900          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2901          * @return {Roo.MessageBox} This message box
2902          */
2903         prompt : function(title, msg, fn, scope, multiline){
2904             this.show({
2905                 title : title,
2906                 msg : msg,
2907                 buttons: this.OKCANCEL,
2908                 fn: fn,
2909                 minWidth:250,
2910                 scope : scope,
2911                 prompt:true,
2912                 multiline: multiline,
2913                 modal : true
2914             });
2915             return this;
2916         },
2917
2918         /**
2919          * Button config that displays a single OK button
2920          * @type Object
2921          */
2922         OK : {ok:true},
2923         /**
2924          * Button config that displays Yes and No buttons
2925          * @type Object
2926          */
2927         YESNO : {yes:true, no:true},
2928         /**
2929          * Button config that displays OK and Cancel buttons
2930          * @type Object
2931          */
2932         OKCANCEL : {ok:true, cancel:true},
2933         /**
2934          * Button config that displays Yes, No and Cancel buttons
2935          * @type Object
2936          */
2937         YESNOCANCEL : {yes:true, no:true, cancel:true},
2938
2939         /**
2940          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2941          * @type Number
2942          */
2943         defaultTextHeight : 75,
2944         /**
2945          * The maximum width in pixels of the message box (defaults to 600)
2946          * @type Number
2947          */
2948         maxWidth : 600,
2949         /**
2950          * The minimum width in pixels of the message box (defaults to 100)
2951          * @type Number
2952          */
2953         minWidth : 100,
2954         /**
2955          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
2956          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2957          * @type Number
2958          */
2959         minProgressWidth : 250,
2960         /**
2961          * An object containing the default button text strings that can be overriden for localized language support.
2962          * Supported properties are: ok, cancel, yes and no.
2963          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2964          * @type Object
2965          */
2966         buttonText : {
2967             ok : "OK",
2968             cancel : "Cancel",
2969             yes : "Yes",
2970             no : "No"
2971         }
2972     };
2973 }();
2974
2975 /**
2976  * Shorthand for {@link Roo.MessageBox}
2977  */
2978 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
2979 Roo.Msg = Roo.Msg || Roo.MessageBox;
2980 /*
2981  * - LGPL
2982  *
2983  * navbar
2984  * 
2985  */
2986
2987 /**
2988  * @class Roo.bootstrap.Navbar
2989  * @extends Roo.bootstrap.Component
2990  * Bootstrap Navbar class
2991
2992  * @constructor
2993  * Create a new Navbar
2994  * @param {Object} config The config object
2995  */
2996
2997
2998 Roo.bootstrap.Navbar = function(config){
2999     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3000     
3001 };
3002
3003 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3004     
3005     
3006    
3007     // private
3008     navItems : false,
3009     loadMask : false,
3010     
3011     
3012     getAutoCreate : function(){
3013         
3014         
3015         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3016         
3017     },
3018     
3019     initEvents :function ()
3020     {
3021         //Roo.log(this.el.select('.navbar-toggle',true));
3022         this.el.select('.navbar-toggle',true).on('click', function() {
3023            // Roo.log('click');
3024             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3025         }, this);
3026         
3027         var mark = {
3028             tag: "div",
3029             cls:"x-dlg-mask"
3030         }
3031         
3032         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3033         
3034         var size = this.el.getSize();
3035         this.maskEl.setSize(size.width, size.height);
3036         this.maskEl.enableDisplayMode("block");
3037         this.maskEl.hide();
3038         
3039         if(this.loadMask){
3040             this.maskEl.show();
3041         }
3042     },
3043     
3044     
3045     getChildContainer : function()
3046     {
3047         if (this.el.select('.collapse').getCount()) {
3048             return this.el.select('.collapse',true).first();
3049         }
3050         
3051         return this.el;
3052     },
3053     
3054     mask : function()
3055     {
3056         this.maskEl.show();
3057     },
3058     
3059     unmask : function()
3060     {
3061         this.maskEl.hide();
3062     } 
3063     
3064     
3065     
3066     
3067 });
3068
3069
3070
3071  
3072
3073  /*
3074  * - LGPL
3075  *
3076  * navbar
3077  * 
3078  */
3079
3080 /**
3081  * @class Roo.bootstrap.NavSimplebar
3082  * @extends Roo.bootstrap.Navbar
3083  * Bootstrap Sidebar class
3084  *
3085  * @cfg {Boolean} inverse is inverted color
3086  * 
3087  * @cfg {String} type (nav | pills | tabs)
3088  * @cfg {Boolean} arrangement stacked | justified
3089  * @cfg {String} align (left | right) alignment
3090  * 
3091  * @cfg {Boolean} main (true|false) main nav bar? default false
3092  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3093  * 
3094  * @cfg {String} tag (header|footer|nav|div) default is nav 
3095
3096  * 
3097  * 
3098  * 
3099  * @constructor
3100  * Create a new Sidebar
3101  * @param {Object} config The config object
3102  */
3103
3104
3105 Roo.bootstrap.NavSimplebar = function(config){
3106     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3107 };
3108
3109 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3110     
3111     inverse: false,
3112     
3113     type: false,
3114     arrangement: '',
3115     align : false,
3116     
3117     
3118     
3119     main : false,
3120     
3121     
3122     tag : false,
3123     
3124     
3125     getAutoCreate : function(){
3126         
3127         
3128         var cfg = {
3129             tag : this.tag || 'div',
3130             cls : 'navbar'
3131         };
3132           
3133         
3134         cfg.cn = [
3135             {
3136                 cls: 'nav',
3137                 tag : 'ul'
3138             }
3139         ];
3140         
3141          
3142         this.type = this.type || 'nav';
3143         if (['tabs','pills'].indexOf(this.type)!==-1) {
3144             cfg.cn[0].cls += ' nav-' + this.type
3145         
3146         
3147         } else {
3148             if (this.type!=='nav') {
3149                 Roo.log('nav type must be nav/tabs/pills')
3150             }
3151             cfg.cn[0].cls += ' navbar-nav'
3152         }
3153         
3154         
3155         
3156         
3157         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3158             cfg.cn[0].cls += ' nav-' + this.arrangement;
3159         }
3160         
3161         
3162         if (this.align === 'right') {
3163             cfg.cn[0].cls += ' navbar-right';
3164         }
3165         
3166         if (this.inverse) {
3167             cfg.cls += ' navbar-inverse';
3168             
3169         }
3170         
3171         
3172         return cfg;
3173     
3174         
3175     }
3176     
3177     
3178     
3179 });
3180
3181
3182
3183  
3184
3185  
3186        /*
3187  * - LGPL
3188  *
3189  * navbar
3190  * 
3191  */
3192
3193 /**
3194  * @class Roo.bootstrap.NavHeaderbar
3195  * @extends Roo.bootstrap.NavSimplebar
3196  * Bootstrap Sidebar class
3197  *
3198  * @cfg {String} brand what is brand
3199  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3200  * @cfg {String} brand_href href of the brand
3201  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3202  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3203  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3204  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3205  * 
3206  * @constructor
3207  * Create a new Sidebar
3208  * @param {Object} config The config object
3209  */
3210
3211
3212 Roo.bootstrap.NavHeaderbar = function(config){
3213     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3214       
3215 };
3216
3217 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3218     
3219     position: '',
3220     brand: '',
3221     brand_href: false,
3222     srButton : true,
3223     autohide : false,
3224     desktopCenter : false,
3225    
3226     
3227     getAutoCreate : function(){
3228         
3229         var   cfg = {
3230             tag: this.nav || 'nav',
3231             cls: 'navbar',
3232             role: 'navigation',
3233             cn: []
3234         };
3235         
3236         var cn = cfg.cn;
3237         if (this.desktopCenter) {
3238             cn.push({cls : 'container', cn : []});
3239             cn = cn[0].cn;
3240         }
3241         
3242         if(this.srButton){
3243             cn.push({
3244                 tag: 'div',
3245                 cls: 'navbar-header',
3246                 cn: [
3247                     {
3248                         tag: 'button',
3249                         type: 'button',
3250                         cls: 'navbar-toggle',
3251                         'data-toggle': 'collapse',
3252                         cn: [
3253                             {
3254                                 tag: 'span',
3255                                 cls: 'sr-only',
3256                                 html: 'Toggle navigation'
3257                             },
3258                             {
3259                                 tag: 'span',
3260                                 cls: 'icon-bar'
3261                             },
3262                             {
3263                                 tag: 'span',
3264                                 cls: 'icon-bar'
3265                             },
3266                             {
3267                                 tag: 'span',
3268                                 cls: 'icon-bar'
3269                             }
3270                         ]
3271                     }
3272                 ]
3273             });
3274         }
3275         
3276         cn.push({
3277             tag: 'div',
3278             cls: 'collapse navbar-collapse',
3279             cn : []
3280         });
3281         
3282         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3283         
3284         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3285             cfg.cls += ' navbar-' + this.position;
3286             
3287             // tag can override this..
3288             
3289             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3290         }
3291         
3292         if (this.brand !== '') {
3293             cn[0].cn.push({
3294                 tag: 'a',
3295                 href: this.brand_href ? this.brand_href : '#',
3296                 cls: 'navbar-brand',
3297                 cn: [
3298                 this.brand
3299                 ]
3300             });
3301         }
3302         
3303         if(this.main){
3304             cfg.cls += ' main-nav';
3305         }
3306         
3307         
3308         return cfg;
3309
3310         
3311     },
3312     getHeaderChildContainer : function()
3313     {
3314         if (this.el.select('.navbar-header').getCount()) {
3315             return this.el.select('.navbar-header',true).first();
3316         }
3317         
3318         return this.getChildContainer();
3319     },
3320     
3321     
3322     initEvents : function()
3323     {
3324         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3325         
3326         if (this.autohide) {
3327             
3328             var prevScroll = 0;
3329             var ft = this.el;
3330             
3331             Roo.get(document).on('scroll',function(e) {
3332                 var ns = Roo.get(document).getScroll().top;
3333                 var os = prevScroll;
3334                 prevScroll = ns;
3335                 
3336                 if(ns > os){
3337                     ft.removeClass('slideDown');
3338                     ft.addClass('slideUp');
3339                     return;
3340                 }
3341                 ft.removeClass('slideUp');
3342                 ft.addClass('slideDown');
3343                  
3344               
3345           },this);
3346         }
3347     }    
3348           
3349       
3350     
3351     
3352 });
3353
3354
3355
3356  
3357
3358  /*
3359  * - LGPL
3360  *
3361  * navbar
3362  * 
3363  */
3364
3365 /**
3366  * @class Roo.bootstrap.NavSidebar
3367  * @extends Roo.bootstrap.Navbar
3368  * Bootstrap Sidebar class
3369  * 
3370  * @constructor
3371  * Create a new Sidebar
3372  * @param {Object} config The config object
3373  */
3374
3375
3376 Roo.bootstrap.NavSidebar = function(config){
3377     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3378 };
3379
3380 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3381     
3382     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3383     
3384     getAutoCreate : function(){
3385         
3386         
3387         return  {
3388             tag: 'div',
3389             cls: 'sidebar sidebar-nav'
3390         };
3391     
3392         
3393     }
3394     
3395     
3396     
3397 });
3398
3399
3400
3401  
3402
3403  /*
3404  * - LGPL
3405  *
3406  * nav group
3407  * 
3408  */
3409
3410 /**
3411  * @class Roo.bootstrap.NavGroup
3412  * @extends Roo.bootstrap.Component
3413  * Bootstrap NavGroup class
3414  * @cfg {String} align left | right
3415  * @cfg {Boolean} inverse false | true
3416  * @cfg {String} type (nav|pills|tab) default nav
3417  * @cfg {String} navId - reference Id for navbar.
3418
3419  * 
3420  * @constructor
3421  * Create a new nav group
3422  * @param {Object} config The config object
3423  */
3424
3425 Roo.bootstrap.NavGroup = function(config){
3426     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3427     this.navItems = [];
3428    
3429     Roo.bootstrap.NavGroup.register(this);
3430      this.addEvents({
3431         /**
3432              * @event changed
3433              * Fires when the active item changes
3434              * @param {Roo.bootstrap.NavGroup} this
3435              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3436              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3437          */
3438         'changed': true
3439      });
3440     
3441 };
3442
3443 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3444     
3445     align: '',
3446     inverse: false,
3447     form: false,
3448     type: 'nav',
3449     navId : '',
3450     // private
3451     
3452     navItems : false, 
3453     
3454     getAutoCreate : function()
3455     {
3456         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3457         
3458         cfg = {
3459             tag : 'ul',
3460             cls: 'nav' 
3461         }
3462         
3463         if (['tabs','pills'].indexOf(this.type)!==-1) {
3464             cfg.cls += ' nav-' + this.type
3465         } else {
3466             if (this.type!=='nav') {
3467                 Roo.log('nav type must be nav/tabs/pills')
3468             }
3469             cfg.cls += ' navbar-nav'
3470         }
3471         
3472         if (this.parent().sidebar) {
3473             cfg = {
3474                 tag: 'ul',
3475                 cls: 'dashboard-menu sidebar-menu'
3476             }
3477             
3478             return cfg;
3479         }
3480         
3481         if (this.form === true) {
3482             cfg = {
3483                 tag: 'form',
3484                 cls: 'navbar-form'
3485             }
3486             
3487             if (this.align === 'right') {
3488                 cfg.cls += ' navbar-right';
3489             } else {
3490                 cfg.cls += ' navbar-left';
3491             }
3492         }
3493         
3494         if (this.align === 'right') {
3495             cfg.cls += ' navbar-right';
3496         }
3497         
3498         if (this.inverse) {
3499             cfg.cls += ' navbar-inverse';
3500             
3501         }
3502         
3503         
3504         return cfg;
3505     },
3506     /**
3507     * sets the active Navigation item
3508     * @param {Roo.bootstrap.NavItem} the new current navitem
3509     */
3510     setActiveItem : function(item)
3511     {
3512         var prev = false;
3513         Roo.each(this.navItems, function(v){
3514             if (v == item) {
3515                 return ;
3516             }
3517             if (v.isActive()) {
3518                 v.setActive(false, true);
3519                 prev = v;
3520                 
3521             }
3522             
3523         });
3524
3525         item.setActive(true, true);
3526         this.fireEvent('changed', this, item, prev);
3527         
3528         
3529     },
3530     /**
3531     * gets the active Navigation item
3532     * @return {Roo.bootstrap.NavItem} the current navitem
3533     */
3534     getActive : function()
3535     {
3536         
3537         var prev = false;
3538         Roo.each(this.navItems, function(v){
3539             
3540             if (v.isActive()) {
3541                 prev = v;
3542                 
3543             }
3544             
3545         });
3546         return prev;
3547     },
3548     
3549     indexOfNav : function()
3550     {
3551         
3552         var prev = false;
3553         Roo.each(this.navItems, function(v,i){
3554             
3555             if (v.isActive()) {
3556                 prev = i;
3557                 
3558             }
3559             
3560         });
3561         return prev;
3562     },
3563     /**
3564     * adds a Navigation item
3565     * @param {Roo.bootstrap.NavItem} the navitem to add
3566     */
3567     addItem : function(cfg)
3568     {
3569         var cn = new Roo.bootstrap.NavItem(cfg);
3570         this.register(cn);
3571         cn.parentId = this.id;
3572         cn.onRender(this.el, null);
3573         return cn;
3574     },
3575     /**
3576     * register a Navigation item
3577     * @param {Roo.bootstrap.NavItem} the navitem to add
3578     */
3579     register : function(item)
3580     {
3581         this.navItems.push( item);
3582         item.navId = this.navId;
3583     
3584     },
3585     
3586     /**
3587     * clear all the Navigation item
3588     */
3589    
3590     clearAll : function()
3591     {
3592         this.navItems = [];
3593         this.el.dom.innerHTML = '';
3594     },
3595     
3596     getNavItem: function(tabId)
3597     {
3598         var ret = false;
3599         Roo.each(this.navItems, function(e) {
3600             if (e.tabId == tabId) {
3601                ret =  e;
3602                return false;
3603             }
3604             return true;
3605             
3606         });
3607         return ret;
3608     },
3609     
3610     setActiveNext : function()
3611     {
3612         var i = this.indexOfNav(this.getActive());
3613         if (i > this.navItems.length) {
3614             return;
3615         }
3616         this.setActiveItem(this.navItems[i+1]);
3617     },
3618     setActivePrev : function()
3619     {
3620         var i = this.indexOfNav(this.getActive());
3621         if (i  < 1) {
3622             return;
3623         }
3624         this.setActiveItem(this.navItems[i-1]);
3625     },
3626     clearWasActive : function(except) {
3627         Roo.each(this.navItems, function(e) {
3628             if (e.tabId != except.tabId && e.was_active) {
3629                e.was_active = false;
3630                return false;
3631             }
3632             return true;
3633             
3634         });
3635     },
3636     getWasActive : function ()
3637     {
3638         var r = false;
3639         Roo.each(this.navItems, function(e) {
3640             if (e.was_active) {
3641                r = e;
3642                return false;
3643             }
3644             return true;
3645             
3646         });
3647         return r;
3648     }
3649     
3650     
3651 });
3652
3653  
3654 Roo.apply(Roo.bootstrap.NavGroup, {
3655     
3656     groups: {},
3657      /**
3658     * register a Navigation Group
3659     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3660     */
3661     register : function(navgrp)
3662     {
3663         this.groups[navgrp.navId] = navgrp;
3664         
3665     },
3666     /**
3667     * fetch a Navigation Group based on the navigation ID
3668     * @param {string} the navgroup to add
3669     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3670     */
3671     get: function(navId) {
3672         if (typeof(this.groups[navId]) == 'undefined') {
3673             return false;
3674             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3675         }
3676         return this.groups[navId] ;
3677     }
3678     
3679     
3680     
3681 });
3682
3683  /*
3684  * - LGPL
3685  *
3686  * row
3687  * 
3688  */
3689
3690 /**
3691  * @class Roo.bootstrap.NavItem
3692  * @extends Roo.bootstrap.Component
3693  * Bootstrap Navbar.NavItem class
3694  * @cfg {String} href  link to
3695  * @cfg {String} html content of button
3696  * @cfg {String} badge text inside badge
3697  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3698  * @cfg {String} glyphicon name of glyphicon
3699  * @cfg {String} icon name of font awesome icon
3700  * @cfg {Boolean} active Is item active
3701  * @cfg {Boolean} disabled Is item disabled
3702  
3703  * @cfg {Boolean} preventDefault (true | false) default false
3704  * @cfg {String} tabId the tab that this item activates.
3705  * @cfg {String} tagtype (a|span) render as a href or span?
3706   
3707  * @constructor
3708  * Create a new Navbar Item
3709  * @param {Object} config The config object
3710  */
3711 Roo.bootstrap.NavItem = function(config){
3712     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3713     this.addEvents({
3714         // raw events
3715         /**
3716          * @event click
3717          * The raw click event for the entire grid.
3718          * @param {Roo.EventObject} e
3719          */
3720         "click" : true,
3721          /**
3722             * @event changed
3723             * Fires when the active item active state changes
3724             * @param {Roo.bootstrap.NavItem} this
3725             * @param {boolean} state the new state
3726              
3727          */
3728         'changed': true
3729     });
3730    
3731 };
3732
3733 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3734     
3735     href: false,
3736     html: '',
3737     badge: '',
3738     icon: false,
3739     glyphicon: false,
3740     active: false,
3741     preventDefault : false,
3742     tabId : false,
3743     tagtype : 'a',
3744     disabled : false,
3745     
3746     was_active : false,
3747     
3748     getAutoCreate : function(){
3749          
3750         var cfg = {
3751             tag: 'li',
3752             cls: 'nav-item'
3753             
3754         }
3755         if (this.active) {
3756             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3757         }
3758         if (this.disabled) {
3759             cfg.cls += ' disabled';
3760         }
3761         
3762         if (this.href || this.html || this.glyphicon || this.icon) {
3763             cfg.cn = [
3764                 {
3765                     tag: this.tagtype,
3766                     href : this.href || "#",
3767                     html: this.html || ''
3768                 }
3769             ];
3770             
3771             if (this.icon) {
3772                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3773             }
3774
3775             if(this.glyphicon) {
3776                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3777             }
3778             
3779             if (this.menu) {
3780                 
3781                 cfg.cn[0].html += " <span class='caret'></span>";
3782              
3783             }
3784             
3785             if (this.badge !== '') {
3786                  
3787                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3788             }
3789         }
3790         
3791         
3792         
3793         return cfg;
3794     },
3795     initEvents: function() 
3796     {
3797         if (typeof (this.menu) != 'undefined') {
3798             this.menu.parentType = this.xtype;
3799             this.menu.triggerEl = this.el;
3800             this.menu = this.addxtype(Roo.apply({}, this.menu));
3801         }
3802         
3803         this.el.select('a',true).on('click', this.onClick, this);
3804         
3805         if(this.tagtype == 'span'){
3806             this.el.select('span',true).on('click', this.onClick, this);
3807         }
3808        
3809         // at this point parent should be available..
3810         this.parent().register(this);
3811     },
3812     
3813     onClick : function(e)
3814     {
3815         if(this.preventDefault || this.href == '#'){
3816             e.preventDefault();
3817         }
3818         
3819         if (this.disabled) {
3820             return;
3821         }
3822         
3823         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3824         if (tg && tg.transition) {
3825             Roo.log("waiting for the transitionend");
3826             return;
3827         }
3828         
3829         Roo.log("fire event clicked");
3830         if(this.fireEvent('click', this, e) === false){
3831             return;
3832         };
3833         
3834         if(this.tagtype == 'span'){
3835             return;
3836         }
3837         
3838         var p = this.parent();
3839         if (['tabs','pills'].indexOf(p.type)!==-1) {
3840             if (typeof(p.setActiveItem) !== 'undefined') {
3841                 p.setActiveItem(this);
3842             }
3843         }
3844         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3845         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3846             // remove the collapsed menu expand...
3847             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3848         }
3849         
3850     },
3851     
3852     isActive: function () {
3853         return this.active
3854     },
3855     setActive : function(state, fire, is_was_active)
3856     {
3857         if (this.active && !state & this.navId) {
3858             this.was_active = true;
3859             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3860             if (nv) {
3861                 nv.clearWasActive(this);
3862             }
3863             
3864         }
3865         this.active = state;
3866         
3867         if (!state ) {
3868             this.el.removeClass('active');
3869         } else if (!this.el.hasClass('active')) {
3870             this.el.addClass('active');
3871         }
3872         if (fire) {
3873             this.fireEvent('changed', this, state);
3874         }
3875         
3876         // show a panel if it's registered and related..
3877         
3878         if (!this.navId || !this.tabId || !state || is_was_active) {
3879             return;
3880         }
3881         
3882         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3883         if (!tg) {
3884             return;
3885         }
3886         var pan = tg.getPanelByName(this.tabId);
3887         if (!pan) {
3888             return;
3889         }
3890         // if we can not flip to new panel - go back to old nav highlight..
3891         if (false == tg.showPanel(pan)) {
3892             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3893             if (nv) {
3894                 var onav = nv.getWasActive();
3895                 if (onav) {
3896                     onav.setActive(true, false, true);
3897                 }
3898             }
3899             
3900         }
3901         
3902         
3903         
3904     },
3905      // this should not be here...
3906     setDisabled : function(state)
3907     {
3908         this.disabled = state;
3909         if (!state ) {
3910             this.el.removeClass('disabled');
3911         } else if (!this.el.hasClass('disabled')) {
3912             this.el.addClass('disabled');
3913         }
3914         
3915     },
3916     
3917     /**
3918      * Fetch the element to display the tooltip on.
3919      * @return {Roo.Element} defaults to this.el
3920      */
3921     tooltipEl : function()
3922     {
3923         return this.el.select('' + this.tagtype + '', true).first();
3924     }
3925 });
3926  
3927
3928  /*
3929  * - LGPL
3930  *
3931  * sidebar item
3932  *
3933  *  li
3934  *    <span> icon </span>
3935  *    <span> text </span>
3936  *    <span>badge </span>
3937  */
3938
3939 /**
3940  * @class Roo.bootstrap.NavSidebarItem
3941  * @extends Roo.bootstrap.NavItem
3942  * Bootstrap Navbar.NavSidebarItem class
3943  * @constructor
3944  * Create a new Navbar Button
3945  * @param {Object} config The config object
3946  */
3947 Roo.bootstrap.NavSidebarItem = function(config){
3948     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3949     this.addEvents({
3950         // raw events
3951         /**
3952          * @event click
3953          * The raw click event for the entire grid.
3954          * @param {Roo.EventObject} e
3955          */
3956         "click" : true,
3957          /**
3958             * @event changed
3959             * Fires when the active item active state changes
3960             * @param {Roo.bootstrap.NavSidebarItem} this
3961             * @param {boolean} state the new state
3962              
3963          */
3964         'changed': true
3965     });
3966    
3967 };
3968
3969 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
3970     
3971     
3972     getAutoCreate : function(){
3973         
3974         
3975         var a = {
3976                 tag: 'a',
3977                 href : this.href || '#',
3978                 cls: '',
3979                 html : '',
3980                 cn : []
3981         };
3982         var cfg = {
3983             tag: 'li',
3984             cls: '',
3985             cn: [ a ]
3986         }
3987         var span = {
3988             tag: 'span',
3989             html : this.html || ''
3990         }
3991         
3992         
3993         if (this.active) {
3994             cfg.cls += ' active';
3995         }
3996         
3997         // left icon..
3998         if (this.glyphicon || this.icon) {
3999             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4000             a.cn.push({ tag : 'i', cls : c }) ;
4001         }
4002         // html..
4003         a.cn.push(span);
4004         // then badge..
4005         if (this.badge !== '') {
4006             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4007         }
4008         // fi
4009         if (this.menu) {
4010             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4011             a.cls += 'dropdown-toggle treeview' ;
4012             
4013         }
4014         
4015         
4016         
4017         return cfg;
4018          
4019            
4020     }
4021    
4022      
4023  
4024 });
4025  
4026
4027  /*
4028  * - LGPL
4029  *
4030  * row
4031  * 
4032  */
4033
4034 /**
4035  * @class Roo.bootstrap.Row
4036  * @extends Roo.bootstrap.Component
4037  * Bootstrap Row class (contains columns...)
4038  * 
4039  * @constructor
4040  * Create a new Row
4041  * @param {Object} config The config object
4042  */
4043
4044 Roo.bootstrap.Row = function(config){
4045     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4046 };
4047
4048 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4049     
4050     getAutoCreate : function(){
4051        return {
4052             cls: 'row clearfix'
4053        };
4054     }
4055     
4056     
4057 });
4058
4059  
4060
4061  /*
4062  * - LGPL
4063  *
4064  * element
4065  * 
4066  */
4067
4068 /**
4069  * @class Roo.bootstrap.Element
4070  * @extends Roo.bootstrap.Component
4071  * Bootstrap Element class
4072  * @cfg {String} html contents of the element
4073  * @cfg {String} tag tag of the element
4074  * @cfg {String} cls class of the element
4075  * 
4076  * @constructor
4077  * Create a new Element
4078  * @param {Object} config The config object
4079  */
4080
4081 Roo.bootstrap.Element = function(config){
4082     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4083 };
4084
4085 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4086     
4087     tag: 'div',
4088     cls: '',
4089     html: '',
4090      
4091     
4092     getAutoCreate : function(){
4093         
4094         var cfg = {
4095             tag: this.tag,
4096             cls: this.cls,
4097             html: this.html
4098         }
4099         
4100         
4101         
4102         return cfg;
4103     }
4104    
4105 });
4106
4107  
4108
4109  /*
4110  * - LGPL
4111  *
4112  * pagination
4113  * 
4114  */
4115
4116 /**
4117  * @class Roo.bootstrap.Pagination
4118  * @extends Roo.bootstrap.Component
4119  * Bootstrap Pagination class
4120  * @cfg {String} size xs | sm | md | lg
4121  * @cfg {Boolean} inverse false | true
4122  * 
4123  * @constructor
4124  * Create a new Pagination
4125  * @param {Object} config The config object
4126  */
4127
4128 Roo.bootstrap.Pagination = function(config){
4129     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4130 };
4131
4132 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4133     
4134     cls: false,
4135     size: false,
4136     inverse: false,
4137     
4138     getAutoCreate : function(){
4139         var cfg = {
4140             tag: 'ul',
4141                 cls: 'pagination'
4142         };
4143         if (this.inverse) {
4144             cfg.cls += ' inverse';
4145         }
4146         if (this.html) {
4147             cfg.html=this.html;
4148         }
4149         if (this.cls) {
4150             cfg.cls += " " + this.cls;
4151         }
4152         return cfg;
4153     }
4154    
4155 });
4156
4157  
4158
4159  /*
4160  * - LGPL
4161  *
4162  * Pagination item
4163  * 
4164  */
4165
4166
4167 /**
4168  * @class Roo.bootstrap.PaginationItem
4169  * @extends Roo.bootstrap.Component
4170  * Bootstrap PaginationItem class
4171  * @cfg {String} html text
4172  * @cfg {String} href the link
4173  * @cfg {Boolean} preventDefault (true | false) default true
4174  * @cfg {Boolean} active (true | false) default false
4175  * @cfg {Boolean} disabled default false
4176  * 
4177  * 
4178  * @constructor
4179  * Create a new PaginationItem
4180  * @param {Object} config The config object
4181  */
4182
4183
4184 Roo.bootstrap.PaginationItem = function(config){
4185     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4186     this.addEvents({
4187         // raw events
4188         /**
4189          * @event click
4190          * The raw click event for the entire grid.
4191          * @param {Roo.EventObject} e
4192          */
4193         "click" : true
4194     });
4195 };
4196
4197 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4198     
4199     href : false,
4200     html : false,
4201     preventDefault: true,
4202     active : false,
4203     cls : false,
4204     disabled: false,
4205     
4206     getAutoCreate : function(){
4207         var cfg= {
4208             tag: 'li',
4209             cn: [
4210                 {
4211                     tag : 'a',
4212                     href : this.href ? this.href : '#',
4213                     html : this.html ? this.html : ''
4214                 }
4215             ]
4216         };
4217         
4218         if(this.cls){
4219             cfg.cls = this.cls;
4220         }
4221         
4222         if(this.disabled){
4223             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4224         }
4225         
4226         if(this.active){
4227             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4228         }
4229         
4230         return cfg;
4231     },
4232     
4233     initEvents: function() {
4234         
4235         this.el.on('click', this.onClick, this);
4236         
4237     },
4238     onClick : function(e)
4239     {
4240         Roo.log('PaginationItem on click ');
4241         if(this.preventDefault){
4242             e.preventDefault();
4243         }
4244         
4245         if(this.disabled){
4246             return;
4247         }
4248         
4249         this.fireEvent('click', this, e);
4250     }
4251    
4252 });
4253
4254  
4255
4256  /*
4257  * - LGPL
4258  *
4259  * slider
4260  * 
4261  */
4262
4263
4264 /**
4265  * @class Roo.bootstrap.Slider
4266  * @extends Roo.bootstrap.Component
4267  * Bootstrap Slider class
4268  *    
4269  * @constructor
4270  * Create a new Slider
4271  * @param {Object} config The config object
4272  */
4273
4274 Roo.bootstrap.Slider = function(config){
4275     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4276 };
4277
4278 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4279     
4280     getAutoCreate : function(){
4281         
4282         var cfg = {
4283             tag: 'div',
4284             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4285             cn: [
4286                 {
4287                     tag: 'a',
4288                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4289                 }
4290             ]
4291         }
4292         
4293         return cfg;
4294     }
4295    
4296 });
4297
4298  /*
4299  * Based on:
4300  * Ext JS Library 1.1.1
4301  * Copyright(c) 2006-2007, Ext JS, LLC.
4302  *
4303  * Originally Released Under LGPL - original licence link has changed is not relivant.
4304  *
4305  * Fork - LGPL
4306  * <script type="text/javascript">
4307  */
4308  
4309
4310 /**
4311  * @class Roo.grid.ColumnModel
4312  * @extends Roo.util.Observable
4313  * This is the default implementation of a ColumnModel used by the Grid. It defines
4314  * the columns in the grid.
4315  * <br>Usage:<br>
4316  <pre><code>
4317  var colModel = new Roo.grid.ColumnModel([
4318         {header: "Ticker", width: 60, sortable: true, locked: true},
4319         {header: "Company Name", width: 150, sortable: true},
4320         {header: "Market Cap.", width: 100, sortable: true},
4321         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4322         {header: "Employees", width: 100, sortable: true, resizable: false}
4323  ]);
4324  </code></pre>
4325  * <p>
4326  
4327  * The config options listed for this class are options which may appear in each
4328  * individual column definition.
4329  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4330  * @constructor
4331  * @param {Object} config An Array of column config objects. See this class's
4332  * config objects for details.
4333 */
4334 Roo.grid.ColumnModel = function(config){
4335         /**
4336      * The config passed into the constructor
4337      */
4338     this.config = config;
4339     this.lookup = {};
4340
4341     // if no id, create one
4342     // if the column does not have a dataIndex mapping,
4343     // map it to the order it is in the config
4344     for(var i = 0, len = config.length; i < len; i++){
4345         var c = config[i];
4346         if(typeof c.dataIndex == "undefined"){
4347             c.dataIndex = i;
4348         }
4349         if(typeof c.renderer == "string"){
4350             c.renderer = Roo.util.Format[c.renderer];
4351         }
4352         if(typeof c.id == "undefined"){
4353             c.id = Roo.id();
4354         }
4355         if(c.editor && c.editor.xtype){
4356             c.editor  = Roo.factory(c.editor, Roo.grid);
4357         }
4358         if(c.editor && c.editor.isFormField){
4359             c.editor = new Roo.grid.GridEditor(c.editor);
4360         }
4361         this.lookup[c.id] = c;
4362     }
4363
4364     /**
4365      * The width of columns which have no width specified (defaults to 100)
4366      * @type Number
4367      */
4368     this.defaultWidth = 100;
4369
4370     /**
4371      * Default sortable of columns which have no sortable specified (defaults to false)
4372      * @type Boolean
4373      */
4374     this.defaultSortable = false;
4375
4376     this.addEvents({
4377         /**
4378              * @event widthchange
4379              * Fires when the width of a column changes.
4380              * @param {ColumnModel} this
4381              * @param {Number} columnIndex The column index
4382              * @param {Number} newWidth The new width
4383              */
4384             "widthchange": true,
4385         /**
4386              * @event headerchange
4387              * Fires when the text of a header changes.
4388              * @param {ColumnModel} this
4389              * @param {Number} columnIndex The column index
4390              * @param {Number} newText The new header text
4391              */
4392             "headerchange": true,
4393         /**
4394              * @event hiddenchange
4395              * Fires when a column is hidden or "unhidden".
4396              * @param {ColumnModel} this
4397              * @param {Number} columnIndex The column index
4398              * @param {Boolean} hidden true if hidden, false otherwise
4399              */
4400             "hiddenchange": true,
4401             /**
4402          * @event columnmoved
4403          * Fires when a column is moved.
4404          * @param {ColumnModel} this
4405          * @param {Number} oldIndex
4406          * @param {Number} newIndex
4407          */
4408         "columnmoved" : true,
4409         /**
4410          * @event columlockchange
4411          * Fires when a column's locked state is changed
4412          * @param {ColumnModel} this
4413          * @param {Number} colIndex
4414          * @param {Boolean} locked true if locked
4415          */
4416         "columnlockchange" : true
4417     });
4418     Roo.grid.ColumnModel.superclass.constructor.call(this);
4419 };
4420 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4421     /**
4422      * @cfg {String} header The header text to display in the Grid view.
4423      */
4424     /**
4425      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4426      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4427      * specified, the column's index is used as an index into the Record's data Array.
4428      */
4429     /**
4430      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4431      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4432      */
4433     /**
4434      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4435      * Defaults to the value of the {@link #defaultSortable} property.
4436      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4437      */
4438     /**
4439      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4440      */
4441     /**
4442      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4443      */
4444     /**
4445      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4446      */
4447     /**
4448      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4449      */
4450     /**
4451      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4452      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4453      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4454      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4455      */
4456        /**
4457      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4458      */
4459     /**
4460      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4461      */
4462     /**
4463      * @cfg {String} cursor (Optional)
4464      */
4465     /**
4466      * @cfg {String} tooltip (Optional)
4467      */
4468     /**
4469      * Returns the id of the column at the specified index.
4470      * @param {Number} index The column index
4471      * @return {String} the id
4472      */
4473     getColumnId : function(index){
4474         return this.config[index].id;
4475     },
4476
4477     /**
4478      * Returns the column for a specified id.
4479      * @param {String} id The column id
4480      * @return {Object} the column
4481      */
4482     getColumnById : function(id){
4483         return this.lookup[id];
4484     },
4485
4486     
4487     /**
4488      * Returns the column for a specified dataIndex.
4489      * @param {String} dataIndex The column dataIndex
4490      * @return {Object|Boolean} the column or false if not found
4491      */
4492     getColumnByDataIndex: function(dataIndex){
4493         var index = this.findColumnIndex(dataIndex);
4494         return index > -1 ? this.config[index] : false;
4495     },
4496     
4497     /**
4498      * Returns the index for a specified column id.
4499      * @param {String} id The column id
4500      * @return {Number} the index, or -1 if not found
4501      */
4502     getIndexById : function(id){
4503         for(var i = 0, len = this.config.length; i < len; i++){
4504             if(this.config[i].id == id){
4505                 return i;
4506             }
4507         }
4508         return -1;
4509     },
4510     
4511     /**
4512      * Returns the index for a specified column dataIndex.
4513      * @param {String} dataIndex The column dataIndex
4514      * @return {Number} the index, or -1 if not found
4515      */
4516     
4517     findColumnIndex : function(dataIndex){
4518         for(var i = 0, len = this.config.length; i < len; i++){
4519             if(this.config[i].dataIndex == dataIndex){
4520                 return i;
4521             }
4522         }
4523         return -1;
4524     },
4525     
4526     
4527     moveColumn : function(oldIndex, newIndex){
4528         var c = this.config[oldIndex];
4529         this.config.splice(oldIndex, 1);
4530         this.config.splice(newIndex, 0, c);
4531         this.dataMap = null;
4532         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4533     },
4534
4535     isLocked : function(colIndex){
4536         return this.config[colIndex].locked === true;
4537     },
4538
4539     setLocked : function(colIndex, value, suppressEvent){
4540         if(this.isLocked(colIndex) == value){
4541             return;
4542         }
4543         this.config[colIndex].locked = value;
4544         if(!suppressEvent){
4545             this.fireEvent("columnlockchange", this, colIndex, value);
4546         }
4547     },
4548
4549     getTotalLockedWidth : function(){
4550         var totalWidth = 0;
4551         for(var i = 0; i < this.config.length; i++){
4552             if(this.isLocked(i) && !this.isHidden(i)){
4553                 this.totalWidth += this.getColumnWidth(i);
4554             }
4555         }
4556         return totalWidth;
4557     },
4558
4559     getLockedCount : function(){
4560         for(var i = 0, len = this.config.length; i < len; i++){
4561             if(!this.isLocked(i)){
4562                 return i;
4563             }
4564         }
4565     },
4566
4567     /**
4568      * Returns the number of columns.
4569      * @return {Number}
4570      */
4571     getColumnCount : function(visibleOnly){
4572         if(visibleOnly === true){
4573             var c = 0;
4574             for(var i = 0, len = this.config.length; i < len; i++){
4575                 if(!this.isHidden(i)){
4576                     c++;
4577                 }
4578             }
4579             return c;
4580         }
4581         return this.config.length;
4582     },
4583
4584     /**
4585      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4586      * @param {Function} fn
4587      * @param {Object} scope (optional)
4588      * @return {Array} result
4589      */
4590     getColumnsBy : function(fn, scope){
4591         var r = [];
4592         for(var i = 0, len = this.config.length; i < len; i++){
4593             var c = this.config[i];
4594             if(fn.call(scope||this, c, i) === true){
4595                 r[r.length] = c;
4596             }
4597         }
4598         return r;
4599     },
4600
4601     /**
4602      * Returns true if the specified column is sortable.
4603      * @param {Number} col The column index
4604      * @return {Boolean}
4605      */
4606     isSortable : function(col){
4607         if(typeof this.config[col].sortable == "undefined"){
4608             return this.defaultSortable;
4609         }
4610         return this.config[col].sortable;
4611     },
4612
4613     /**
4614      * Returns the rendering (formatting) function defined for the column.
4615      * @param {Number} col The column index.
4616      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4617      */
4618     getRenderer : function(col){
4619         if(!this.config[col].renderer){
4620             return Roo.grid.ColumnModel.defaultRenderer;
4621         }
4622         return this.config[col].renderer;
4623     },
4624
4625     /**
4626      * Sets the rendering (formatting) function for a column.
4627      * @param {Number} col The column index
4628      * @param {Function} fn The function to use to process the cell's raw data
4629      * to return HTML markup for the grid view. The render function is called with
4630      * the following parameters:<ul>
4631      * <li>Data value.</li>
4632      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4633      * <li>css A CSS style string to apply to the table cell.</li>
4634      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4635      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4636      * <li>Row index</li>
4637      * <li>Column index</li>
4638      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4639      */
4640     setRenderer : function(col, fn){
4641         this.config[col].renderer = fn;
4642     },
4643
4644     /**
4645      * Returns the width for the specified column.
4646      * @param {Number} col The column index
4647      * @return {Number}
4648      */
4649     getColumnWidth : function(col){
4650         return this.config[col].width * 1 || this.defaultWidth;
4651     },
4652
4653     /**
4654      * Sets the width for a column.
4655      * @param {Number} col The column index
4656      * @param {Number} width The new width
4657      */
4658     setColumnWidth : function(col, width, suppressEvent){
4659         this.config[col].width = width;
4660         this.totalWidth = null;
4661         if(!suppressEvent){
4662              this.fireEvent("widthchange", this, col, width);
4663         }
4664     },
4665
4666     /**
4667      * Returns the total width of all columns.
4668      * @param {Boolean} includeHidden True to include hidden column widths
4669      * @return {Number}
4670      */
4671     getTotalWidth : function(includeHidden){
4672         if(!this.totalWidth){
4673             this.totalWidth = 0;
4674             for(var i = 0, len = this.config.length; i < len; i++){
4675                 if(includeHidden || !this.isHidden(i)){
4676                     this.totalWidth += this.getColumnWidth(i);
4677                 }
4678             }
4679         }
4680         return this.totalWidth;
4681     },
4682
4683     /**
4684      * Returns the header for the specified column.
4685      * @param {Number} col The column index
4686      * @return {String}
4687      */
4688     getColumnHeader : function(col){
4689         return this.config[col].header;
4690     },
4691
4692     /**
4693      * Sets the header for a column.
4694      * @param {Number} col The column index
4695      * @param {String} header The new header
4696      */
4697     setColumnHeader : function(col, header){
4698         this.config[col].header = header;
4699         this.fireEvent("headerchange", this, col, header);
4700     },
4701
4702     /**
4703      * Returns the tooltip for the specified column.
4704      * @param {Number} col The column index
4705      * @return {String}
4706      */
4707     getColumnTooltip : function(col){
4708             return this.config[col].tooltip;
4709     },
4710     /**
4711      * Sets the tooltip for a column.
4712      * @param {Number} col The column index
4713      * @param {String} tooltip The new tooltip
4714      */
4715     setColumnTooltip : function(col, tooltip){
4716             this.config[col].tooltip = tooltip;
4717     },
4718
4719     /**
4720      * Returns the dataIndex for the specified column.
4721      * @param {Number} col The column index
4722      * @return {Number}
4723      */
4724     getDataIndex : function(col){
4725         return this.config[col].dataIndex;
4726     },
4727
4728     /**
4729      * Sets the dataIndex for a column.
4730      * @param {Number} col The column index
4731      * @param {Number} dataIndex The new dataIndex
4732      */
4733     setDataIndex : function(col, dataIndex){
4734         this.config[col].dataIndex = dataIndex;
4735     },
4736
4737     
4738     
4739     /**
4740      * Returns true if the cell is editable.
4741      * @param {Number} colIndex The column index
4742      * @param {Number} rowIndex The row index
4743      * @return {Boolean}
4744      */
4745     isCellEditable : function(colIndex, rowIndex){
4746         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4747     },
4748
4749     /**
4750      * Returns the editor defined for the cell/column.
4751      * return false or null to disable editing.
4752      * @param {Number} colIndex The column index
4753      * @param {Number} rowIndex The row index
4754      * @return {Object}
4755      */
4756     getCellEditor : function(colIndex, rowIndex){
4757         return this.config[colIndex].editor;
4758     },
4759
4760     /**
4761      * Sets if a column is editable.
4762      * @param {Number} col The column index
4763      * @param {Boolean} editable True if the column is editable
4764      */
4765     setEditable : function(col, editable){
4766         this.config[col].editable = editable;
4767     },
4768
4769
4770     /**
4771      * Returns true if the column is hidden.
4772      * @param {Number} colIndex The column index
4773      * @return {Boolean}
4774      */
4775     isHidden : function(colIndex){
4776         return this.config[colIndex].hidden;
4777     },
4778
4779
4780     /**
4781      * Returns true if the column width cannot be changed
4782      */
4783     isFixed : function(colIndex){
4784         return this.config[colIndex].fixed;
4785     },
4786
4787     /**
4788      * Returns true if the column can be resized
4789      * @return {Boolean}
4790      */
4791     isResizable : function(colIndex){
4792         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4793     },
4794     /**
4795      * Sets if a column is hidden.
4796      * @param {Number} colIndex The column index
4797      * @param {Boolean} hidden True if the column is hidden
4798      */
4799     setHidden : function(colIndex, hidden){
4800         this.config[colIndex].hidden = hidden;
4801         this.totalWidth = null;
4802         this.fireEvent("hiddenchange", this, colIndex, hidden);
4803     },
4804
4805     /**
4806      * Sets the editor for a column.
4807      * @param {Number} col The column index
4808      * @param {Object} editor The editor object
4809      */
4810     setEditor : function(col, editor){
4811         this.config[col].editor = editor;
4812     }
4813 });
4814
4815 Roo.grid.ColumnModel.defaultRenderer = function(value){
4816         if(typeof value == "string" && value.length < 1){
4817             return "&#160;";
4818         }
4819         return value;
4820 };
4821
4822 // Alias for backwards compatibility
4823 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4824 /*
4825  * Based on:
4826  * Ext JS Library 1.1.1
4827  * Copyright(c) 2006-2007, Ext JS, LLC.
4828  *
4829  * Originally Released Under LGPL - original licence link has changed is not relivant.
4830  *
4831  * Fork - LGPL
4832  * <script type="text/javascript">
4833  */
4834  
4835 /**
4836  * @class Roo.LoadMask
4837  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4838  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4839  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4840  * element's UpdateManager load indicator and will be destroyed after the initial load.
4841  * @constructor
4842  * Create a new LoadMask
4843  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4844  * @param {Object} config The config object
4845  */
4846 Roo.LoadMask = function(el, config){
4847     this.el = Roo.get(el);
4848     Roo.apply(this, config);
4849     if(this.store){
4850         this.store.on('beforeload', this.onBeforeLoad, this);
4851         this.store.on('load', this.onLoad, this);
4852         this.store.on('loadexception', this.onLoadException, this);
4853         this.removeMask = false;
4854     }else{
4855         var um = this.el.getUpdateManager();
4856         um.showLoadIndicator = false; // disable the default indicator
4857         um.on('beforeupdate', this.onBeforeLoad, this);
4858         um.on('update', this.onLoad, this);
4859         um.on('failure', this.onLoad, this);
4860         this.removeMask = true;
4861     }
4862 };
4863
4864 Roo.LoadMask.prototype = {
4865     /**
4866      * @cfg {Boolean} removeMask
4867      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4868      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4869      */
4870     /**
4871      * @cfg {String} msg
4872      * The text to display in a centered loading message box (defaults to 'Loading...')
4873      */
4874     msg : 'Loading...',
4875     /**
4876      * @cfg {String} msgCls
4877      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4878      */
4879     msgCls : 'x-mask-loading',
4880
4881     /**
4882      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4883      * @type Boolean
4884      */
4885     disabled: false,
4886
4887     /**
4888      * Disables the mask to prevent it from being displayed
4889      */
4890     disable : function(){
4891        this.disabled = true;
4892     },
4893
4894     /**
4895      * Enables the mask so that it can be displayed
4896      */
4897     enable : function(){
4898         this.disabled = false;
4899     },
4900     
4901     onLoadException : function()
4902     {
4903         Roo.log(arguments);
4904         
4905         if (typeof(arguments[3]) != 'undefined') {
4906             Roo.MessageBox.alert("Error loading",arguments[3]);
4907         } 
4908         /*
4909         try {
4910             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4911                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4912             }   
4913         } catch(e) {
4914             
4915         }
4916         */
4917     
4918         
4919         
4920         this.el.unmask(this.removeMask);
4921     },
4922     // private
4923     onLoad : function()
4924     {
4925         this.el.unmask(this.removeMask);
4926     },
4927
4928     // private
4929     onBeforeLoad : function(){
4930         if(!this.disabled){
4931             this.el.mask(this.msg, this.msgCls);
4932         }
4933     },
4934
4935     // private
4936     destroy : function(){
4937         if(this.store){
4938             this.store.un('beforeload', this.onBeforeLoad, this);
4939             this.store.un('load', this.onLoad, this);
4940             this.store.un('loadexception', this.onLoadException, this);
4941         }else{
4942             var um = this.el.getUpdateManager();
4943             um.un('beforeupdate', this.onBeforeLoad, this);
4944             um.un('update', this.onLoad, this);
4945             um.un('failure', this.onLoad, this);
4946         }
4947     }
4948 };/*
4949  * - LGPL
4950  *
4951  * table
4952  * 
4953  */
4954
4955 /**
4956  * @class Roo.bootstrap.Table
4957  * @extends Roo.bootstrap.Component
4958  * Bootstrap Table class
4959  * @cfg {String} cls table class
4960  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4961  * @cfg {String} bgcolor Specifies the background color for a table
4962  * @cfg {Number} border Specifies whether the table cells should have borders or not
4963  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4964  * @cfg {Number} cellspacing Specifies the space between cells
4965  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4966  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4967  * @cfg {String} sortable Specifies that the table should be sortable
4968  * @cfg {String} summary Specifies a summary of the content of a table
4969  * @cfg {Number} width Specifies the width of a table
4970  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4971  * 
4972  * @cfg {boolean} striped Should the rows be alternative striped
4973  * @cfg {boolean} bordered Add borders to the table
4974  * @cfg {boolean} hover Add hover highlighting
4975  * @cfg {boolean} condensed Format condensed
4976  * @cfg {boolean} responsive Format condensed
4977  * @cfg {Boolean} loadMask (true|false) default false
4978  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4979  * @cfg {Boolean} thead (true|false) generate thead, default true
4980  * @cfg {Boolean} RowSelection (true|false) default false
4981  * @cfg {Boolean} CellSelection (true|false) default false
4982  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
4983  
4984  * 
4985  * @constructor
4986  * Create a new Table
4987  * @param {Object} config The config object
4988  */
4989
4990 Roo.bootstrap.Table = function(config){
4991     Roo.bootstrap.Table.superclass.constructor.call(this, config);
4992     
4993     if (this.sm) {
4994         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4995         this.sm = this.selModel;
4996         this.sm.xmodule = this.xmodule || false;
4997     }
4998     if (this.cm && typeof(this.cm.config) == 'undefined') {
4999         this.colModel = new Roo.grid.ColumnModel(this.cm);
5000         this.cm = this.colModel;
5001         this.cm.xmodule = this.xmodule || false;
5002     }
5003     if (this.store) {
5004         this.store= Roo.factory(this.store, Roo.data);
5005         this.ds = this.store;
5006         this.ds.xmodule = this.xmodule || false;
5007          
5008     }
5009     if (this.footer && this.store) {
5010         this.footer.dataSource = this.ds;
5011         this.footer = Roo.factory(this.footer);
5012     }
5013     
5014     /** @private */
5015     this.addEvents({
5016         /**
5017          * @event cellclick
5018          * Fires when a cell is clicked
5019          * @param {Roo.bootstrap.Table} this
5020          * @param {Roo.Element} el
5021          * @param {Number} rowIndex
5022          * @param {Number} columnIndex
5023          * @param {Roo.EventObject} e
5024          */
5025         "cellclick" : true,
5026         /**
5027          * @event celldblclick
5028          * Fires when a cell is double clicked
5029          * @param {Roo.bootstrap.Table} this
5030          * @param {Roo.Element} el
5031          * @param {Number} rowIndex
5032          * @param {Number} columnIndex
5033          * @param {Roo.EventObject} e
5034          */
5035         "celldblclick" : true,
5036         /**
5037          * @event rowclick
5038          * Fires when a row is clicked
5039          * @param {Roo.bootstrap.Table} this
5040          * @param {Roo.Element} el
5041          * @param {Number} rowIndex
5042          * @param {Roo.EventObject} e
5043          */
5044         "rowclick" : true,
5045         /**
5046          * @event rowdblclick
5047          * Fires when a row is double clicked
5048          * @param {Roo.bootstrap.Table} this
5049          * @param {Roo.Element} el
5050          * @param {Number} rowIndex
5051          * @param {Roo.EventObject} e
5052          */
5053         "rowdblclick" : true,
5054         /**
5055          * @event mouseover
5056          * Fires when a mouseover occur
5057          * @param {Roo.bootstrap.Table} this
5058          * @param {Roo.Element} el
5059          * @param {Number} rowIndex
5060          * @param {Number} columnIndex
5061          * @param {Roo.EventObject} e
5062          */
5063         "mouseover" : true,
5064         /**
5065          * @event mouseout
5066          * Fires when a mouseout occur
5067          * @param {Roo.bootstrap.Table} this
5068          * @param {Roo.Element} el
5069          * @param {Number} rowIndex
5070          * @param {Number} columnIndex
5071          * @param {Roo.EventObject} e
5072          */
5073         "mouseout" : true,
5074         /**
5075          * @event rowclass
5076          * Fires when a row is rendered, so you can change add a style to it.
5077          * @param {Roo.bootstrap.Table} this
5078          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5079          */
5080         'rowclass' : true,
5081           /**
5082          * @event rowsrendered
5083          * Fires when all the  rows have been rendered
5084          * @param {Roo.bootstrap.Table} this
5085          */
5086         'rowsrendered' : true
5087         
5088     });
5089 };
5090
5091 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5092     
5093     cls: false,
5094     align: false,
5095     bgcolor: false,
5096     border: false,
5097     cellpadding: false,
5098     cellspacing: false,
5099     frame: false,
5100     rules: false,
5101     sortable: false,
5102     summary: false,
5103     width: false,
5104     striped : false,
5105     bordered: false,
5106     hover:  false,
5107     condensed : false,
5108     responsive : false,
5109     sm : false,
5110     cm : false,
5111     store : false,
5112     loadMask : false,
5113     tfoot : true,
5114     thead : true,
5115     RowSelection : false,
5116     CellSelection : false,
5117     layout : false,
5118     
5119     // Roo.Element - the tbody
5120     mainBody: false, 
5121     
5122     getAutoCreate : function(){
5123         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5124         
5125         cfg = {
5126             tag: 'table',
5127             cls : 'table',
5128             cn : []
5129         }
5130             
5131         if (this.striped) {
5132             cfg.cls += ' table-striped';
5133         }
5134         
5135         if (this.hover) {
5136             cfg.cls += ' table-hover';
5137         }
5138         if (this.bordered) {
5139             cfg.cls += ' table-bordered';
5140         }
5141         if (this.condensed) {
5142             cfg.cls += ' table-condensed';
5143         }
5144         if (this.responsive) {
5145             cfg.cls += ' table-responsive';
5146         }
5147         
5148         if (this.cls) {
5149             cfg.cls+=  ' ' +this.cls;
5150         }
5151         
5152         // this lot should be simplifed...
5153         
5154         if (this.align) {
5155             cfg.align=this.align;
5156         }
5157         if (this.bgcolor) {
5158             cfg.bgcolor=this.bgcolor;
5159         }
5160         if (this.border) {
5161             cfg.border=this.border;
5162         }
5163         if (this.cellpadding) {
5164             cfg.cellpadding=this.cellpadding;
5165         }
5166         if (this.cellspacing) {
5167             cfg.cellspacing=this.cellspacing;
5168         }
5169         if (this.frame) {
5170             cfg.frame=this.frame;
5171         }
5172         if (this.rules) {
5173             cfg.rules=this.rules;
5174         }
5175         if (this.sortable) {
5176             cfg.sortable=this.sortable;
5177         }
5178         if (this.summary) {
5179             cfg.summary=this.summary;
5180         }
5181         if (this.width) {
5182             cfg.width=this.width;
5183         }
5184         if (this.layout) {
5185             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5186         }
5187         
5188         if(this.store || this.cm){
5189             if(this.thead){
5190                 cfg.cn.push(this.renderHeader());
5191             }
5192             
5193             cfg.cn.push(this.renderBody());
5194             
5195             if(this.tfoot){
5196                 cfg.cn.push(this.renderFooter());
5197             }
5198             
5199             cfg.cls+=  ' TableGrid';
5200         }
5201         
5202         return { cn : [ cfg ] };
5203     },
5204     
5205     initEvents : function()
5206     {   
5207         if(!this.store || !this.cm){
5208             return;
5209         }
5210         
5211         //Roo.log('initEvents with ds!!!!');
5212         
5213         this.mainBody = this.el.select('tbody', true).first();
5214         
5215         
5216         var _this = this;
5217         
5218         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5219             e.on('click', _this.sort, _this);
5220         });
5221         
5222         this.el.on("click", this.onClick, this);
5223         this.el.on("dblclick", this.onDblClick, this);
5224         
5225         // why is this done????? = it breaks dialogs??
5226         //this.parent().el.setStyle('position', 'relative');
5227         
5228         
5229         if (this.footer) {
5230             this.footer.parentId = this.id;
5231             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5232         }
5233         
5234         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5235         
5236         this.store.on('load', this.onLoad, this);
5237         this.store.on('beforeload', this.onBeforeLoad, this);
5238         this.store.on('update', this.onUpdate, this);
5239         this.store.on('add', this.onAdd, this);
5240         
5241     },
5242     
5243     onMouseover : function(e, el)
5244     {
5245         var cell = Roo.get(el);
5246         
5247         if(!cell){
5248             return;
5249         }
5250         
5251         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5252             cell = cell.findParent('td', false, true);
5253         }
5254         
5255         var row = cell.findParent('tr', false, true);
5256         var cellIndex = cell.dom.cellIndex;
5257         var rowIndex = row.dom.rowIndex - 1; // start from 0
5258         
5259         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5260         
5261     },
5262     
5263     onMouseout : function(e, el)
5264     {
5265         var cell = Roo.get(el);
5266         
5267         if(!cell){
5268             return;
5269         }
5270         
5271         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5272             cell = cell.findParent('td', false, true);
5273         }
5274         
5275         var row = cell.findParent('tr', false, true);
5276         var cellIndex = cell.dom.cellIndex;
5277         var rowIndex = row.dom.rowIndex - 1; // start from 0
5278         
5279         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5280         
5281     },
5282     
5283     onClick : function(e, el)
5284     {
5285         var cell = Roo.get(el);
5286         
5287         if(!cell || (!this.CellSelection && !this.RowSelection)){
5288             return;
5289         }
5290         
5291         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5292             cell = cell.findParent('td', false, true);
5293         }
5294         
5295         if(!cell || typeof(cell) == 'undefined'){
5296             return;
5297         }
5298         
5299         var row = cell.findParent('tr', false, true);
5300         
5301         if(!row || typeof(row) == 'undefined'){
5302             return;
5303         }
5304         
5305         var cellIndex = cell.dom.cellIndex;
5306         var rowIndex = this.getRowIndex(row);
5307         
5308         if(this.CellSelection){
5309             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5310         }
5311         
5312         if(this.RowSelection){
5313             this.fireEvent('rowclick', this, row, rowIndex, e);
5314         }
5315         
5316         
5317     },
5318     
5319     onDblClick : function(e,el)
5320     {
5321         var cell = Roo.get(el);
5322         
5323         if(!cell || (!this.CellSelection && !this.RowSelection)){
5324             return;
5325         }
5326         
5327         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5328             cell = cell.findParent('td', false, true);
5329         }
5330         
5331         if(!cell || typeof(cell) == 'undefined'){
5332             return;
5333         }
5334         
5335         var row = cell.findParent('tr', false, true);
5336         
5337         if(!row || typeof(row) == 'undefined'){
5338             return;
5339         }
5340         
5341         var cellIndex = cell.dom.cellIndex;
5342         var rowIndex = this.getRowIndex(row);
5343         
5344         if(this.CellSelection){
5345             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5346         }
5347         
5348         if(this.RowSelection){
5349             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5350         }
5351     },
5352     
5353     sort : function(e,el)
5354     {
5355         var col = Roo.get(el);
5356         
5357         if(!col.hasClass('sortable')){
5358             return;
5359         }
5360         
5361         var sort = col.attr('sort');
5362         var dir = 'ASC';
5363         
5364         if(col.hasClass('glyphicon-arrow-up')){
5365             dir = 'DESC';
5366         }
5367         
5368         this.store.sortInfo = {field : sort, direction : dir};
5369         
5370         if (this.footer) {
5371             Roo.log("calling footer first");
5372             this.footer.onClick('first');
5373         } else {
5374         
5375             this.store.load({ params : { start : 0 } });
5376         }
5377     },
5378     
5379     renderHeader : function()
5380     {
5381         var header = {
5382             tag: 'thead',
5383             cn : []
5384         };
5385         
5386         var cm = this.cm;
5387         
5388         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5389             
5390             var config = cm.config[i];
5391                     
5392             var c = {
5393                 tag: 'th',
5394                 style : '',
5395                 html: cm.getColumnHeader(i)
5396             };
5397             
5398             if(typeof(config.tooltip) != 'undefined'){
5399                 c.tooltip = config.tooltip;
5400             }
5401             
5402             if(typeof(config.hidden) != 'undefined' && config.hidden){
5403                 c.style += ' display:none;';
5404             }
5405             
5406             if(typeof(config.dataIndex) != 'undefined'){
5407                 c.sort = config.dataIndex;
5408             }
5409             
5410             if(typeof(config.sortable) != 'undefined' && config.sortable){
5411                 c.cls = 'sortable';
5412             }
5413             
5414             if(typeof(config.align) != 'undefined' && config.align.length){
5415                 c.style += ' text-align:' + config.align + ';';
5416             }
5417             
5418             if(typeof(config.width) != 'undefined'){
5419                 c.style += ' width:' + config.width + 'px;';
5420             }
5421             
5422             header.cn.push(c)
5423         }
5424         
5425         return header;
5426     },
5427     
5428     renderBody : function()
5429     {
5430         var body = {
5431             tag: 'tbody',
5432             cn : [
5433                 {
5434                     tag: 'tr',
5435                     cn : [
5436                         {
5437                             tag : 'td',
5438                             colspan :  this.cm.getColumnCount()
5439                         }
5440                     ]
5441                 }
5442             ]
5443         };
5444         
5445         return body;
5446     },
5447     
5448     renderFooter : function()
5449     {
5450         var footer = {
5451             tag: 'tfoot',
5452             cn : [
5453                 {
5454                     tag: 'tr',
5455                     cn : [
5456                         {
5457                             tag : 'td',
5458                             colspan :  this.cm.getColumnCount()
5459                         }
5460                     ]
5461                 }
5462             ]
5463         };
5464         
5465         return footer;
5466     },
5467     
5468     
5469     
5470     onLoad : function()
5471     {
5472         Roo.log('ds onload');
5473         this.clear();
5474         
5475         var _this = this;
5476         var cm = this.cm;
5477         var ds = this.store;
5478         
5479         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5480             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5481             
5482             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5483                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5484             }
5485             
5486             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5487                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5488             }
5489         });
5490         
5491         var tbody =  this.mainBody;
5492               
5493         if(ds.getCount() > 0){
5494             ds.data.each(function(d,rowIndex){
5495                 var row =  this.renderRow(cm, ds, rowIndex);
5496                 
5497                 tbody.createChild(row);
5498                 
5499                 var _this = this;
5500                 
5501                 if(row.cellObjects.length){
5502                     Roo.each(row.cellObjects, function(r){
5503                         _this.renderCellObject(r);
5504                     })
5505                 }
5506                 
5507             }, this);
5508         }
5509         
5510         Roo.each(this.el.select('tbody td', true).elements, function(e){
5511             e.on('mouseover', _this.onMouseover, _this);
5512         });
5513         
5514         Roo.each(this.el.select('tbody td', true).elements, function(e){
5515             e.on('mouseout', _this.onMouseout, _this);
5516         });
5517         this.fireEvent('rowsrendered', this);
5518         //if(this.loadMask){
5519         //    this.maskEl.hide();
5520         //}
5521     },
5522     
5523     
5524     onUpdate : function(ds,record)
5525     {
5526         this.refreshRow(record);
5527     },
5528     
5529     onRemove : function(ds, record, index, isUpdate){
5530         if(isUpdate !== true){
5531             this.fireEvent("beforerowremoved", this, index, record);
5532         }
5533         var bt = this.mainBody.dom;
5534         
5535         var rows = this.el.select('tbody > tr', true).elements;
5536         
5537         if(typeof(rows[index]) != 'undefined'){
5538             bt.removeChild(rows[index].dom);
5539         }
5540         
5541 //        if(bt.rows[index]){
5542 //            bt.removeChild(bt.rows[index]);
5543 //        }
5544         
5545         if(isUpdate !== true){
5546             //this.stripeRows(index);
5547             //this.syncRowHeights(index, index);
5548             //this.layout();
5549             this.fireEvent("rowremoved", this, index, record);
5550         }
5551     },
5552     
5553     onAdd : function(ds, records, rowIndex)
5554     {
5555         //Roo.log('on Add called');
5556         // - note this does not handle multiple adding very well..
5557         var bt = this.mainBody.dom;
5558         for (var i =0 ; i < records.length;i++) {
5559             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5560             //Roo.log(records[i]);
5561             //Roo.log(this.store.getAt(rowIndex+i));
5562             this.insertRow(this.store, rowIndex + i, false);
5563             return;
5564         }
5565         
5566     },
5567     
5568     
5569     refreshRow : function(record){
5570         var ds = this.store, index;
5571         if(typeof record == 'number'){
5572             index = record;
5573             record = ds.getAt(index);
5574         }else{
5575             index = ds.indexOf(record);
5576         }
5577         this.insertRow(ds, index, true);
5578         this.onRemove(ds, record, index+1, true);
5579         //this.syncRowHeights(index, index);
5580         //this.layout();
5581         this.fireEvent("rowupdated", this, index, record);
5582     },
5583     
5584     insertRow : function(dm, rowIndex, isUpdate){
5585         
5586         if(!isUpdate){
5587             this.fireEvent("beforerowsinserted", this, rowIndex);
5588         }
5589             //var s = this.getScrollState();
5590         var row = this.renderRow(this.cm, this.store, rowIndex);
5591         // insert before rowIndex..
5592         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5593         
5594         var _this = this;
5595                 
5596         if(row.cellObjects.length){
5597             Roo.each(row.cellObjects, function(r){
5598                 _this.renderCellObject(r);
5599             })
5600         }
5601             
5602         if(!isUpdate){
5603             this.fireEvent("rowsinserted", this, rowIndex);
5604             //this.syncRowHeights(firstRow, lastRow);
5605             //this.stripeRows(firstRow);
5606             //this.layout();
5607         }
5608         
5609     },
5610     
5611     
5612     getRowDom : function(rowIndex)
5613     {
5614         var rows = this.el.select('tbody > tr', true).elements;
5615         
5616         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5617         
5618     },
5619     // returns the object tree for a tr..
5620   
5621     
5622     renderRow : function(cm, ds, rowIndex) 
5623     {
5624         
5625         var d = ds.getAt(rowIndex);
5626         
5627         var row = {
5628             tag : 'tr',
5629             cn : []
5630         };
5631             
5632         var cellObjects = [];
5633         
5634         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5635             var config = cm.config[i];
5636             
5637             var renderer = cm.getRenderer(i);
5638             var value = '';
5639             var id = false;
5640             
5641             if(typeof(renderer) !== 'undefined'){
5642                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5643             }
5644             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5645             // and are rendered into the cells after the row is rendered - using the id for the element.
5646             
5647             if(typeof(value) === 'object'){
5648                 id = Roo.id();
5649                 cellObjects.push({
5650                     container : id,
5651                     cfg : value 
5652                 })
5653             }
5654             
5655             var rowcfg = {
5656                 record: d,
5657                 rowIndex : rowIndex,
5658                 colIndex : i,
5659                 rowClass : ''
5660             }
5661
5662             this.fireEvent('rowclass', this, rowcfg);
5663             
5664             var td = {
5665                 tag: 'td',
5666                 cls : rowcfg.rowClass,
5667                 style: '',
5668                 html: (typeof(value) === 'object') ? '' : value
5669             };
5670             
5671             if (id) {
5672                 td.id = id;
5673             }
5674             
5675             if(typeof(config.hidden) != 'undefined' && config.hidden){
5676                 td.style += ' display:none;';
5677             }
5678             
5679             if(typeof(config.align) != 'undefined' && config.align.length){
5680                 td.style += ' text-align:' + config.align + ';';
5681             }
5682             
5683             if(typeof(config.width) != 'undefined'){
5684                 td.style += ' width:' +  config.width + 'px;';
5685             }
5686             
5687             if(typeof(config.cursor) != 'undefined'){
5688                 td.style += ' cursor:' +  config.cursor + ';';
5689             }
5690              
5691             row.cn.push(td);
5692            
5693         }
5694         
5695         row.cellObjects = cellObjects;
5696         
5697         return row;
5698           
5699     },
5700     
5701     
5702     
5703     onBeforeLoad : function()
5704     {
5705         //Roo.log('ds onBeforeLoad');
5706         
5707         //this.clear();
5708         
5709         //if(this.loadMask){
5710         //    this.maskEl.show();
5711         //}
5712     },
5713      /**
5714      * Remove all rows
5715      */
5716     clear : function()
5717     {
5718         this.el.select('tbody', true).first().dom.innerHTML = '';
5719     },
5720     /**
5721      * Show or hide a row.
5722      * @param {Number} rowIndex to show or hide
5723      * @param {Boolean} state hide
5724      */
5725     setRowVisibility : function(rowIndex, state)
5726     {
5727         var bt = this.mainBody.dom;
5728         
5729         var rows = this.el.select('tbody > tr', true).elements;
5730         
5731         if(typeof(rows[rowIndex]) == 'undefined'){
5732             return;
5733         }
5734         rows[rowIndex].dom.style.display = state ? '' : 'none';
5735     },
5736     
5737     
5738     getSelectionModel : function(){
5739         if(!this.selModel){
5740             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5741         }
5742         return this.selModel;
5743     },
5744     /*
5745      * Render the Roo.bootstrap object from renderder
5746      */
5747     renderCellObject : function(r)
5748     {
5749         var _this = this;
5750         
5751         var t = r.cfg.render(r.container);
5752         
5753         if(r.cfg.cn){
5754             Roo.each(r.cfg.cn, function(c){
5755                 var child = {
5756                     container: t.getChildContainer(),
5757                     cfg: c
5758                 }
5759                 _this.renderCellObject(child);
5760             })
5761         }
5762     },
5763     
5764     getRowIndex : function(row)
5765     {
5766         var rowIndex = -1;
5767         
5768         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5769             if(el != row){
5770                 return;
5771             }
5772             
5773             rowIndex = index;
5774         });
5775         
5776         return rowIndex;
5777     }
5778    
5779 });
5780
5781  
5782
5783  /*
5784  * - LGPL
5785  *
5786  * table cell
5787  * 
5788  */
5789
5790 /**
5791  * @class Roo.bootstrap.TableCell
5792  * @extends Roo.bootstrap.Component
5793  * Bootstrap TableCell class
5794  * @cfg {String} html cell contain text
5795  * @cfg {String} cls cell class
5796  * @cfg {String} tag cell tag (td|th) default td
5797  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5798  * @cfg {String} align Aligns the content in a cell
5799  * @cfg {String} axis Categorizes cells
5800  * @cfg {String} bgcolor Specifies the background color of a cell
5801  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5802  * @cfg {Number} colspan Specifies the number of columns a cell should span
5803  * @cfg {String} headers Specifies one or more header cells a cell is related to
5804  * @cfg {Number} height Sets the height of a cell
5805  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5806  * @cfg {Number} rowspan Sets the number of rows a cell should span
5807  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5808  * @cfg {String} valign Vertical aligns the content in a cell
5809  * @cfg {Number} width Specifies the width of a cell
5810  * 
5811  * @constructor
5812  * Create a new TableCell
5813  * @param {Object} config The config object
5814  */
5815
5816 Roo.bootstrap.TableCell = function(config){
5817     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5818 };
5819
5820 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5821     
5822     html: false,
5823     cls: false,
5824     tag: false,
5825     abbr: false,
5826     align: false,
5827     axis: false,
5828     bgcolor: false,
5829     charoff: false,
5830     colspan: false,
5831     headers: false,
5832     height: false,
5833     nowrap: false,
5834     rowspan: false,
5835     scope: false,
5836     valign: false,
5837     width: false,
5838     
5839     
5840     getAutoCreate : function(){
5841         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5842         
5843         cfg = {
5844             tag: 'td'
5845         }
5846         
5847         if(this.tag){
5848             cfg.tag = this.tag;
5849         }
5850         
5851         if (this.html) {
5852             cfg.html=this.html
5853         }
5854         if (this.cls) {
5855             cfg.cls=this.cls
5856         }
5857         if (this.abbr) {
5858             cfg.abbr=this.abbr
5859         }
5860         if (this.align) {
5861             cfg.align=this.align
5862         }
5863         if (this.axis) {
5864             cfg.axis=this.axis
5865         }
5866         if (this.bgcolor) {
5867             cfg.bgcolor=this.bgcolor
5868         }
5869         if (this.charoff) {
5870             cfg.charoff=this.charoff
5871         }
5872         if (this.colspan) {
5873             cfg.colspan=this.colspan
5874         }
5875         if (this.headers) {
5876             cfg.headers=this.headers
5877         }
5878         if (this.height) {
5879             cfg.height=this.height
5880         }
5881         if (this.nowrap) {
5882             cfg.nowrap=this.nowrap
5883         }
5884         if (this.rowspan) {
5885             cfg.rowspan=this.rowspan
5886         }
5887         if (this.scope) {
5888             cfg.scope=this.scope
5889         }
5890         if (this.valign) {
5891             cfg.valign=this.valign
5892         }
5893         if (this.width) {
5894             cfg.width=this.width
5895         }
5896         
5897         
5898         return cfg;
5899     }
5900    
5901 });
5902
5903  
5904
5905  /*
5906  * - LGPL
5907  *
5908  * table row
5909  * 
5910  */
5911
5912 /**
5913  * @class Roo.bootstrap.TableRow
5914  * @extends Roo.bootstrap.Component
5915  * Bootstrap TableRow class
5916  * @cfg {String} cls row class
5917  * @cfg {String} align Aligns the content in a table row
5918  * @cfg {String} bgcolor Specifies a background color for a table row
5919  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5920  * @cfg {String} valign Vertical aligns the content in a table row
5921  * 
5922  * @constructor
5923  * Create a new TableRow
5924  * @param {Object} config The config object
5925  */
5926
5927 Roo.bootstrap.TableRow = function(config){
5928     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5929 };
5930
5931 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
5932     
5933     cls: false,
5934     align: false,
5935     bgcolor: false,
5936     charoff: false,
5937     valign: false,
5938     
5939     getAutoCreate : function(){
5940         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5941         
5942         cfg = {
5943             tag: 'tr'
5944         }
5945             
5946         if(this.cls){
5947             cfg.cls = this.cls;
5948         }
5949         if(this.align){
5950             cfg.align = this.align;
5951         }
5952         if(this.bgcolor){
5953             cfg.bgcolor = this.bgcolor;
5954         }
5955         if(this.charoff){
5956             cfg.charoff = this.charoff;
5957         }
5958         if(this.valign){
5959             cfg.valign = this.valign;
5960         }
5961         
5962         return cfg;
5963     }
5964    
5965 });
5966
5967  
5968
5969  /*
5970  * - LGPL
5971  *
5972  * table body
5973  * 
5974  */
5975
5976 /**
5977  * @class Roo.bootstrap.TableBody
5978  * @extends Roo.bootstrap.Component
5979  * Bootstrap TableBody class
5980  * @cfg {String} cls element class
5981  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5982  * @cfg {String} align Aligns the content inside the element
5983  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5984  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5985  * 
5986  * @constructor
5987  * Create a new TableBody
5988  * @param {Object} config The config object
5989  */
5990
5991 Roo.bootstrap.TableBody = function(config){
5992     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5993 };
5994
5995 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
5996     
5997     cls: false,
5998     tag: false,
5999     align: false,
6000     charoff: false,
6001     valign: false,
6002     
6003     getAutoCreate : function(){
6004         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6005         
6006         cfg = {
6007             tag: 'tbody'
6008         }
6009             
6010         if (this.cls) {
6011             cfg.cls=this.cls
6012         }
6013         if(this.tag){
6014             cfg.tag = this.tag;
6015         }
6016         
6017         if(this.align){
6018             cfg.align = this.align;
6019         }
6020         if(this.charoff){
6021             cfg.charoff = this.charoff;
6022         }
6023         if(this.valign){
6024             cfg.valign = this.valign;
6025         }
6026         
6027         return cfg;
6028     }
6029     
6030     
6031 //    initEvents : function()
6032 //    {
6033 //        
6034 //        if(!this.store){
6035 //            return;
6036 //        }
6037 //        
6038 //        this.store = Roo.factory(this.store, Roo.data);
6039 //        this.store.on('load', this.onLoad, this);
6040 //        
6041 //        this.store.load();
6042 //        
6043 //    },
6044 //    
6045 //    onLoad: function () 
6046 //    {   
6047 //        this.fireEvent('load', this);
6048 //    }
6049 //    
6050 //   
6051 });
6052
6053  
6054
6055  /*
6056  * Based on:
6057  * Ext JS Library 1.1.1
6058  * Copyright(c) 2006-2007, Ext JS, LLC.
6059  *
6060  * Originally Released Under LGPL - original licence link has changed is not relivant.
6061  *
6062  * Fork - LGPL
6063  * <script type="text/javascript">
6064  */
6065
6066 // as we use this in bootstrap.
6067 Roo.namespace('Roo.form');
6068  /**
6069  * @class Roo.form.Action
6070  * Internal Class used to handle form actions
6071  * @constructor
6072  * @param {Roo.form.BasicForm} el The form element or its id
6073  * @param {Object} config Configuration options
6074  */
6075
6076  
6077  
6078 // define the action interface
6079 Roo.form.Action = function(form, options){
6080     this.form = form;
6081     this.options = options || {};
6082 };
6083 /**
6084  * Client Validation Failed
6085  * @const 
6086  */
6087 Roo.form.Action.CLIENT_INVALID = 'client';
6088 /**
6089  * Server Validation Failed
6090  * @const 
6091  */
6092 Roo.form.Action.SERVER_INVALID = 'server';
6093  /**
6094  * Connect to Server Failed
6095  * @const 
6096  */
6097 Roo.form.Action.CONNECT_FAILURE = 'connect';
6098 /**
6099  * Reading Data from Server Failed
6100  * @const 
6101  */
6102 Roo.form.Action.LOAD_FAILURE = 'load';
6103
6104 Roo.form.Action.prototype = {
6105     type : 'default',
6106     failureType : undefined,
6107     response : undefined,
6108     result : undefined,
6109
6110     // interface method
6111     run : function(options){
6112
6113     },
6114
6115     // interface method
6116     success : function(response){
6117
6118     },
6119
6120     // interface method
6121     handleResponse : function(response){
6122
6123     },
6124
6125     // default connection failure
6126     failure : function(response){
6127         
6128         this.response = response;
6129         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6130         this.form.afterAction(this, false);
6131     },
6132
6133     processResponse : function(response){
6134         this.response = response;
6135         if(!response.responseText){
6136             return true;
6137         }
6138         this.result = this.handleResponse(response);
6139         return this.result;
6140     },
6141
6142     // utility functions used internally
6143     getUrl : function(appendParams){
6144         var url = this.options.url || this.form.url || this.form.el.dom.action;
6145         if(appendParams){
6146             var p = this.getParams();
6147             if(p){
6148                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6149             }
6150         }
6151         return url;
6152     },
6153
6154     getMethod : function(){
6155         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6156     },
6157
6158     getParams : function(){
6159         var bp = this.form.baseParams;
6160         var p = this.options.params;
6161         if(p){
6162             if(typeof p == "object"){
6163                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6164             }else if(typeof p == 'string' && bp){
6165                 p += '&' + Roo.urlEncode(bp);
6166             }
6167         }else if(bp){
6168             p = Roo.urlEncode(bp);
6169         }
6170         return p;
6171     },
6172
6173     createCallback : function(){
6174         return {
6175             success: this.success,
6176             failure: this.failure,
6177             scope: this,
6178             timeout: (this.form.timeout*1000),
6179             upload: this.form.fileUpload ? this.success : undefined
6180         };
6181     }
6182 };
6183
6184 Roo.form.Action.Submit = function(form, options){
6185     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6186 };
6187
6188 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6189     type : 'submit',
6190
6191     haveProgress : false,
6192     uploadComplete : false,
6193     
6194     // uploadProgress indicator.
6195     uploadProgress : function()
6196     {
6197         if (!this.form.progressUrl) {
6198             return;
6199         }
6200         
6201         if (!this.haveProgress) {
6202             Roo.MessageBox.progress("Uploading", "Uploading");
6203         }
6204         if (this.uploadComplete) {
6205            Roo.MessageBox.hide();
6206            return;
6207         }
6208         
6209         this.haveProgress = true;
6210    
6211         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6212         
6213         var c = new Roo.data.Connection();
6214         c.request({
6215             url : this.form.progressUrl,
6216             params: {
6217                 id : uid
6218             },
6219             method: 'GET',
6220             success : function(req){
6221                //console.log(data);
6222                 var rdata = false;
6223                 var edata;
6224                 try  {
6225                    rdata = Roo.decode(req.responseText)
6226                 } catch (e) {
6227                     Roo.log("Invalid data from server..");
6228                     Roo.log(edata);
6229                     return;
6230                 }
6231                 if (!rdata || !rdata.success) {
6232                     Roo.log(rdata);
6233                     Roo.MessageBox.alert(Roo.encode(rdata));
6234                     return;
6235                 }
6236                 var data = rdata.data;
6237                 
6238                 if (this.uploadComplete) {
6239                    Roo.MessageBox.hide();
6240                    return;
6241                 }
6242                    
6243                 if (data){
6244                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6245                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6246                     );
6247                 }
6248                 this.uploadProgress.defer(2000,this);
6249             },
6250        
6251             failure: function(data) {
6252                 Roo.log('progress url failed ');
6253                 Roo.log(data);
6254             },
6255             scope : this
6256         });
6257            
6258     },
6259     
6260     
6261     run : function()
6262     {
6263         // run get Values on the form, so it syncs any secondary forms.
6264         this.form.getValues();
6265         
6266         var o = this.options;
6267         var method = this.getMethod();
6268         var isPost = method == 'POST';
6269         if(o.clientValidation === false || this.form.isValid()){
6270             
6271             if (this.form.progressUrl) {
6272                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6273                     (new Date() * 1) + '' + Math.random());
6274                     
6275             } 
6276             
6277             
6278             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6279                 form:this.form.el.dom,
6280                 url:this.getUrl(!isPost),
6281                 method: method,
6282                 params:isPost ? this.getParams() : null,
6283                 isUpload: this.form.fileUpload
6284             }));
6285             
6286             this.uploadProgress();
6287
6288         }else if (o.clientValidation !== false){ // client validation failed
6289             this.failureType = Roo.form.Action.CLIENT_INVALID;
6290             this.form.afterAction(this, false);
6291         }
6292     },
6293
6294     success : function(response)
6295     {
6296         this.uploadComplete= true;
6297         if (this.haveProgress) {
6298             Roo.MessageBox.hide();
6299         }
6300         
6301         
6302         var result = this.processResponse(response);
6303         if(result === true || result.success){
6304             this.form.afterAction(this, true);
6305             return;
6306         }
6307         if(result.errors){
6308             this.form.markInvalid(result.errors);
6309             this.failureType = Roo.form.Action.SERVER_INVALID;
6310         }
6311         this.form.afterAction(this, false);
6312     },
6313     failure : function(response)
6314     {
6315         this.uploadComplete= true;
6316         if (this.haveProgress) {
6317             Roo.MessageBox.hide();
6318         }
6319         
6320         this.response = response;
6321         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6322         this.form.afterAction(this, false);
6323     },
6324     
6325     handleResponse : function(response){
6326         if(this.form.errorReader){
6327             var rs = this.form.errorReader.read(response);
6328             var errors = [];
6329             if(rs.records){
6330                 for(var i = 0, len = rs.records.length; i < len; i++) {
6331                     var r = rs.records[i];
6332                     errors[i] = r.data;
6333                 }
6334             }
6335             if(errors.length < 1){
6336                 errors = null;
6337             }
6338             return {
6339                 success : rs.success,
6340                 errors : errors
6341             };
6342         }
6343         var ret = false;
6344         try {
6345             ret = Roo.decode(response.responseText);
6346         } catch (e) {
6347             ret = {
6348                 success: false,
6349                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6350                 errors : []
6351             };
6352         }
6353         return ret;
6354         
6355     }
6356 });
6357
6358
6359 Roo.form.Action.Load = function(form, options){
6360     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6361     this.reader = this.form.reader;
6362 };
6363
6364 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6365     type : 'load',
6366
6367     run : function(){
6368         
6369         Roo.Ajax.request(Roo.apply(
6370                 this.createCallback(), {
6371                     method:this.getMethod(),
6372                     url:this.getUrl(false),
6373                     params:this.getParams()
6374         }));
6375     },
6376
6377     success : function(response){
6378         
6379         var result = this.processResponse(response);
6380         if(result === true || !result.success || !result.data){
6381             this.failureType = Roo.form.Action.LOAD_FAILURE;
6382             this.form.afterAction(this, false);
6383             return;
6384         }
6385         this.form.clearInvalid();
6386         this.form.setValues(result.data);
6387         this.form.afterAction(this, true);
6388     },
6389
6390     handleResponse : function(response){
6391         if(this.form.reader){
6392             var rs = this.form.reader.read(response);
6393             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6394             return {
6395                 success : rs.success,
6396                 data : data
6397             };
6398         }
6399         return Roo.decode(response.responseText);
6400     }
6401 });
6402
6403 Roo.form.Action.ACTION_TYPES = {
6404     'load' : Roo.form.Action.Load,
6405     'submit' : Roo.form.Action.Submit
6406 };/*
6407  * - LGPL
6408  *
6409  * form
6410  * 
6411  */
6412
6413 /**
6414  * @class Roo.bootstrap.Form
6415  * @extends Roo.bootstrap.Component
6416  * Bootstrap Form class
6417  * @cfg {String} method  GET | POST (default POST)
6418  * @cfg {String} labelAlign top | left (default top)
6419  * @cfg {String} align left  | right - for navbars
6420  * @cfg {Boolean} loadMask load mask when submit (default true)
6421
6422  * 
6423  * @constructor
6424  * Create a new Form
6425  * @param {Object} config The config object
6426  */
6427
6428
6429 Roo.bootstrap.Form = function(config){
6430     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6431     this.addEvents({
6432         /**
6433          * @event clientvalidation
6434          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6435          * @param {Form} this
6436          * @param {Boolean} valid true if the form has passed client-side validation
6437          */
6438         clientvalidation: true,
6439         /**
6440          * @event beforeaction
6441          * Fires before any action is performed. Return false to cancel the action.
6442          * @param {Form} this
6443          * @param {Action} action The action to be performed
6444          */
6445         beforeaction: true,
6446         /**
6447          * @event actionfailed
6448          * Fires when an action fails.
6449          * @param {Form} this
6450          * @param {Action} action The action that failed
6451          */
6452         actionfailed : true,
6453         /**
6454          * @event actioncomplete
6455          * Fires when an action is completed.
6456          * @param {Form} this
6457          * @param {Action} action The action that completed
6458          */
6459         actioncomplete : true
6460     });
6461     
6462 };
6463
6464 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6465       
6466      /**
6467      * @cfg {String} method
6468      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6469      */
6470     method : 'POST',
6471     /**
6472      * @cfg {String} url
6473      * The URL to use for form actions if one isn't supplied in the action options.
6474      */
6475     /**
6476      * @cfg {Boolean} fileUpload
6477      * Set to true if this form is a file upload.
6478      */
6479      
6480     /**
6481      * @cfg {Object} baseParams
6482      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6483      */
6484       
6485     /**
6486      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6487      */
6488     timeout: 30,
6489     /**
6490      * @cfg {Sting} align (left|right) for navbar forms
6491      */
6492     align : 'left',
6493
6494     // private
6495     activeAction : null,
6496  
6497     /**
6498      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6499      * element by passing it or its id or mask the form itself by passing in true.
6500      * @type Mixed
6501      */
6502     waitMsgTarget : false,
6503     
6504     loadMask : true,
6505     
6506     getAutoCreate : function(){
6507         
6508         var cfg = {
6509             tag: 'form',
6510             method : this.method || 'POST',
6511             id : this.id || Roo.id(),
6512             cls : ''
6513         }
6514         if (this.parent().xtype.match(/^Nav/)) {
6515             cfg.cls = 'navbar-form navbar-' + this.align;
6516             
6517         }
6518         
6519         if (this.labelAlign == 'left' ) {
6520             cfg.cls += ' form-horizontal';
6521         }
6522         
6523         
6524         return cfg;
6525     },
6526     initEvents : function()
6527     {
6528         this.el.on('submit', this.onSubmit, this);
6529         // this was added as random key presses on the form where triggering form submit.
6530         this.el.on('keypress', function(e) {
6531             if (e.getCharCode() != 13) {
6532                 return true;
6533             }
6534             // we might need to allow it for textareas.. and some other items.
6535             // check e.getTarget().
6536             
6537             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6538                 return true;
6539             }
6540         
6541             Roo.log("keypress blocked");
6542             
6543             e.preventDefault();
6544             return false;
6545         });
6546         
6547     },
6548     // private
6549     onSubmit : function(e){
6550         e.stopEvent();
6551     },
6552     
6553      /**
6554      * Returns true if client-side validation on the form is successful.
6555      * @return Boolean
6556      */
6557     isValid : function(){
6558         var items = this.getItems();
6559         var valid = true;
6560         items.each(function(f){
6561            if(!f.validate()){
6562                valid = false;
6563                
6564            }
6565         });
6566         return valid;
6567     },
6568     /**
6569      * Returns true if any fields in this form have changed since their original load.
6570      * @return Boolean
6571      */
6572     isDirty : function(){
6573         var dirty = false;
6574         var items = this.getItems();
6575         items.each(function(f){
6576            if(f.isDirty()){
6577                dirty = true;
6578                return false;
6579            }
6580            return true;
6581         });
6582         return dirty;
6583     },
6584      /**
6585      * Performs a predefined action (submit or load) or custom actions you define on this form.
6586      * @param {String} actionName The name of the action type
6587      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6588      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6589      * accept other config options):
6590      * <pre>
6591 Property          Type             Description
6592 ----------------  ---------------  ----------------------------------------------------------------------------------
6593 url               String           The url for the action (defaults to the form's url)
6594 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6595 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6596 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6597                                    validate the form on the client (defaults to false)
6598      * </pre>
6599      * @return {BasicForm} this
6600      */
6601     doAction : function(action, options){
6602         if(typeof action == 'string'){
6603             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6604         }
6605         if(this.fireEvent('beforeaction', this, action) !== false){
6606             this.beforeAction(action);
6607             action.run.defer(100, action);
6608         }
6609         return this;
6610     },
6611     
6612     // private
6613     beforeAction : function(action){
6614         var o = action.options;
6615         
6616         if(this.loadMask){
6617             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6618         }
6619         // not really supported yet.. ??
6620         
6621         //if(this.waitMsgTarget === true){
6622         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6623         //}else if(this.waitMsgTarget){
6624         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6625         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6626         //}else {
6627         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6628        // }
6629          
6630     },
6631
6632     // private
6633     afterAction : function(action, success){
6634         this.activeAction = null;
6635         var o = action.options;
6636         
6637         //if(this.waitMsgTarget === true){
6638             this.el.unmask();
6639         //}else if(this.waitMsgTarget){
6640         //    this.waitMsgTarget.unmask();
6641         //}else{
6642         //    Roo.MessageBox.updateProgress(1);
6643         //    Roo.MessageBox.hide();
6644        // }
6645         // 
6646         if(success){
6647             if(o.reset){
6648                 this.reset();
6649             }
6650             Roo.callback(o.success, o.scope, [this, action]);
6651             this.fireEvent('actioncomplete', this, action);
6652             
6653         }else{
6654             
6655             // failure condition..
6656             // we have a scenario where updates need confirming.
6657             // eg. if a locking scenario exists..
6658             // we look for { errors : { needs_confirm : true }} in the response.
6659             if (
6660                 (typeof(action.result) != 'undefined')  &&
6661                 (typeof(action.result.errors) != 'undefined')  &&
6662                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6663            ){
6664                 var _t = this;
6665                 Roo.log("not supported yet");
6666                  /*
6667                 
6668                 Roo.MessageBox.confirm(
6669                     "Change requires confirmation",
6670                     action.result.errorMsg,
6671                     function(r) {
6672                         if (r != 'yes') {
6673                             return;
6674                         }
6675                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6676                     }
6677                     
6678                 );
6679                 */
6680                 
6681                 
6682                 return;
6683             }
6684             
6685             Roo.callback(o.failure, o.scope, [this, action]);
6686             // show an error message if no failed handler is set..
6687             if (!this.hasListener('actionfailed')) {
6688                 Roo.log("need to add dialog support");
6689                 /*
6690                 Roo.MessageBox.alert("Error",
6691                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6692                         action.result.errorMsg :
6693                         "Saving Failed, please check your entries or try again"
6694                 );
6695                 */
6696             }
6697             
6698             this.fireEvent('actionfailed', this, action);
6699         }
6700         
6701     },
6702     /**
6703      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6704      * @param {String} id The value to search for
6705      * @return Field
6706      */
6707     findField : function(id){
6708         var items = this.getItems();
6709         var field = items.get(id);
6710         if(!field){
6711              items.each(function(f){
6712                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6713                     field = f;
6714                     return false;
6715                 }
6716                 return true;
6717             });
6718         }
6719         return field || null;
6720     },
6721      /**
6722      * Mark fields in this form invalid in bulk.
6723      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6724      * @return {BasicForm} this
6725      */
6726     markInvalid : function(errors){
6727         if(errors instanceof Array){
6728             for(var i = 0, len = errors.length; i < len; i++){
6729                 var fieldError = errors[i];
6730                 var f = this.findField(fieldError.id);
6731                 if(f){
6732                     f.markInvalid(fieldError.msg);
6733                 }
6734             }
6735         }else{
6736             var field, id;
6737             for(id in errors){
6738                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6739                     field.markInvalid(errors[id]);
6740                 }
6741             }
6742         }
6743         //Roo.each(this.childForms || [], function (f) {
6744         //    f.markInvalid(errors);
6745         //});
6746         
6747         return this;
6748     },
6749
6750     /**
6751      * Set values for fields in this form in bulk.
6752      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6753      * @return {BasicForm} this
6754      */
6755     setValues : function(values){
6756         if(values instanceof Array){ // array of objects
6757             for(var i = 0, len = values.length; i < len; i++){
6758                 var v = values[i];
6759                 var f = this.findField(v.id);
6760                 if(f){
6761                     f.setValue(v.value);
6762                     if(this.trackResetOnLoad){
6763                         f.originalValue = f.getValue();
6764                     }
6765                 }
6766             }
6767         }else{ // object hash
6768             var field, id;
6769             for(id in values){
6770                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6771                     
6772                     if (field.setFromData && 
6773                         field.valueField && 
6774                         field.displayField &&
6775                         // combos' with local stores can 
6776                         // be queried via setValue()
6777                         // to set their value..
6778                         (field.store && !field.store.isLocal)
6779                         ) {
6780                         // it's a combo
6781                         var sd = { };
6782                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6783                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6784                         field.setFromData(sd);
6785                         
6786                     } else {
6787                         field.setValue(values[id]);
6788                     }
6789                     
6790                     
6791                     if(this.trackResetOnLoad){
6792                         field.originalValue = field.getValue();
6793                     }
6794                 }
6795             }
6796         }
6797          
6798         //Roo.each(this.childForms || [], function (f) {
6799         //    f.setValues(values);
6800         //});
6801                 
6802         return this;
6803     },
6804
6805     /**
6806      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6807      * they are returned as an array.
6808      * @param {Boolean} asString
6809      * @return {Object}
6810      */
6811     getValues : function(asString){
6812         //if (this.childForms) {
6813             // copy values from the child forms
6814         //    Roo.each(this.childForms, function (f) {
6815         //        this.setValues(f.getValues());
6816         //    }, this);
6817         //}
6818         
6819         
6820         
6821         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6822         if(asString === true){
6823             return fs;
6824         }
6825         return Roo.urlDecode(fs);
6826     },
6827     
6828     /**
6829      * Returns the fields in this form as an object with key/value pairs. 
6830      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6831      * @return {Object}
6832      */
6833     getFieldValues : function(with_hidden)
6834     {
6835         var items = this.getItems();
6836         var ret = {};
6837         items.each(function(f){
6838             if (!f.getName()) {
6839                 return;
6840             }
6841             var v = f.getValue();
6842             if (f.inputType =='radio') {
6843                 if (typeof(ret[f.getName()]) == 'undefined') {
6844                     ret[f.getName()] = ''; // empty..
6845                 }
6846                 
6847                 if (!f.el.dom.checked) {
6848                     return;
6849                     
6850                 }
6851                 v = f.el.dom.value;
6852                 
6853             }
6854             
6855             // not sure if this supported any more..
6856             if ((typeof(v) == 'object') && f.getRawValue) {
6857                 v = f.getRawValue() ; // dates..
6858             }
6859             // combo boxes where name != hiddenName...
6860             if (f.name != f.getName()) {
6861                 ret[f.name] = f.getRawValue();
6862             }
6863             ret[f.getName()] = v;
6864         });
6865         
6866         return ret;
6867     },
6868
6869     /**
6870      * Clears all invalid messages in this form.
6871      * @return {BasicForm} this
6872      */
6873     clearInvalid : function(){
6874         var items = this.getItems();
6875         
6876         items.each(function(f){
6877            f.clearInvalid();
6878         });
6879         
6880         
6881         
6882         return this;
6883     },
6884
6885     /**
6886      * Resets this form.
6887      * @return {BasicForm} this
6888      */
6889     reset : function(){
6890         var items = this.getItems();
6891         items.each(function(f){
6892             f.reset();
6893         });
6894         
6895         Roo.each(this.childForms || [], function (f) {
6896             f.reset();
6897         });
6898        
6899         
6900         return this;
6901     },
6902     getItems : function()
6903     {
6904         var r=new Roo.util.MixedCollection(false, function(o){
6905             return o.id || (o.id = Roo.id());
6906         });
6907         var iter = function(el) {
6908             if (el.inputEl) {
6909                 r.add(el);
6910             }
6911             if (!el.items) {
6912                 return;
6913             }
6914             Roo.each(el.items,function(e) {
6915                 iter(e);
6916             });
6917             
6918             
6919         };
6920         iter(this);
6921         return r;
6922         
6923         
6924         
6925         
6926     }
6927     
6928 });
6929
6930  
6931 /*
6932  * Based on:
6933  * Ext JS Library 1.1.1
6934  * Copyright(c) 2006-2007, Ext JS, LLC.
6935  *
6936  * Originally Released Under LGPL - original licence link has changed is not relivant.
6937  *
6938  * Fork - LGPL
6939  * <script type="text/javascript">
6940  */
6941 /**
6942  * @class Roo.form.VTypes
6943  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6944  * @singleton
6945  */
6946 Roo.form.VTypes = function(){
6947     // closure these in so they are only created once.
6948     var alpha = /^[a-zA-Z_]+$/;
6949     var alphanum = /^[a-zA-Z0-9_]+$/;
6950     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6951     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6952
6953     // All these messages and functions are configurable
6954     return {
6955         /**
6956          * The function used to validate email addresses
6957          * @param {String} value The email address
6958          */
6959         'email' : function(v){
6960             return email.test(v);
6961         },
6962         /**
6963          * The error text to display when the email validation function returns false
6964          * @type String
6965          */
6966         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6967         /**
6968          * The keystroke filter mask to be applied on email input
6969          * @type RegExp
6970          */
6971         'emailMask' : /[a-z0-9_\.\-@]/i,
6972
6973         /**
6974          * The function used to validate URLs
6975          * @param {String} value The URL
6976          */
6977         'url' : function(v){
6978             return url.test(v);
6979         },
6980         /**
6981          * The error text to display when the url validation function returns false
6982          * @type String
6983          */
6984         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6985         
6986         /**
6987          * The function used to validate alpha values
6988          * @param {String} value The value
6989          */
6990         'alpha' : function(v){
6991             return alpha.test(v);
6992         },
6993         /**
6994          * The error text to display when the alpha validation function returns false
6995          * @type String
6996          */
6997         'alphaText' : 'This field should only contain letters and _',
6998         /**
6999          * The keystroke filter mask to be applied on alpha input
7000          * @type RegExp
7001          */
7002         'alphaMask' : /[a-z_]/i,
7003
7004         /**
7005          * The function used to validate alphanumeric values
7006          * @param {String} value The value
7007          */
7008         'alphanum' : function(v){
7009             return alphanum.test(v);
7010         },
7011         /**
7012          * The error text to display when the alphanumeric validation function returns false
7013          * @type String
7014          */
7015         'alphanumText' : 'This field should only contain letters, numbers and _',
7016         /**
7017          * The keystroke filter mask to be applied on alphanumeric input
7018          * @type RegExp
7019          */
7020         'alphanumMask' : /[a-z0-9_]/i
7021     };
7022 }();/*
7023  * - LGPL
7024  *
7025  * Input
7026  * 
7027  */
7028
7029 /**
7030  * @class Roo.bootstrap.Input
7031  * @extends Roo.bootstrap.Component
7032  * Bootstrap Input class
7033  * @cfg {Boolean} disabled is it disabled
7034  * @cfg {String} fieldLabel - the label associated
7035  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7036  * @cfg {String} name name of the input
7037  * @cfg {string} fieldLabel - the label associated
7038  * @cfg {string}  inputType - input / file submit ...
7039  * @cfg {string} placeholder - placeholder to put in text.
7040  * @cfg {string}  before - input group add on before
7041  * @cfg {string} after - input group add on after
7042  * @cfg {string} size - (lg|sm) or leave empty..
7043  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7044  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7045  * @cfg {Number} md colspan out of 12 for computer-sized screens
7046  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7047  * @cfg {string} value default value of the input
7048  * @cfg {Number} labelWidth set the width of label (0-12)
7049  * @cfg {String} labelAlign (top|left)
7050  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7051  * @cfg {String} align (left|center|right) Default left
7052  * 
7053  * 
7054  * @constructor
7055  * Create a new Input
7056  * @param {Object} config The config object
7057  */
7058
7059 Roo.bootstrap.Input = function(config){
7060     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7061    
7062         this.addEvents({
7063             /**
7064              * @event focus
7065              * Fires when this field receives input focus.
7066              * @param {Roo.form.Field} this
7067              */
7068             focus : true,
7069             /**
7070              * @event blur
7071              * Fires when this field loses input focus.
7072              * @param {Roo.form.Field} this
7073              */
7074             blur : true,
7075             /**
7076              * @event specialkey
7077              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7078              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7079              * @param {Roo.form.Field} this
7080              * @param {Roo.EventObject} e The event object
7081              */
7082             specialkey : true,
7083             /**
7084              * @event change
7085              * Fires just before the field blurs if the field value has changed.
7086              * @param {Roo.form.Field} this
7087              * @param {Mixed} newValue The new value
7088              * @param {Mixed} oldValue The original value
7089              */
7090             change : true,
7091             /**
7092              * @event invalid
7093              * Fires after the field has been marked as invalid.
7094              * @param {Roo.form.Field} this
7095              * @param {String} msg The validation message
7096              */
7097             invalid : true,
7098             /**
7099              * @event valid
7100              * Fires after the field has been validated with no errors.
7101              * @param {Roo.form.Field} this
7102              */
7103             valid : true,
7104              /**
7105              * @event keyup
7106              * Fires after the key up
7107              * @param {Roo.form.Field} this
7108              * @param {Roo.EventObject}  e The event Object
7109              */
7110             keyup : true
7111         });
7112 };
7113
7114 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7115      /**
7116      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7117       automatic validation (defaults to "keyup").
7118      */
7119     validationEvent : "keyup",
7120      /**
7121      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7122      */
7123     validateOnBlur : true,
7124     /**
7125      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7126      */
7127     validationDelay : 250,
7128      /**
7129      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7130      */
7131     focusClass : "x-form-focus",  // not needed???
7132     
7133        
7134     /**
7135      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7136      */
7137     invalidClass : "has-error",
7138     
7139     /**
7140      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7141      */
7142     selectOnFocus : false,
7143     
7144      /**
7145      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7146      */
7147     maskRe : null,
7148        /**
7149      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7150      */
7151     vtype : null,
7152     
7153       /**
7154      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7155      */
7156     disableKeyFilter : false,
7157     
7158        /**
7159      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7160      */
7161     disabled : false,
7162      /**
7163      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7164      */
7165     allowBlank : true,
7166     /**
7167      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7168      */
7169     blankText : "This field is required",
7170     
7171      /**
7172      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7173      */
7174     minLength : 0,
7175     /**
7176      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7177      */
7178     maxLength : Number.MAX_VALUE,
7179     /**
7180      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7181      */
7182     minLengthText : "The minimum length for this field is {0}",
7183     /**
7184      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7185      */
7186     maxLengthText : "The maximum length for this field is {0}",
7187   
7188     
7189     /**
7190      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7191      * If available, this function will be called only after the basic validators all return true, and will be passed the
7192      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7193      */
7194     validator : null,
7195     /**
7196      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7197      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7198      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7199      */
7200     regex : null,
7201     /**
7202      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7203      */
7204     regexText : "",
7205     
7206     
7207     
7208     fieldLabel : '',
7209     inputType : 'text',
7210     
7211     name : false,
7212     placeholder: false,
7213     before : false,
7214     after : false,
7215     size : false,
7216     // private
7217     hasFocus : false,
7218     preventMark: false,
7219     isFormField : true,
7220     value : '',
7221     labelWidth : 2,
7222     labelAlign : false,
7223     readOnly : false,
7224     align : false,
7225     formatedValue : false,
7226     
7227     parentLabelAlign : function()
7228     {
7229         var parent = this;
7230         while (parent.parent()) {
7231             parent = parent.parent();
7232             if (typeof(parent.labelAlign) !='undefined') {
7233                 return parent.labelAlign;
7234             }
7235         }
7236         return 'left';
7237         
7238     },
7239     
7240     getAutoCreate : function(){
7241         
7242         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7243         
7244         var id = Roo.id();
7245         
7246         var cfg = {};
7247         
7248         if(this.inputType != 'hidden'){
7249             cfg.cls = 'form-group' //input-group
7250         }
7251         
7252         var input =  {
7253             tag: 'input',
7254             id : id,
7255             type : this.inputType,
7256             value : this.value,
7257             cls : 'form-control',
7258             placeholder : this.placeholder || ''
7259             
7260         };
7261         
7262         if(this.align){
7263             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7264         }
7265         
7266         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7267             input.maxLength = this.maxLength;
7268         }
7269         
7270         if (this.disabled) {
7271             input.disabled=true;
7272         }
7273         
7274         if (this.readOnly) {
7275             input.readonly=true;
7276         }
7277         
7278         if (this.name) {
7279             input.name = this.name;
7280         }
7281         if (this.size) {
7282             input.cls += ' input-' + this.size;
7283         }
7284         var settings=this;
7285         ['xs','sm','md','lg'].map(function(size){
7286             if (settings[size]) {
7287                 cfg.cls += ' col-' + size + '-' + settings[size];
7288             }
7289         });
7290         
7291         var inputblock = input;
7292         
7293         if (this.before || this.after) {
7294             
7295             inputblock = {
7296                 cls : 'input-group',
7297                 cn :  [] 
7298             };
7299             if (this.before && typeof(this.before) == 'string') {
7300                 
7301                 inputblock.cn.push({
7302                     tag :'span',
7303                     cls : 'roo-input-before input-group-addon',
7304                     html : this.before
7305                 });
7306             }
7307             if (this.before && typeof(this.before) == 'object') {
7308                 this.before = Roo.factory(this.before);
7309                 Roo.log(this.before);
7310                 inputblock.cn.push({
7311                     tag :'span',
7312                     cls : 'roo-input-before input-group-' +
7313                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7314                 });
7315             }
7316             
7317             inputblock.cn.push(input);
7318             
7319             if (this.after && typeof(this.after) == 'string') {
7320                 inputblock.cn.push({
7321                     tag :'span',
7322                     cls : 'roo-input-after input-group-addon',
7323                     html : this.after
7324                 });
7325             }
7326             if (this.after && typeof(this.after) == 'object') {
7327                 this.after = Roo.factory(this.after);
7328                 Roo.log(this.after);
7329                 inputblock.cn.push({
7330                     tag :'span',
7331                     cls : 'roo-input-after input-group-' +
7332                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7333                 });
7334             }
7335         };
7336         
7337         if (align ==='left' && this.fieldLabel.length) {
7338                 Roo.log("left and has label");
7339                 cfg.cn = [
7340                     
7341                     {
7342                         tag: 'label',
7343                         'for' :  id,
7344                         cls : 'control-label col-sm-' + this.labelWidth,
7345                         html : this.fieldLabel
7346                         
7347                     },
7348                     {
7349                         cls : "col-sm-" + (12 - this.labelWidth), 
7350                         cn: [
7351                             inputblock
7352                         ]
7353                     }
7354                     
7355                 ];
7356         } else if ( this.fieldLabel.length) {
7357                 Roo.log(" label");
7358                  cfg.cn = [
7359                    
7360                     {
7361                         tag: 'label',
7362                         //cls : 'input-group-addon',
7363                         html : this.fieldLabel
7364                         
7365                     },
7366                     
7367                     inputblock
7368                     
7369                 ];
7370
7371         } else {
7372             
7373                 Roo.log(" no label && no align");
7374                 cfg.cn = [
7375                     
7376                         inputblock
7377                     
7378                 ];
7379                 
7380                 
7381         };
7382         Roo.log('input-parentType: ' + this.parentType);
7383         
7384         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7385            cfg.cls += ' navbar-form';
7386            Roo.log(cfg);
7387         }
7388         
7389         return cfg;
7390         
7391     },
7392     /**
7393      * return the real input element.
7394      */
7395     inputEl: function ()
7396     {
7397         return this.el.select('input.form-control',true).first();
7398     },
7399     
7400     tooltipEl : function()
7401     {
7402         return this.inputEl();
7403     },
7404     
7405     setDisabled : function(v)
7406     {
7407         var i  = this.inputEl().dom;
7408         if (!v) {
7409             i.removeAttribute('disabled');
7410             return;
7411             
7412         }
7413         i.setAttribute('disabled','true');
7414     },
7415     initEvents : function()
7416     {
7417           
7418         this.inputEl().on("keydown" , this.fireKey,  this);
7419         this.inputEl().on("focus", this.onFocus,  this);
7420         this.inputEl().on("blur", this.onBlur,  this);
7421         
7422         this.inputEl().relayEvent('keyup', this);
7423
7424         // reference to original value for reset
7425         this.originalValue = this.getValue();
7426         //Roo.form.TextField.superclass.initEvents.call(this);
7427         if(this.validationEvent == 'keyup'){
7428             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7429             this.inputEl().on('keyup', this.filterValidation, this);
7430         }
7431         else if(this.validationEvent !== false){
7432             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7433         }
7434         
7435         if(this.selectOnFocus){
7436             this.on("focus", this.preFocus, this);
7437             
7438         }
7439         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7440             this.inputEl().on("keypress", this.filterKeys, this);
7441         }
7442        /* if(this.grow){
7443             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7444             this.el.on("click", this.autoSize,  this);
7445         }
7446         */
7447         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7448             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7449         }
7450         
7451         if (typeof(this.before) == 'object') {
7452             this.before.render(this.el.select('.roo-input-before',true).first());
7453         }
7454         if (typeof(this.after) == 'object') {
7455             this.after.render(this.el.select('.roo-input-after',true).first());
7456         }
7457         
7458         
7459     },
7460     filterValidation : function(e){
7461         if(!e.isNavKeyPress()){
7462             this.validationTask.delay(this.validationDelay);
7463         }
7464     },
7465      /**
7466      * Validates the field value
7467      * @return {Boolean} True if the value is valid, else false
7468      */
7469     validate : function(){
7470         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7471         if(this.disabled || this.validateValue(this.getRawValue())){
7472             this.clearInvalid();
7473             return true;
7474         }
7475         return false;
7476     },
7477     
7478     
7479     /**
7480      * Validates a value according to the field's validation rules and marks the field as invalid
7481      * if the validation fails
7482      * @param {Mixed} value The value to validate
7483      * @return {Boolean} True if the value is valid, else false
7484      */
7485     validateValue : function(value){
7486         if(value.length < 1)  { // if it's blank
7487              if(this.allowBlank){
7488                 this.clearInvalid();
7489                 return true;
7490              }else{
7491                 this.markInvalid(this.blankText);
7492                 return false;
7493              }
7494         }
7495         if(value.length < this.minLength){
7496             this.markInvalid(String.format(this.minLengthText, this.minLength));
7497             return false;
7498         }
7499         if(value.length > this.maxLength){
7500             this.markInvalid(String.format(this.maxLengthText, this.maxLength));
7501             return false;
7502         }
7503         if(this.vtype){
7504             var vt = Roo.form.VTypes;
7505             if(!vt[this.vtype](value, this)){
7506                 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
7507                 return false;
7508             }
7509         }
7510         if(typeof this.validator == "function"){
7511             var msg = this.validator(value);
7512             if(msg !== true){
7513                 this.markInvalid(msg);
7514                 return false;
7515             }
7516         }
7517         if(this.regex && !this.regex.test(value)){
7518             this.markInvalid(this.regexText);
7519             return false;
7520         }
7521         return true;
7522     },
7523
7524     
7525     
7526      // private
7527     fireKey : function(e){
7528         //Roo.log('field ' + e.getKey());
7529         if(e.isNavKeyPress()){
7530             this.fireEvent("specialkey", this, e);
7531         }
7532     },
7533     focus : function (selectText){
7534         if(this.rendered){
7535             this.inputEl().focus();
7536             if(selectText === true){
7537                 this.inputEl().dom.select();
7538             }
7539         }
7540         return this;
7541     } ,
7542     
7543     onFocus : function(){
7544         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7545            // this.el.addClass(this.focusClass);
7546         }
7547         if(!this.hasFocus){
7548             this.hasFocus = true;
7549             this.startValue = this.getValue();
7550             this.fireEvent("focus", this);
7551         }
7552     },
7553     
7554     beforeBlur : Roo.emptyFn,
7555
7556     
7557     // private
7558     onBlur : function(){
7559         this.beforeBlur();
7560         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7561             //this.el.removeClass(this.focusClass);
7562         }
7563         this.hasFocus = false;
7564         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7565             this.validate();
7566         }
7567         var v = this.getValue();
7568         if(String(v) !== String(this.startValue)){
7569             this.fireEvent('change', this, v, this.startValue);
7570         }
7571         this.fireEvent("blur", this);
7572     },
7573     
7574     /**
7575      * Resets the current field value to the originally loaded value and clears any validation messages
7576      */
7577     reset : function(){
7578         this.setValue(this.originalValue);
7579         this.clearInvalid();
7580     },
7581      /**
7582      * Returns the name of the field
7583      * @return {Mixed} name The name field
7584      */
7585     getName: function(){
7586         return this.name;
7587     },
7588      /**
7589      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7590      * @return {Mixed} value The field value
7591      */
7592     getValue : function(){
7593         
7594         var v = this.inputEl().getValue();
7595         
7596         return v;
7597     },
7598     /**
7599      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7600      * @return {Mixed} value The field value
7601      */
7602     getRawValue : function(){
7603         var v = this.inputEl().getValue();
7604         
7605         return v;
7606     },
7607     
7608     /**
7609      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7610      * @param {Mixed} value The value to set
7611      */
7612     setRawValue : function(v){
7613         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7614     },
7615     
7616     selectText : function(start, end){
7617         var v = this.getRawValue();
7618         if(v.length > 0){
7619             start = start === undefined ? 0 : start;
7620             end = end === undefined ? v.length : end;
7621             var d = this.inputEl().dom;
7622             if(d.setSelectionRange){
7623                 d.setSelectionRange(start, end);
7624             }else if(d.createTextRange){
7625                 var range = d.createTextRange();
7626                 range.moveStart("character", start);
7627                 range.moveEnd("character", v.length-end);
7628                 range.select();
7629             }
7630         }
7631     },
7632     
7633     /**
7634      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7635      * @param {Mixed} value The value to set
7636      */
7637     setValue : function(v){
7638         this.value = v;
7639         if(this.rendered){
7640             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7641             this.validate();
7642         }
7643     },
7644     
7645     /*
7646     processValue : function(value){
7647         if(this.stripCharsRe){
7648             var newValue = value.replace(this.stripCharsRe, '');
7649             if(newValue !== value){
7650                 this.setRawValue(newValue);
7651                 return newValue;
7652             }
7653         }
7654         return value;
7655     },
7656   */
7657     preFocus : function(){
7658         
7659         if(this.selectOnFocus){
7660             this.inputEl().dom.select();
7661         }
7662     },
7663     filterKeys : function(e){
7664         var k = e.getKey();
7665         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7666             return;
7667         }
7668         var c = e.getCharCode(), cc = String.fromCharCode(c);
7669         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7670             return;
7671         }
7672         if(!this.maskRe.test(cc)){
7673             e.stopEvent();
7674         }
7675     },
7676      /**
7677      * Clear any invalid styles/messages for this field
7678      */
7679     clearInvalid : function(){
7680         
7681         if(!this.el || this.preventMark){ // not rendered
7682             return;
7683         }
7684         this.el.removeClass(this.invalidClass);
7685         /*
7686         switch(this.msgTarget){
7687             case 'qtip':
7688                 this.el.dom.qtip = '';
7689                 break;
7690             case 'title':
7691                 this.el.dom.title = '';
7692                 break;
7693             case 'under':
7694                 if(this.errorEl){
7695                     Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
7696                 }
7697                 break;
7698             case 'side':
7699                 if(this.errorIcon){
7700                     this.errorIcon.dom.qtip = '';
7701                     this.errorIcon.hide();
7702                     this.un('resize', this.alignErrorIcon, this);
7703                 }
7704                 break;
7705             default:
7706                 var t = Roo.getDom(this.msgTarget);
7707                 t.innerHTML = '';
7708                 t.style.display = 'none';
7709                 break;
7710         }
7711         */
7712         this.fireEvent('valid', this);
7713     },
7714      /**
7715      * Mark this field as invalid
7716      * @param {String} msg The validation message
7717      */
7718     markInvalid : function(msg){
7719         if(!this.el  || this.preventMark){ // not rendered
7720             return;
7721         }
7722         this.el.addClass(this.invalidClass);
7723         /*
7724         msg = msg || this.invalidText;
7725         switch(this.msgTarget){
7726             case 'qtip':
7727                 this.el.dom.qtip = msg;
7728                 this.el.dom.qclass = 'x-form-invalid-tip';
7729                 if(Roo.QuickTips){ // fix for floating editors interacting with DND
7730                     Roo.QuickTips.enable();
7731                 }
7732                 break;
7733             case 'title':
7734                 this.el.dom.title = msg;
7735                 break;
7736             case 'under':
7737                 if(!this.errorEl){
7738                     var elp = this.el.findParent('.x-form-element', 5, true);
7739                     this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7740                     this.errorEl.setWidth(elp.getWidth(true)-20);
7741                 }
7742                 this.errorEl.update(msg);
7743                 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7744                 break;
7745             case 'side':
7746                 if(!this.errorIcon){
7747                     var elp = this.el.findParent('.x-form-element', 5, true);
7748                     this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7749                 }
7750                 this.alignErrorIcon();
7751                 this.errorIcon.dom.qtip = msg;
7752                 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7753                 this.errorIcon.show();
7754                 this.on('resize', this.alignErrorIcon, this);
7755                 break;
7756             default:
7757                 var t = Roo.getDom(this.msgTarget);
7758                 t.innerHTML = msg;
7759                 t.style.display = this.msgDisplay;
7760                 break;
7761         }
7762         */
7763         this.fireEvent('invalid', this, msg);
7764     },
7765     // private
7766     SafariOnKeyDown : function(event)
7767     {
7768         // this is a workaround for a password hang bug on chrome/ webkit.
7769         
7770         var isSelectAll = false;
7771         
7772         if(this.inputEl().dom.selectionEnd > 0){
7773             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7774         }
7775         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7776             event.preventDefault();
7777             this.setValue('');
7778             return;
7779         }
7780         
7781         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7782             
7783             event.preventDefault();
7784             // this is very hacky as keydown always get's upper case.
7785             //
7786             var cc = String.fromCharCode(event.getCharCode());
7787             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7788             
7789         }
7790     },
7791     adjustWidth : function(tag, w){
7792         tag = tag.toLowerCase();
7793         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7794             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7795                 if(tag == 'input'){
7796                     return w + 2;
7797                 }
7798                 if(tag == 'textarea'){
7799                     return w-2;
7800                 }
7801             }else if(Roo.isOpera){
7802                 if(tag == 'input'){
7803                     return w + 2;
7804                 }
7805                 if(tag == 'textarea'){
7806                     return w-2;
7807                 }
7808             }
7809         }
7810         return w;
7811     }
7812     
7813 });
7814
7815  
7816 /*
7817  * - LGPL
7818  *
7819  * Input
7820  * 
7821  */
7822
7823 /**
7824  * @class Roo.bootstrap.TextArea
7825  * @extends Roo.bootstrap.Input
7826  * Bootstrap TextArea class
7827  * @cfg {Number} cols Specifies the visible width of a text area
7828  * @cfg {Number} rows Specifies the visible number of lines in a text area
7829  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7830  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7831  * @cfg {string} html text
7832  * 
7833  * @constructor
7834  * Create a new TextArea
7835  * @param {Object} config The config object
7836  */
7837
7838 Roo.bootstrap.TextArea = function(config){
7839     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7840    
7841 };
7842
7843 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7844      
7845     cols : false,
7846     rows : 5,
7847     readOnly : false,
7848     warp : 'soft',
7849     resize : false,
7850     value: false,
7851     html: false,
7852     
7853     getAutoCreate : function(){
7854         
7855         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7856         
7857         var id = Roo.id();
7858         
7859         var cfg = {};
7860         
7861         var input =  {
7862             tag: 'textarea',
7863             id : id,
7864             warp : this.warp,
7865             rows : this.rows,
7866             value : this.value || '',
7867             html: this.html || '',
7868             cls : 'form-control',
7869             placeholder : this.placeholder || '' 
7870             
7871         };
7872         
7873         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7874             input.maxLength = this.maxLength;
7875         }
7876         
7877         if(this.resize){
7878             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7879         }
7880         
7881         if(this.cols){
7882             input.cols = this.cols;
7883         }
7884         
7885         if (this.readOnly) {
7886             input.readonly = true;
7887         }
7888         
7889         if (this.name) {
7890             input.name = this.name;
7891         }
7892         
7893         if (this.size) {
7894             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7895         }
7896         
7897         var settings=this;
7898         ['xs','sm','md','lg'].map(function(size){
7899             if (settings[size]) {
7900                 cfg.cls += ' col-' + size + '-' + settings[size];
7901             }
7902         });
7903         
7904         var inputblock = input;
7905         
7906         if (this.before || this.after) {
7907             
7908             inputblock = {
7909                 cls : 'input-group',
7910                 cn :  [] 
7911             };
7912             if (this.before) {
7913                 inputblock.cn.push({
7914                     tag :'span',
7915                     cls : 'input-group-addon',
7916                     html : this.before
7917                 });
7918             }
7919             inputblock.cn.push(input);
7920             if (this.after) {
7921                 inputblock.cn.push({
7922                     tag :'span',
7923                     cls : 'input-group-addon',
7924                     html : this.after
7925                 });
7926             }
7927             
7928         }
7929         
7930         if (align ==='left' && this.fieldLabel.length) {
7931                 Roo.log("left and has label");
7932                 cfg.cn = [
7933                     
7934                     {
7935                         tag: 'label',
7936                         'for' :  id,
7937                         cls : 'control-label col-sm-' + this.labelWidth,
7938                         html : this.fieldLabel
7939                         
7940                     },
7941                     {
7942                         cls : "col-sm-" + (12 - this.labelWidth), 
7943                         cn: [
7944                             inputblock
7945                         ]
7946                     }
7947                     
7948                 ];
7949         } else if ( this.fieldLabel.length) {
7950                 Roo.log(" label");
7951                  cfg.cn = [
7952                    
7953                     {
7954                         tag: 'label',
7955                         //cls : 'input-group-addon',
7956                         html : this.fieldLabel
7957                         
7958                     },
7959                     
7960                     inputblock
7961                     
7962                 ];
7963
7964         } else {
7965             
7966                    Roo.log(" no label && no align");
7967                 cfg.cn = [
7968                     
7969                         inputblock
7970                     
7971                 ];
7972                 
7973                 
7974         }
7975         
7976         if (this.disabled) {
7977             input.disabled=true;
7978         }
7979         
7980         return cfg;
7981         
7982     },
7983     /**
7984      * return the real textarea element.
7985      */
7986     inputEl: function ()
7987     {
7988         return this.el.select('textarea.form-control',true).first();
7989     }
7990 });
7991
7992  
7993 /*
7994  * - LGPL
7995  *
7996  * trigger field - base class for combo..
7997  * 
7998  */
7999  
8000 /**
8001  * @class Roo.bootstrap.TriggerField
8002  * @extends Roo.bootstrap.Input
8003  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8004  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8005  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8006  * for which you can provide a custom implementation.  For example:
8007  * <pre><code>
8008 var trigger = new Roo.bootstrap.TriggerField();
8009 trigger.onTriggerClick = myTriggerFn;
8010 trigger.applyTo('my-field');
8011 </code></pre>
8012  *
8013  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8014  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8015  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8016  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8017  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8018
8019  * @constructor
8020  * Create a new TriggerField.
8021  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8022  * to the base TextField)
8023  */
8024 Roo.bootstrap.TriggerField = function(config){
8025     this.mimicing = false;
8026     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8027 };
8028
8029 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8030     /**
8031      * @cfg {String} triggerClass A CSS class to apply to the trigger
8032      */
8033      /**
8034      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8035      */
8036     hideTrigger:false,
8037
8038     /** @cfg {Boolean} grow @hide */
8039     /** @cfg {Number} growMin @hide */
8040     /** @cfg {Number} growMax @hide */
8041
8042     /**
8043      * @hide 
8044      * @method
8045      */
8046     autoSize: Roo.emptyFn,
8047     // private
8048     monitorTab : true,
8049     // private
8050     deferHeight : true,
8051
8052     
8053     actionMode : 'wrap',
8054     
8055     caret : false,
8056     
8057     
8058     getAutoCreate : function(){
8059        
8060         var align = this.labelAlign || this.parentLabelAlign();
8061         
8062         var id = Roo.id();
8063         
8064         var cfg = {
8065             cls: 'form-group' //input-group
8066         };
8067         
8068         
8069         var input =  {
8070             tag: 'input',
8071             id : id,
8072             type : this.inputType,
8073             cls : 'form-control',
8074             autocomplete: 'false',
8075             placeholder : this.placeholder || '' 
8076             
8077         };
8078         if (this.name) {
8079             input.name = this.name;
8080         }
8081         if (this.size) {
8082             input.cls += ' input-' + this.size;
8083         }
8084         
8085         if (this.disabled) {
8086             input.disabled=true;
8087         }
8088         
8089         var inputblock = input;
8090         
8091         if (this.before || this.after) {
8092             
8093             inputblock = {
8094                 cls : 'input-group',
8095                 cn :  [] 
8096             };
8097             if (this.before) {
8098                 inputblock.cn.push({
8099                     tag :'span',
8100                     cls : 'input-group-addon',
8101                     html : this.before
8102                 });
8103             }
8104             inputblock.cn.push(input);
8105             if (this.after) {
8106                 inputblock.cn.push({
8107                     tag :'span',
8108                     cls : 'input-group-addon',
8109                     html : this.after
8110                 });
8111             }
8112             
8113         };
8114         
8115         var box = {
8116             tag: 'div',
8117             cn: [
8118                 {
8119                     tag: 'input',
8120                     type : 'hidden',
8121                     cls: 'form-hidden-field'
8122                 },
8123                 inputblock
8124             ]
8125             
8126         };
8127         
8128         if(this.multiple){
8129             Roo.log('multiple');
8130             
8131             box = {
8132                 tag: 'div',
8133                 cn: [
8134                     {
8135                         tag: 'input',
8136                         type : 'hidden',
8137                         cls: 'form-hidden-field'
8138                     },
8139                     {
8140                         tag: 'ul',
8141                         cls: 'select2-choices',
8142                         cn:[
8143                             {
8144                                 tag: 'li',
8145                                 cls: 'select2-search-field',
8146                                 cn: [
8147
8148                                     inputblock
8149                                 ]
8150                             }
8151                         ]
8152                     }
8153                 ]
8154             }
8155         };
8156         
8157         var combobox = {
8158             cls: 'select2-container input-group',
8159             cn: [
8160                 box
8161 //                {
8162 //                    tag: 'ul',
8163 //                    cls: 'typeahead typeahead-long dropdown-menu',
8164 //                    style: 'display:none'
8165 //                }
8166             ]
8167         };
8168         
8169         if(!this.multiple && this.showToggleBtn){
8170             
8171             var caret = {
8172                         tag: 'span',
8173                         cls: 'caret'
8174              };
8175             if (this.caret != false) {
8176                 caret = {
8177                      tag: 'i',
8178                      cls: 'fa fa-' + this.caret
8179                 };
8180                 
8181             }
8182             
8183             combobox.cn.push({
8184                 tag :'span',
8185                 cls : 'input-group-addon btn dropdown-toggle',
8186                 cn : [
8187                     caret,
8188                     {
8189                         tag: 'span',
8190                         cls: 'combobox-clear',
8191                         cn  : [
8192                             {
8193                                 tag : 'i',
8194                                 cls: 'icon-remove'
8195                             }
8196                         ]
8197                     }
8198                 ]
8199
8200             })
8201         }
8202         
8203         if(this.multiple){
8204             combobox.cls += ' select2-container-multi';
8205         }
8206         
8207         if (align ==='left' && this.fieldLabel.length) {
8208             
8209                 Roo.log("left and has label");
8210                 cfg.cn = [
8211                     
8212                     {
8213                         tag: 'label',
8214                         'for' :  id,
8215                         cls : 'control-label col-sm-' + this.labelWidth,
8216                         html : this.fieldLabel
8217                         
8218                     },
8219                     {
8220                         cls : "col-sm-" + (12 - this.labelWidth), 
8221                         cn: [
8222                             combobox
8223                         ]
8224                     }
8225                     
8226                 ];
8227         } else if ( this.fieldLabel.length) {
8228                 Roo.log(" label");
8229                  cfg.cn = [
8230                    
8231                     {
8232                         tag: 'label',
8233                         //cls : 'input-group-addon',
8234                         html : this.fieldLabel
8235                         
8236                     },
8237                     
8238                     combobox
8239                     
8240                 ];
8241
8242         } else {
8243             
8244                 Roo.log(" no label && no align");
8245                 cfg = combobox
8246                      
8247                 
8248         }
8249          
8250         var settings=this;
8251         ['xs','sm','md','lg'].map(function(size){
8252             if (settings[size]) {
8253                 cfg.cls += ' col-' + size + '-' + settings[size];
8254             }
8255         });
8256         
8257         return cfg;
8258         
8259     },
8260     
8261     
8262     
8263     // private
8264     onResize : function(w, h){
8265 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8266 //        if(typeof w == 'number'){
8267 //            var x = w - this.trigger.getWidth();
8268 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8269 //            this.trigger.setStyle('left', x+'px');
8270 //        }
8271     },
8272
8273     // private
8274     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8275
8276     // private
8277     getResizeEl : function(){
8278         return this.inputEl();
8279     },
8280
8281     // private
8282     getPositionEl : function(){
8283         return this.inputEl();
8284     },
8285
8286     // private
8287     alignErrorIcon : function(){
8288         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8289     },
8290
8291     // private
8292     initEvents : function(){
8293         
8294         this.createList();
8295         
8296         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8297         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8298         if(!this.multiple && this.showToggleBtn){
8299             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8300             if(this.hideTrigger){
8301                 this.trigger.setDisplayed(false);
8302             }
8303             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8304         }
8305         
8306         if(this.multiple){
8307             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8308         }
8309         
8310         //this.trigger.addClassOnOver('x-form-trigger-over');
8311         //this.trigger.addClassOnClick('x-form-trigger-click');
8312         
8313         //if(!this.width){
8314         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8315         //}
8316     },
8317     
8318     createList : function()
8319     {
8320         this.list = Roo.get(document.body).createChild({
8321             tag: 'ul',
8322             cls: 'typeahead typeahead-long dropdown-menu',
8323             style: 'display:none'
8324         });
8325         
8326         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8327         
8328     },
8329
8330     // private
8331     initTrigger : function(){
8332        
8333     },
8334
8335     // private
8336     onDestroy : function(){
8337         if(this.trigger){
8338             this.trigger.removeAllListeners();
8339           //  this.trigger.remove();
8340         }
8341         //if(this.wrap){
8342         //    this.wrap.remove();
8343         //}
8344         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8345     },
8346
8347     // private
8348     onFocus : function(){
8349         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8350         /*
8351         if(!this.mimicing){
8352             this.wrap.addClass('x-trigger-wrap-focus');
8353             this.mimicing = true;
8354             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8355             if(this.monitorTab){
8356                 this.el.on("keydown", this.checkTab, this);
8357             }
8358         }
8359         */
8360     },
8361
8362     // private
8363     checkTab : function(e){
8364         if(e.getKey() == e.TAB){
8365             this.triggerBlur();
8366         }
8367     },
8368
8369     // private
8370     onBlur : function(){
8371         // do nothing
8372     },
8373
8374     // private
8375     mimicBlur : function(e, t){
8376         /*
8377         if(!this.wrap.contains(t) && this.validateBlur()){
8378             this.triggerBlur();
8379         }
8380         */
8381     },
8382
8383     // private
8384     triggerBlur : function(){
8385         this.mimicing = false;
8386         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8387         if(this.monitorTab){
8388             this.el.un("keydown", this.checkTab, this);
8389         }
8390         //this.wrap.removeClass('x-trigger-wrap-focus');
8391         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8392     },
8393
8394     // private
8395     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8396     validateBlur : function(e, t){
8397         return true;
8398     },
8399
8400     // private
8401     onDisable : function(){
8402         this.inputEl().dom.disabled = true;
8403         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8404         //if(this.wrap){
8405         //    this.wrap.addClass('x-item-disabled');
8406         //}
8407     },
8408
8409     // private
8410     onEnable : function(){
8411         this.inputEl().dom.disabled = false;
8412         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8413         //if(this.wrap){
8414         //    this.el.removeClass('x-item-disabled');
8415         //}
8416     },
8417
8418     // private
8419     onShow : function(){
8420         var ae = this.getActionEl();
8421         
8422         if(ae){
8423             ae.dom.style.display = '';
8424             ae.dom.style.visibility = 'visible';
8425         }
8426     },
8427
8428     // private
8429     
8430     onHide : function(){
8431         var ae = this.getActionEl();
8432         ae.dom.style.display = 'none';
8433     },
8434
8435     /**
8436      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8437      * by an implementing function.
8438      * @method
8439      * @param {EventObject} e
8440      */
8441     onTriggerClick : Roo.emptyFn
8442 });
8443  /*
8444  * Based on:
8445  * Ext JS Library 1.1.1
8446  * Copyright(c) 2006-2007, Ext JS, LLC.
8447  *
8448  * Originally Released Under LGPL - original licence link has changed is not relivant.
8449  *
8450  * Fork - LGPL
8451  * <script type="text/javascript">
8452  */
8453
8454
8455 /**
8456  * @class Roo.data.SortTypes
8457  * @singleton
8458  * Defines the default sorting (casting?) comparison functions used when sorting data.
8459  */
8460 Roo.data.SortTypes = {
8461     /**
8462      * Default sort that does nothing
8463      * @param {Mixed} s The value being converted
8464      * @return {Mixed} The comparison value
8465      */
8466     none : function(s){
8467         return s;
8468     },
8469     
8470     /**
8471      * The regular expression used to strip tags
8472      * @type {RegExp}
8473      * @property
8474      */
8475     stripTagsRE : /<\/?[^>]+>/gi,
8476     
8477     /**
8478      * Strips all HTML tags to sort on text only
8479      * @param {Mixed} s The value being converted
8480      * @return {String} The comparison value
8481      */
8482     asText : function(s){
8483         return String(s).replace(this.stripTagsRE, "");
8484     },
8485     
8486     /**
8487      * Strips all HTML tags to sort on text only - Case insensitive
8488      * @param {Mixed} s The value being converted
8489      * @return {String} The comparison value
8490      */
8491     asUCText : function(s){
8492         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8493     },
8494     
8495     /**
8496      * Case insensitive string
8497      * @param {Mixed} s The value being converted
8498      * @return {String} The comparison value
8499      */
8500     asUCString : function(s) {
8501         return String(s).toUpperCase();
8502     },
8503     
8504     /**
8505      * Date sorting
8506      * @param {Mixed} s The value being converted
8507      * @return {Number} The comparison value
8508      */
8509     asDate : function(s) {
8510         if(!s){
8511             return 0;
8512         }
8513         if(s instanceof Date){
8514             return s.getTime();
8515         }
8516         return Date.parse(String(s));
8517     },
8518     
8519     /**
8520      * Float sorting
8521      * @param {Mixed} s The value being converted
8522      * @return {Float} The comparison value
8523      */
8524     asFloat : function(s) {
8525         var val = parseFloat(String(s).replace(/,/g, ""));
8526         if(isNaN(val)) val = 0;
8527         return val;
8528     },
8529     
8530     /**
8531      * Integer sorting
8532      * @param {Mixed} s The value being converted
8533      * @return {Number} The comparison value
8534      */
8535     asInt : function(s) {
8536         var val = parseInt(String(s).replace(/,/g, ""));
8537         if(isNaN(val)) val = 0;
8538         return val;
8539     }
8540 };/*
8541  * Based on:
8542  * Ext JS Library 1.1.1
8543  * Copyright(c) 2006-2007, Ext JS, LLC.
8544  *
8545  * Originally Released Under LGPL - original licence link has changed is not relivant.
8546  *
8547  * Fork - LGPL
8548  * <script type="text/javascript">
8549  */
8550
8551 /**
8552 * @class Roo.data.Record
8553  * Instances of this class encapsulate both record <em>definition</em> information, and record
8554  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8555  * to access Records cached in an {@link Roo.data.Store} object.<br>
8556  * <p>
8557  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8558  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8559  * objects.<br>
8560  * <p>
8561  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8562  * @constructor
8563  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8564  * {@link #create}. The parameters are the same.
8565  * @param {Array} data An associative Array of data values keyed by the field name.
8566  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8567  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8568  * not specified an integer id is generated.
8569  */
8570 Roo.data.Record = function(data, id){
8571     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8572     this.data = data;
8573 };
8574
8575 /**
8576  * Generate a constructor for a specific record layout.
8577  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8578  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8579  * Each field definition object may contain the following properties: <ul>
8580  * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
8581  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8582  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8583  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8584  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8585  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8586  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8587  * this may be omitted.</p></li>
8588  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8589  * <ul><li>auto (Default, implies no conversion)</li>
8590  * <li>string</li>
8591  * <li>int</li>
8592  * <li>float</li>
8593  * <li>boolean</li>
8594  * <li>date</li></ul></p></li>
8595  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8596  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8597  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8598  * by the Reader into an object that will be stored in the Record. It is passed the
8599  * following parameters:<ul>
8600  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8601  * </ul></p></li>
8602  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8603  * </ul>
8604  * <br>usage:<br><pre><code>
8605 var TopicRecord = Roo.data.Record.create(
8606     {name: 'title', mapping: 'topic_title'},
8607     {name: 'author', mapping: 'username'},
8608     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8609     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8610     {name: 'lastPoster', mapping: 'user2'},
8611     {name: 'excerpt', mapping: 'post_text'}
8612 );
8613
8614 var myNewRecord = new TopicRecord({
8615     title: 'Do my job please',
8616     author: 'noobie',
8617     totalPosts: 1,
8618     lastPost: new Date(),
8619     lastPoster: 'Animal',
8620     excerpt: 'No way dude!'
8621 });
8622 myStore.add(myNewRecord);
8623 </code></pre>
8624  * @method create
8625  * @static
8626  */
8627 Roo.data.Record.create = function(o){
8628     var f = function(){
8629         f.superclass.constructor.apply(this, arguments);
8630     };
8631     Roo.extend(f, Roo.data.Record);
8632     var p = f.prototype;
8633     p.fields = new Roo.util.MixedCollection(false, function(field){
8634         return field.name;
8635     });
8636     for(var i = 0, len = o.length; i < len; i++){
8637         p.fields.add(new Roo.data.Field(o[i]));
8638     }
8639     f.getField = function(name){
8640         return p.fields.get(name);  
8641     };
8642     return f;
8643 };
8644
8645 Roo.data.Record.AUTO_ID = 1000;
8646 Roo.data.Record.EDIT = 'edit';
8647 Roo.data.Record.REJECT = 'reject';
8648 Roo.data.Record.COMMIT = 'commit';
8649
8650 Roo.data.Record.prototype = {
8651     /**
8652      * Readonly flag - true if this record has been modified.
8653      * @type Boolean
8654      */
8655     dirty : false,
8656     editing : false,
8657     error: null,
8658     modified: null,
8659
8660     // private
8661     join : function(store){
8662         this.store = store;
8663     },
8664
8665     /**
8666      * Set the named field to the specified value.
8667      * @param {String} name The name of the field to set.
8668      * @param {Object} value The value to set the field to.
8669      */
8670     set : function(name, value){
8671         if(this.data[name] == value){
8672             return;
8673         }
8674         this.dirty = true;
8675         if(!this.modified){
8676             this.modified = {};
8677         }
8678         if(typeof this.modified[name] == 'undefined'){
8679             this.modified[name] = this.data[name];
8680         }
8681         this.data[name] = value;
8682         if(!this.editing && this.store){
8683             this.store.afterEdit(this);
8684         }       
8685     },
8686
8687     /**
8688      * Get the value of the named field.
8689      * @param {String} name The name of the field to get the value of.
8690      * @return {Object} The value of the field.
8691      */
8692     get : function(name){
8693         return this.data[name]; 
8694     },
8695
8696     // private
8697     beginEdit : function(){
8698         this.editing = true;
8699         this.modified = {}; 
8700     },
8701
8702     // private
8703     cancelEdit : function(){
8704         this.editing = false;
8705         delete this.modified;
8706     },
8707
8708     // private
8709     endEdit : function(){
8710         this.editing = false;
8711         if(this.dirty && this.store){
8712             this.store.afterEdit(this);
8713         }
8714     },
8715
8716     /**
8717      * Usually called by the {@link Roo.data.Store} which owns the Record.
8718      * Rejects all changes made to the Record since either creation, or the last commit operation.
8719      * Modified fields are reverted to their original values.
8720      * <p>
8721      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8722      * of reject operations.
8723      */
8724     reject : function(){
8725         var m = this.modified;
8726         for(var n in m){
8727             if(typeof m[n] != "function"){
8728                 this.data[n] = m[n];
8729             }
8730         }
8731         this.dirty = false;
8732         delete this.modified;
8733         this.editing = false;
8734         if(this.store){
8735             this.store.afterReject(this);
8736         }
8737     },
8738
8739     /**
8740      * Usually called by the {@link Roo.data.Store} which owns the Record.
8741      * Commits all changes made to the Record since either creation, or the last commit operation.
8742      * <p>
8743      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8744      * of commit operations.
8745      */
8746     commit : function(){
8747         this.dirty = false;
8748         delete this.modified;
8749         this.editing = false;
8750         if(this.store){
8751             this.store.afterCommit(this);
8752         }
8753     },
8754
8755     // private
8756     hasError : function(){
8757         return this.error != null;
8758     },
8759
8760     // private
8761     clearError : function(){
8762         this.error = null;
8763     },
8764
8765     /**
8766      * Creates a copy of this record.
8767      * @param {String} id (optional) A new record id if you don't want to use this record's id
8768      * @return {Record}
8769      */
8770     copy : function(newId) {
8771         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8772     }
8773 };/*
8774  * Based on:
8775  * Ext JS Library 1.1.1
8776  * Copyright(c) 2006-2007, Ext JS, LLC.
8777  *
8778  * Originally Released Under LGPL - original licence link has changed is not relivant.
8779  *
8780  * Fork - LGPL
8781  * <script type="text/javascript">
8782  */
8783
8784
8785
8786 /**
8787  * @class Roo.data.Store
8788  * @extends Roo.util.Observable
8789  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8790  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8791  * <p>
8792  * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
8793  * has no knowledge of the format of the data returned by the Proxy.<br>
8794  * <p>
8795  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8796  * instances from the data object. These records are cached and made available through accessor functions.
8797  * @constructor
8798  * Creates a new Store.
8799  * @param {Object} config A config object containing the objects needed for the Store to access data,
8800  * and read the data into Records.
8801  */
8802 Roo.data.Store = function(config){
8803     this.data = new Roo.util.MixedCollection(false);
8804     this.data.getKey = function(o){
8805         return o.id;
8806     };
8807     this.baseParams = {};
8808     // private
8809     this.paramNames = {
8810         "start" : "start",
8811         "limit" : "limit",
8812         "sort" : "sort",
8813         "dir" : "dir",
8814         "multisort" : "_multisort"
8815     };
8816
8817     if(config && config.data){
8818         this.inlineData = config.data;
8819         delete config.data;
8820     }
8821
8822     Roo.apply(this, config);
8823     
8824     if(this.reader){ // reader passed
8825         this.reader = Roo.factory(this.reader, Roo.data);
8826         this.reader.xmodule = this.xmodule || false;
8827         if(!this.recordType){
8828             this.recordType = this.reader.recordType;
8829         }
8830         if(this.reader.onMetaChange){
8831             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8832         }
8833     }
8834
8835     if(this.recordType){
8836         this.fields = this.recordType.prototype.fields;
8837     }
8838     this.modified = [];
8839
8840     this.addEvents({
8841         /**
8842          * @event datachanged
8843          * Fires when the data cache has changed, and a widget which is using this Store
8844          * as a Record cache should refresh its view.
8845          * @param {Store} this
8846          */
8847         datachanged : true,
8848         /**
8849          * @event metachange
8850          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8851          * @param {Store} this
8852          * @param {Object} meta The JSON metadata
8853          */
8854         metachange : true,
8855         /**
8856          * @event add
8857          * Fires when Records have been added to the Store
8858          * @param {Store} this
8859          * @param {Roo.data.Record[]} records The array of Records added
8860          * @param {Number} index The index at which the record(s) were added
8861          */
8862         add : true,
8863         /**
8864          * @event remove
8865          * Fires when a Record has been removed from the Store
8866          * @param {Store} this
8867          * @param {Roo.data.Record} record The Record that was removed
8868          * @param {Number} index The index at which the record was removed
8869          */
8870         remove : true,
8871         /**
8872          * @event update
8873          * Fires when a Record has been updated
8874          * @param {Store} this
8875          * @param {Roo.data.Record} record The Record that was updated
8876          * @param {String} operation The update operation being performed.  Value may be one of:
8877          * <pre><code>
8878  Roo.data.Record.EDIT
8879  Roo.data.Record.REJECT
8880  Roo.data.Record.COMMIT
8881          * </code></pre>
8882          */
8883         update : true,
8884         /**
8885          * @event clear
8886          * Fires when the data cache has been cleared.
8887          * @param {Store} this
8888          */
8889         clear : true,
8890         /**
8891          * @event beforeload
8892          * Fires before a request is made for a new data object.  If the beforeload handler returns false
8893          * the load action will be canceled.
8894          * @param {Store} this
8895          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8896          */
8897         beforeload : true,
8898         /**
8899          * @event beforeloadadd
8900          * Fires after a new set of Records has been loaded.
8901          * @param {Store} this
8902          * @param {Roo.data.Record[]} records The Records that were loaded
8903          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8904          */
8905         beforeloadadd : true,
8906         /**
8907          * @event load
8908          * Fires after a new set of Records has been loaded, before they are added to the store.
8909          * @param {Store} this
8910          * @param {Roo.data.Record[]} records The Records that were loaded
8911          * @param {Object} options The loading options that were specified (see {@link #load} for details)
8912          * @params {Object} return from reader
8913          */
8914         load : true,
8915         /**
8916          * @event loadexception
8917          * Fires if an exception occurs in the Proxy during loading.
8918          * Called with the signature of the Proxy's "loadexception" event.
8919          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8920          * 
8921          * @param {Proxy} 
8922          * @param {Object} return from JsonData.reader() - success, totalRecords, records
8923          * @param {Object} load options 
8924          * @param {Object} jsonData from your request (normally this contains the Exception)
8925          */
8926         loadexception : true
8927     });
8928     
8929     if(this.proxy){
8930         this.proxy = Roo.factory(this.proxy, Roo.data);
8931         this.proxy.xmodule = this.xmodule || false;
8932         this.relayEvents(this.proxy,  ["loadexception"]);
8933     }
8934     this.sortToggle = {};
8935     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8936
8937     Roo.data.Store.superclass.constructor.call(this);
8938
8939     if(this.inlineData){
8940         this.loadData(this.inlineData);
8941         delete this.inlineData;
8942     }
8943 };
8944
8945 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8946      /**
8947     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
8948     * without a remote query - used by combo/forms at present.
8949     */
8950     
8951     /**
8952     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8953     */
8954     /**
8955     * @cfg {Array} data Inline data to be loaded when the store is initialized.
8956     */
8957     /**
8958     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8959     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8960     */
8961     /**
8962     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8963     * on any HTTP request
8964     */
8965     /**
8966     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8967     */
8968     /**
8969     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8970     */
8971     multiSort: false,
8972     /**
8973     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8974     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8975     */
8976     remoteSort : false,
8977
8978     /**
8979     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8980      * loaded or when a record is removed. (defaults to false).
8981     */
8982     pruneModifiedRecords : false,
8983
8984     // private
8985     lastOptions : null,
8986
8987     /**
8988      * Add Records to the Store and fires the add event.
8989      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8990      */
8991     add : function(records){
8992         records = [].concat(records);
8993         for(var i = 0, len = records.length; i < len; i++){
8994             records[i].join(this);
8995         }
8996         var index = this.data.length;
8997         this.data.addAll(records);
8998         this.fireEvent("add", this, records, index);
8999     },
9000
9001     /**
9002      * Remove a Record from the Store and fires the remove event.
9003      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9004      */
9005     remove : function(record){
9006         var index = this.data.indexOf(record);
9007         this.data.removeAt(index);
9008         if(this.pruneModifiedRecords){
9009             this.modified.remove(record);
9010         }
9011         this.fireEvent("remove", this, record, index);
9012     },
9013
9014     /**
9015      * Remove all Records from the Store and fires the clear event.
9016      */
9017     removeAll : function(){
9018         this.data.clear();
9019         if(this.pruneModifiedRecords){
9020             this.modified = [];
9021         }
9022         this.fireEvent("clear", this);
9023     },
9024
9025     /**
9026      * Inserts Records to the Store at the given index and fires the add event.
9027      * @param {Number} index The start index at which to insert the passed Records.
9028      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9029      */
9030     insert : function(index, records){
9031         records = [].concat(records);
9032         for(var i = 0, len = records.length; i < len; i++){
9033             this.data.insert(index, records[i]);
9034             records[i].join(this);
9035         }
9036         this.fireEvent("add", this, records, index);
9037     },
9038
9039     /**
9040      * Get the index within the cache of the passed Record.
9041      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9042      * @return {Number} The index of the passed Record. Returns -1 if not found.
9043      */
9044     indexOf : function(record){
9045         return this.data.indexOf(record);
9046     },
9047
9048     /**
9049      * Get the index within the cache of the Record with the passed id.
9050      * @param {String} id The id of the Record to find.
9051      * @return {Number} The index of the Record. Returns -1 if not found.
9052      */
9053     indexOfId : function(id){
9054         return this.data.indexOfKey(id);
9055     },
9056
9057     /**
9058      * Get the Record with the specified id.
9059      * @param {String} id The id of the Record to find.
9060      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9061      */
9062     getById : function(id){
9063         return this.data.key(id);
9064     },
9065
9066     /**
9067      * Get the Record at the specified index.
9068      * @param {Number} index The index of the Record to find.
9069      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9070      */
9071     getAt : function(index){
9072         return this.data.itemAt(index);
9073     },
9074
9075     /**
9076      * Returns a range of Records between specified indices.
9077      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9078      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9079      * @return {Roo.data.Record[]} An array of Records
9080      */
9081     getRange : function(start, end){
9082         return this.data.getRange(start, end);
9083     },
9084
9085     // private
9086     storeOptions : function(o){
9087         o = Roo.apply({}, o);
9088         delete o.callback;
9089         delete o.scope;
9090         this.lastOptions = o;
9091     },
9092
9093     /**
9094      * Loads the Record cache from the configured Proxy using the configured Reader.
9095      * <p>
9096      * If using remote paging, then the first load call must specify the <em>start</em>
9097      * and <em>limit</em> properties in the options.params property to establish the initial
9098      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9099      * <p>
9100      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9101      * and this call will return before the new data has been loaded. Perform any post-processing
9102      * in a callback function, or in a "load" event handler.</strong>
9103      * <p>
9104      * @param {Object} options An object containing properties which control loading options:<ul>
9105      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9106      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9107      * passed the following arguments:<ul>
9108      * <li>r : Roo.data.Record[]</li>
9109      * <li>options: Options object from the load call</li>
9110      * <li>success: Boolean success indicator</li></ul></li>
9111      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9112      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9113      * </ul>
9114      */
9115     load : function(options){
9116         options = options || {};
9117         if(this.fireEvent("beforeload", this, options) !== false){
9118             this.storeOptions(options);
9119             var p = Roo.apply(options.params || {}, this.baseParams);
9120             // if meta was not loaded from remote source.. try requesting it.
9121             if (!this.reader.metaFromRemote) {
9122                 p._requestMeta = 1;
9123             }
9124             if(this.sortInfo && this.remoteSort){
9125                 var pn = this.paramNames;
9126                 p[pn["sort"]] = this.sortInfo.field;
9127                 p[pn["dir"]] = this.sortInfo.direction;
9128             }
9129             if (this.multiSort) {
9130                 var pn = this.paramNames;
9131                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9132             }
9133             
9134             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9135         }
9136     },
9137
9138     /**
9139      * Reloads the Record cache from the configured Proxy using the configured Reader and
9140      * the options from the last load operation performed.
9141      * @param {Object} options (optional) An object containing properties which may override the options
9142      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9143      * the most recently used options are reused).
9144      */
9145     reload : function(options){
9146         this.load(Roo.applyIf(options||{}, this.lastOptions));
9147     },
9148
9149     // private
9150     // Called as a callback by the Reader during a load operation.
9151     loadRecords : function(o, options, success){
9152         if(!o || success === false){
9153             if(success !== false){
9154                 this.fireEvent("load", this, [], options, o);
9155             }
9156             if(options.callback){
9157                 options.callback.call(options.scope || this, [], options, false);
9158             }
9159             return;
9160         }
9161         // if data returned failure - throw an exception.
9162         if (o.success === false) {
9163             // show a message if no listener is registered.
9164             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9165                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9166             }
9167             // loadmask wil be hooked into this..
9168             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9169             return;
9170         }
9171         var r = o.records, t = o.totalRecords || r.length;
9172         
9173         this.fireEvent("beforeloadadd", this, r, options, o);
9174         
9175         if(!options || options.add !== true){
9176             if(this.pruneModifiedRecords){
9177                 this.modified = [];
9178             }
9179             for(var i = 0, len = r.length; i < len; i++){
9180                 r[i].join(this);
9181             }
9182             if(this.snapshot){
9183                 this.data = this.snapshot;
9184                 delete this.snapshot;
9185             }
9186             this.data.clear();
9187             this.data.addAll(r);
9188             this.totalLength = t;
9189             this.applySort();
9190             this.fireEvent("datachanged", this);
9191         }else{
9192             this.totalLength = Math.max(t, this.data.length+r.length);
9193             this.add(r);
9194         }
9195         this.fireEvent("load", this, r, options, o);
9196         if(options.callback){
9197             options.callback.call(options.scope || this, r, options, true);
9198         }
9199     },
9200
9201
9202     /**
9203      * Loads data from a passed data block. A Reader which understands the format of the data
9204      * must have been configured in the constructor.
9205      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9206      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9207      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9208      */
9209     loadData : function(o, append){
9210         var r = this.reader.readRecords(o);
9211         this.loadRecords(r, {add: append}, true);
9212     },
9213
9214     /**
9215      * Gets the number of cached records.
9216      * <p>
9217      * <em>If using paging, this may not be the total size of the dataset. If the data object
9218      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9219      * the data set size</em>
9220      */
9221     getCount : function(){
9222         return this.data.length || 0;
9223     },
9224
9225     /**
9226      * Gets the total number of records in the dataset as returned by the server.
9227      * <p>
9228      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9229      * the dataset size</em>
9230      */
9231     getTotalCount : function(){
9232         return this.totalLength || 0;
9233     },
9234
9235     /**
9236      * Returns the sort state of the Store as an object with two properties:
9237      * <pre><code>
9238  field {String} The name of the field by which the Records are sorted
9239  direction {String} The sort order, "ASC" or "DESC"
9240      * </code></pre>
9241      */
9242     getSortState : function(){
9243         return this.sortInfo;
9244     },
9245
9246     // private
9247     applySort : function(){
9248         if(this.sortInfo && !this.remoteSort){
9249             var s = this.sortInfo, f = s.field;
9250             var st = this.fields.get(f).sortType;
9251             var fn = function(r1, r2){
9252                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9253                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9254             };
9255             this.data.sort(s.direction, fn);
9256             if(this.snapshot && this.snapshot != this.data){
9257                 this.snapshot.sort(s.direction, fn);
9258             }
9259         }
9260     },
9261
9262     /**
9263      * Sets the default sort column and order to be used by the next load operation.
9264      * @param {String} fieldName The name of the field to sort by.
9265      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9266      */
9267     setDefaultSort : function(field, dir){
9268         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9269     },
9270
9271     /**
9272      * Sort the Records.
9273      * If remote sorting is used, the sort is performed on the server, and the cache is
9274      * reloaded. If local sorting is used, the cache is sorted internally.
9275      * @param {String} fieldName The name of the field to sort by.
9276      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9277      */
9278     sort : function(fieldName, dir){
9279         var f = this.fields.get(fieldName);
9280         if(!dir){
9281             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9282             
9283             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9284                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9285             }else{
9286                 dir = f.sortDir;
9287             }
9288         }
9289         this.sortToggle[f.name] = dir;
9290         this.sortInfo = {field: f.name, direction: dir};
9291         if(!this.remoteSort){
9292             this.applySort();
9293             this.fireEvent("datachanged", this);
9294         }else{
9295             this.load(this.lastOptions);
9296         }
9297     },
9298
9299     /**
9300      * Calls the specified function for each of the Records in the cache.
9301      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9302      * Returning <em>false</em> aborts and exits the iteration.
9303      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9304      */
9305     each : function(fn, scope){
9306         this.data.each(fn, scope);
9307     },
9308
9309     /**
9310      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9311      * (e.g., during paging).
9312      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9313      */
9314     getModifiedRecords : function(){
9315         return this.modified;
9316     },
9317
9318     // private
9319     createFilterFn : function(property, value, anyMatch){
9320         if(!value.exec){ // not a regex
9321             value = String(value);
9322             if(value.length == 0){
9323                 return false;
9324             }
9325             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9326         }
9327         return function(r){
9328             return value.test(r.data[property]);
9329         };
9330     },
9331
9332     /**
9333      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9334      * @param {String} property A field on your records
9335      * @param {Number} start The record index to start at (defaults to 0)
9336      * @param {Number} end The last record index to include (defaults to length - 1)
9337      * @return {Number} The sum
9338      */
9339     sum : function(property, start, end){
9340         var rs = this.data.items, v = 0;
9341         start = start || 0;
9342         end = (end || end === 0) ? end : rs.length-1;
9343
9344         for(var i = start; i <= end; i++){
9345             v += (rs[i].data[property] || 0);
9346         }
9347         return v;
9348     },
9349
9350     /**
9351      * Filter the records by a specified property.
9352      * @param {String} field A field on your records
9353      * @param {String/RegExp} value Either a string that the field
9354      * should start with or a RegExp to test against the field
9355      * @param {Boolean} anyMatch True to match any part not just the beginning
9356      */
9357     filter : function(property, value, anyMatch){
9358         var fn = this.createFilterFn(property, value, anyMatch);
9359         return fn ? this.filterBy(fn) : this.clearFilter();
9360     },
9361
9362     /**
9363      * Filter by a function. The specified function will be called with each
9364      * record in this data source. If the function returns true the record is included,
9365      * otherwise it is filtered.
9366      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9367      * @param {Object} scope (optional) The scope of the function (defaults to this)
9368      */
9369     filterBy : function(fn, scope){
9370         this.snapshot = this.snapshot || this.data;
9371         this.data = this.queryBy(fn, scope||this);
9372         this.fireEvent("datachanged", this);
9373     },
9374
9375     /**
9376      * Query the records by a specified property.
9377      * @param {String} field A field on your records
9378      * @param {String/RegExp} value Either a string that the field
9379      * should start with or a RegExp to test against the field
9380      * @param {Boolean} anyMatch True to match any part not just the beginning
9381      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9382      */
9383     query : function(property, value, anyMatch){
9384         var fn = this.createFilterFn(property, value, anyMatch);
9385         return fn ? this.queryBy(fn) : this.data.clone();
9386     },
9387
9388     /**
9389      * Query by a function. The specified function will be called with each
9390      * record in this data source. If the function returns true the record is included
9391      * in the results.
9392      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9393      * @param {Object} scope (optional) The scope of the function (defaults to this)
9394       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9395      **/
9396     queryBy : function(fn, scope){
9397         var data = this.snapshot || this.data;
9398         return data.filterBy(fn, scope||this);
9399     },
9400
9401     /**
9402      * Collects unique values for a particular dataIndex from this store.
9403      * @param {String} dataIndex The property to collect
9404      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9405      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9406      * @return {Array} An array of the unique values
9407      **/
9408     collect : function(dataIndex, allowNull, bypassFilter){
9409         var d = (bypassFilter === true && this.snapshot) ?
9410                 this.snapshot.items : this.data.items;
9411         var v, sv, r = [], l = {};
9412         for(var i = 0, len = d.length; i < len; i++){
9413             v = d[i].data[dataIndex];
9414             sv = String(v);
9415             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9416                 l[sv] = true;
9417                 r[r.length] = v;
9418             }
9419         }
9420         return r;
9421     },
9422
9423     /**
9424      * Revert to a view of the Record cache with no filtering applied.
9425      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9426      */
9427     clearFilter : function(suppressEvent){
9428         if(this.snapshot && this.snapshot != this.data){
9429             this.data = this.snapshot;
9430             delete this.snapshot;
9431             if(suppressEvent !== true){
9432                 this.fireEvent("datachanged", this);
9433             }
9434         }
9435     },
9436
9437     // private
9438     afterEdit : function(record){
9439         if(this.modified.indexOf(record) == -1){
9440             this.modified.push(record);
9441         }
9442         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9443     },
9444     
9445     // private
9446     afterReject : function(record){
9447         this.modified.remove(record);
9448         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9449     },
9450
9451     // private
9452     afterCommit : function(record){
9453         this.modified.remove(record);
9454         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9455     },
9456
9457     /**
9458      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9459      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9460      */
9461     commitChanges : function(){
9462         var m = this.modified.slice(0);
9463         this.modified = [];
9464         for(var i = 0, len = m.length; i < len; i++){
9465             m[i].commit();
9466         }
9467     },
9468
9469     /**
9470      * Cancel outstanding changes on all changed records.
9471      */
9472     rejectChanges : function(){
9473         var m = this.modified.slice(0);
9474         this.modified = [];
9475         for(var i = 0, len = m.length; i < len; i++){
9476             m[i].reject();
9477         }
9478     },
9479
9480     onMetaChange : function(meta, rtype, o){
9481         this.recordType = rtype;
9482         this.fields = rtype.prototype.fields;
9483         delete this.snapshot;
9484         this.sortInfo = meta.sortInfo || this.sortInfo;
9485         this.modified = [];
9486         this.fireEvent('metachange', this, this.reader.meta);
9487     },
9488     
9489     moveIndex : function(data, type)
9490     {
9491         var index = this.indexOf(data);
9492         
9493         var newIndex = index + type;
9494         
9495         this.remove(data);
9496         
9497         this.insert(newIndex, data);
9498         
9499     }
9500 });/*
9501  * Based on:
9502  * Ext JS Library 1.1.1
9503  * Copyright(c) 2006-2007, Ext JS, LLC.
9504  *
9505  * Originally Released Under LGPL - original licence link has changed is not relivant.
9506  *
9507  * Fork - LGPL
9508  * <script type="text/javascript">
9509  */
9510
9511 /**
9512  * @class Roo.data.SimpleStore
9513  * @extends Roo.data.Store
9514  * Small helper class to make creating Stores from Array data easier.
9515  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9516  * @cfg {Array} fields An array of field definition objects, or field name strings.
9517  * @cfg {Array} data The multi-dimensional array of data
9518  * @constructor
9519  * @param {Object} config
9520  */
9521 Roo.data.SimpleStore = function(config){
9522     Roo.data.SimpleStore.superclass.constructor.call(this, {
9523         isLocal : true,
9524         reader: new Roo.data.ArrayReader({
9525                 id: config.id
9526             },
9527             Roo.data.Record.create(config.fields)
9528         ),
9529         proxy : new Roo.data.MemoryProxy(config.data)
9530     });
9531     this.load();
9532 };
9533 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9534  * Based on:
9535  * Ext JS Library 1.1.1
9536  * Copyright(c) 2006-2007, Ext JS, LLC.
9537  *
9538  * Originally Released Under LGPL - original licence link has changed is not relivant.
9539  *
9540  * Fork - LGPL
9541  * <script type="text/javascript">
9542  */
9543
9544 /**
9545 /**
9546  * @extends Roo.data.Store
9547  * @class Roo.data.JsonStore
9548  * Small helper class to make creating Stores for JSON data easier. <br/>
9549 <pre><code>
9550 var store = new Roo.data.JsonStore({
9551     url: 'get-images.php',
9552     root: 'images',
9553     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9554 });
9555 </code></pre>
9556  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9557  * JsonReader and HttpProxy (unless inline data is provided).</b>
9558  * @cfg {Array} fields An array of field definition objects, or field name strings.
9559  * @constructor
9560  * @param {Object} config
9561  */
9562 Roo.data.JsonStore = function(c){
9563     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9564         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9565         reader: new Roo.data.JsonReader(c, c.fields)
9566     }));
9567 };
9568 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9569  * Based on:
9570  * Ext JS Library 1.1.1
9571  * Copyright(c) 2006-2007, Ext JS, LLC.
9572  *
9573  * Originally Released Under LGPL - original licence link has changed is not relivant.
9574  *
9575  * Fork - LGPL
9576  * <script type="text/javascript">
9577  */
9578
9579  
9580 Roo.data.Field = function(config){
9581     if(typeof config == "string"){
9582         config = {name: config};
9583     }
9584     Roo.apply(this, config);
9585     
9586     if(!this.type){
9587         this.type = "auto";
9588     }
9589     
9590     var st = Roo.data.SortTypes;
9591     // named sortTypes are supported, here we look them up
9592     if(typeof this.sortType == "string"){
9593         this.sortType = st[this.sortType];
9594     }
9595     
9596     // set default sortType for strings and dates
9597     if(!this.sortType){
9598         switch(this.type){
9599             case "string":
9600                 this.sortType = st.asUCString;
9601                 break;
9602             case "date":
9603                 this.sortType = st.asDate;
9604                 break;
9605             default:
9606                 this.sortType = st.none;
9607         }
9608     }
9609
9610     // define once
9611     var stripRe = /[\$,%]/g;
9612
9613     // prebuilt conversion function for this field, instead of
9614     // switching every time we're reading a value
9615     if(!this.convert){
9616         var cv, dateFormat = this.dateFormat;
9617         switch(this.type){
9618             case "":
9619             case "auto":
9620             case undefined:
9621                 cv = function(v){ return v; };
9622                 break;
9623             case "string":
9624                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9625                 break;
9626             case "int":
9627                 cv = function(v){
9628                     return v !== undefined && v !== null && v !== '' ?
9629                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9630                     };
9631                 break;
9632             case "float":
9633                 cv = function(v){
9634                     return v !== undefined && v !== null && v !== '' ?
9635                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9636                     };
9637                 break;
9638             case "bool":
9639             case "boolean":
9640                 cv = function(v){ return v === true || v === "true" || v == 1; };
9641                 break;
9642             case "date":
9643                 cv = function(v){
9644                     if(!v){
9645                         return '';
9646                     }
9647                     if(v instanceof Date){
9648                         return v;
9649                     }
9650                     if(dateFormat){
9651                         if(dateFormat == "timestamp"){
9652                             return new Date(v*1000);
9653                         }
9654                         return Date.parseDate(v, dateFormat);
9655                     }
9656                     var parsed = Date.parse(v);
9657                     return parsed ? new Date(parsed) : null;
9658                 };
9659              break;
9660             
9661         }
9662         this.convert = cv;
9663     }
9664 };
9665
9666 Roo.data.Field.prototype = {
9667     dateFormat: null,
9668     defaultValue: "",
9669     mapping: null,
9670     sortType : null,
9671     sortDir : "ASC"
9672 };/*
9673  * Based on:
9674  * Ext JS Library 1.1.1
9675  * Copyright(c) 2006-2007, Ext JS, LLC.
9676  *
9677  * Originally Released Under LGPL - original licence link has changed is not relivant.
9678  *
9679  * Fork - LGPL
9680  * <script type="text/javascript">
9681  */
9682  
9683 // Base class for reading structured data from a data source.  This class is intended to be
9684 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9685
9686 /**
9687  * @class Roo.data.DataReader
9688  * Base class for reading structured data from a data source.  This class is intended to be
9689  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9690  */
9691
9692 Roo.data.DataReader = function(meta, recordType){
9693     
9694     this.meta = meta;
9695     
9696     this.recordType = recordType instanceof Array ? 
9697         Roo.data.Record.create(recordType) : recordType;
9698 };
9699
9700 Roo.data.DataReader.prototype = {
9701      /**
9702      * Create an empty record
9703      * @param {Object} data (optional) - overlay some values
9704      * @return {Roo.data.Record} record created.
9705      */
9706     newRow :  function(d) {
9707         var da =  {};
9708         this.recordType.prototype.fields.each(function(c) {
9709             switch( c.type) {
9710                 case 'int' : da[c.name] = 0; break;
9711                 case 'date' : da[c.name] = new Date(); break;
9712                 case 'float' : da[c.name] = 0.0; break;
9713                 case 'boolean' : da[c.name] = false; break;
9714                 default : da[c.name] = ""; break;
9715             }
9716             
9717         });
9718         return new this.recordType(Roo.apply(da, d));
9719     }
9720     
9721 };/*
9722  * Based on:
9723  * Ext JS Library 1.1.1
9724  * Copyright(c) 2006-2007, Ext JS, LLC.
9725  *
9726  * Originally Released Under LGPL - original licence link has changed is not relivant.
9727  *
9728  * Fork - LGPL
9729  * <script type="text/javascript">
9730  */
9731
9732 /**
9733  * @class Roo.data.DataProxy
9734  * @extends Roo.data.Observable
9735  * This class is an abstract base class for implementations which provide retrieval of
9736  * unformatted data objects.<br>
9737  * <p>
9738  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9739  * (of the appropriate type which knows how to parse the data object) to provide a block of
9740  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9741  * <p>
9742  * Custom implementations must implement the load method as described in
9743  * {@link Roo.data.HttpProxy#load}.
9744  */
9745 Roo.data.DataProxy = function(){
9746     this.addEvents({
9747         /**
9748          * @event beforeload
9749          * Fires before a network request is made to retrieve a data object.
9750          * @param {Object} This DataProxy object.
9751          * @param {Object} params The params parameter to the load function.
9752          */
9753         beforeload : true,
9754         /**
9755          * @event load
9756          * Fires before the load method's callback is called.
9757          * @param {Object} This DataProxy object.
9758          * @param {Object} o The data object.
9759          * @param {Object} arg The callback argument object passed to the load function.
9760          */
9761         load : true,
9762         /**
9763          * @event loadexception
9764          * Fires if an Exception occurs during data retrieval.
9765          * @param {Object} This DataProxy object.
9766          * @param {Object} o The data object.
9767          * @param {Object} arg The callback argument object passed to the load function.
9768          * @param {Object} e The Exception.
9769          */
9770         loadexception : true
9771     });
9772     Roo.data.DataProxy.superclass.constructor.call(this);
9773 };
9774
9775 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9776
9777     /**
9778      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9779      */
9780 /*
9781  * Based on:
9782  * Ext JS Library 1.1.1
9783  * Copyright(c) 2006-2007, Ext JS, LLC.
9784  *
9785  * Originally Released Under LGPL - original licence link has changed is not relivant.
9786  *
9787  * Fork - LGPL
9788  * <script type="text/javascript">
9789  */
9790 /**
9791  * @class Roo.data.MemoryProxy
9792  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9793  * to the Reader when its load method is called.
9794  * @constructor
9795  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9796  */
9797 Roo.data.MemoryProxy = function(data){
9798     if (data.data) {
9799         data = data.data;
9800     }
9801     Roo.data.MemoryProxy.superclass.constructor.call(this);
9802     this.data = data;
9803 };
9804
9805 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9806     /**
9807      * Load data from the requested source (in this case an in-memory
9808      * data object passed to the constructor), read the data object into
9809      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9810      * process that block using the passed callback.
9811      * @param {Object} params This parameter is not used by the MemoryProxy class.
9812      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9813      * object into a block of Roo.data.Records.
9814      * @param {Function} callback The function into which to pass the block of Roo.data.records.
9815      * The function must be passed <ul>
9816      * <li>The Record block object</li>
9817      * <li>The "arg" argument from the load function</li>
9818      * <li>A boolean success indicator</li>
9819      * </ul>
9820      * @param {Object} scope The scope in which to call the callback
9821      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9822      */
9823     load : function(params, reader, callback, scope, arg){
9824         params = params || {};
9825         var result;
9826         try {
9827             result = reader.readRecords(this.data);
9828         }catch(e){
9829             this.fireEvent("loadexception", this, arg, null, e);
9830             callback.call(scope, null, arg, false);
9831             return;
9832         }
9833         callback.call(scope, result, arg, true);
9834     },
9835     
9836     // private
9837     update : function(params, records){
9838         
9839     }
9840 });/*
9841  * Based on:
9842  * Ext JS Library 1.1.1
9843  * Copyright(c) 2006-2007, Ext JS, LLC.
9844  *
9845  * Originally Released Under LGPL - original licence link has changed is not relivant.
9846  *
9847  * Fork - LGPL
9848  * <script type="text/javascript">
9849  */
9850 /**
9851  * @class Roo.data.HttpProxy
9852  * @extends Roo.data.DataProxy
9853  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9854  * configured to reference a certain URL.<br><br>
9855  * <p>
9856  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9857  * from which the running page was served.<br><br>
9858  * <p>
9859  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9860  * <p>
9861  * Be aware that to enable the browser to parse an XML document, the server must set
9862  * the Content-Type header in the HTTP response to "text/xml".
9863  * @constructor
9864  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9865  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
9866  * will be used to make the request.
9867  */
9868 Roo.data.HttpProxy = function(conn){
9869     Roo.data.HttpProxy.superclass.constructor.call(this);
9870     // is conn a conn config or a real conn?
9871     this.conn = conn;
9872     this.useAjax = !conn || !conn.events;
9873   
9874 };
9875
9876 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9877     // thse are take from connection...
9878     
9879     /**
9880      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9881      */
9882     /**
9883      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9884      * extra parameters to each request made by this object. (defaults to undefined)
9885      */
9886     /**
9887      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9888      *  to each request made by this object. (defaults to undefined)
9889      */
9890     /**
9891      * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
9892      */
9893     /**
9894      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9895      */
9896      /**
9897      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9898      * @type Boolean
9899      */
9900   
9901
9902     /**
9903      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9904      * @type Boolean
9905      */
9906     /**
9907      * Return the {@link Roo.data.Connection} object being used by this Proxy.
9908      * @return {Connection} The Connection object. This object may be used to subscribe to events on
9909      * a finer-grained basis than the DataProxy events.
9910      */
9911     getConnection : function(){
9912         return this.useAjax ? Roo.Ajax : this.conn;
9913     },
9914
9915     /**
9916      * Load data from the configured {@link Roo.data.Connection}, read the data object into
9917      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9918      * process that block using the passed callback.
9919      * @param {Object} params An object containing properties which are to be used as HTTP parameters
9920      * for the request to the remote server.
9921      * @param {Roo.data.DataReader} reader The Reader object which converts the data
9922      * object into a block of Roo.data.Records.
9923      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9924      * The function must be passed <ul>
9925      * <li>The Record block object</li>
9926      * <li>The "arg" argument from the load function</li>
9927      * <li>A boolean success indicator</li>
9928      * </ul>
9929      * @param {Object} scope The scope in which to call the callback
9930      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9931      */
9932     load : function(params, reader, callback, scope, arg){
9933         if(this.fireEvent("beforeload", this, params) !== false){
9934             var  o = {
9935                 params : params || {},
9936                 request: {
9937                     callback : callback,
9938                     scope : scope,
9939                     arg : arg
9940                 },
9941                 reader: reader,
9942                 callback : this.loadResponse,
9943                 scope: this
9944             };
9945             if(this.useAjax){
9946                 Roo.applyIf(o, this.conn);
9947                 if(this.activeRequest){
9948                     Roo.Ajax.abort(this.activeRequest);
9949                 }
9950                 this.activeRequest = Roo.Ajax.request(o);
9951             }else{
9952                 this.conn.request(o);
9953             }
9954         }else{
9955             callback.call(scope||this, null, arg, false);
9956         }
9957     },
9958
9959     // private
9960     loadResponse : function(o, success, response){
9961         delete this.activeRequest;
9962         if(!success){
9963             this.fireEvent("loadexception", this, o, response);
9964             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9965             return;
9966         }
9967         var result;
9968         try {
9969             result = o.reader.read(response);
9970         }catch(e){
9971             this.fireEvent("loadexception", this, o, response, e);
9972             o.request.callback.call(o.request.scope, null, o.request.arg, false);
9973             return;
9974         }
9975         
9976         this.fireEvent("load", this, o, o.request.arg);
9977         o.request.callback.call(o.request.scope, result, o.request.arg, true);
9978     },
9979
9980     // private
9981     update : function(dataSet){
9982
9983     },
9984
9985     // private
9986     updateResponse : function(dataSet){
9987
9988     }
9989 });/*
9990  * Based on:
9991  * Ext JS Library 1.1.1
9992  * Copyright(c) 2006-2007, Ext JS, LLC.
9993  *
9994  * Originally Released Under LGPL - original licence link has changed is not relivant.
9995  *
9996  * Fork - LGPL
9997  * <script type="text/javascript">
9998  */
9999
10000 /**
10001  * @class Roo.data.ScriptTagProxy
10002  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10003  * other than the originating domain of the running page.<br><br>
10004  * <p>
10005  * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
10006  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10007  * <p>
10008  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10009  * source code that is used as the source inside a &lt;script> tag.<br><br>
10010  * <p>
10011  * In order for the browser to process the returned data, the server must wrap the data object
10012  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10013  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10014  * depending on whether the callback name was passed:
10015  * <p>
10016  * <pre><code>
10017 boolean scriptTag = false;
10018 String cb = request.getParameter("callback");
10019 if (cb != null) {
10020     scriptTag = true;
10021     response.setContentType("text/javascript");
10022 } else {
10023     response.setContentType("application/x-json");
10024 }
10025 Writer out = response.getWriter();
10026 if (scriptTag) {
10027     out.write(cb + "(");
10028 }
10029 out.print(dataBlock.toJsonString());
10030 if (scriptTag) {
10031     out.write(");");
10032 }
10033 </pre></code>
10034  *
10035  * @constructor
10036  * @param {Object} config A configuration object.
10037  */
10038 Roo.data.ScriptTagProxy = function(config){
10039     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10040     Roo.apply(this, config);
10041     this.head = document.getElementsByTagName("head")[0];
10042 };
10043
10044 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10045
10046 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10047     /**
10048      * @cfg {String} url The URL from which to request the data object.
10049      */
10050     /**
10051      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10052      */
10053     timeout : 30000,
10054     /**
10055      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10056      * the server the name of the callback function set up by the load call to process the returned data object.
10057      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10058      * javascript output which calls this named function passing the data object as its only parameter.
10059      */
10060     callbackParam : "callback",
10061     /**
10062      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10063      * name to the request.
10064      */
10065     nocache : true,
10066
10067     /**
10068      * Load data from the configured URL, read the data object into
10069      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10070      * process that block using the passed callback.
10071      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10072      * for the request to the remote server.
10073      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10074      * object into a block of Roo.data.Records.
10075      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10076      * The function must be passed <ul>
10077      * <li>The Record block object</li>
10078      * <li>The "arg" argument from the load function</li>
10079      * <li>A boolean success indicator</li>
10080      * </ul>
10081      * @param {Object} scope The scope in which to call the callback
10082      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10083      */
10084     load : function(params, reader, callback, scope, arg){
10085         if(this.fireEvent("beforeload", this, params) !== false){
10086
10087             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10088
10089             var url = this.url;
10090             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10091             if(this.nocache){
10092                 url += "&_dc=" + (new Date().getTime());
10093             }
10094             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10095             var trans = {
10096                 id : transId,
10097                 cb : "stcCallback"+transId,
10098                 scriptId : "stcScript"+transId,
10099                 params : params,
10100                 arg : arg,
10101                 url : url,
10102                 callback : callback,
10103                 scope : scope,
10104                 reader : reader
10105             };
10106             var conn = this;
10107
10108             window[trans.cb] = function(o){
10109                 conn.handleResponse(o, trans);
10110             };
10111
10112             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10113
10114             if(this.autoAbort !== false){
10115                 this.abort();
10116             }
10117
10118             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10119
10120             var script = document.createElement("script");
10121             script.setAttribute("src", url);
10122             script.setAttribute("type", "text/javascript");
10123             script.setAttribute("id", trans.scriptId);
10124             this.head.appendChild(script);
10125
10126             this.trans = trans;
10127         }else{
10128             callback.call(scope||this, null, arg, false);
10129         }
10130     },
10131
10132     // private
10133     isLoading : function(){
10134         return this.trans ? true : false;
10135     },
10136
10137     /**
10138      * Abort the current server request.
10139      */
10140     abort : function(){
10141         if(this.isLoading()){
10142             this.destroyTrans(this.trans);
10143         }
10144     },
10145
10146     // private
10147     destroyTrans : function(trans, isLoaded){
10148         this.head.removeChild(document.getElementById(trans.scriptId));
10149         clearTimeout(trans.timeoutId);
10150         if(isLoaded){
10151             window[trans.cb] = undefined;
10152             try{
10153                 delete window[trans.cb];
10154             }catch(e){}
10155         }else{
10156             // if hasn't been loaded, wait for load to remove it to prevent script error
10157             window[trans.cb] = function(){
10158                 window[trans.cb] = undefined;
10159                 try{
10160                     delete window[trans.cb];
10161                 }catch(e){}
10162             };
10163         }
10164     },
10165
10166     // private
10167     handleResponse : function(o, trans){
10168         this.trans = false;
10169         this.destroyTrans(trans, true);
10170         var result;
10171         try {
10172             result = trans.reader.readRecords(o);
10173         }catch(e){
10174             this.fireEvent("loadexception", this, o, trans.arg, e);
10175             trans.callback.call(trans.scope||window, null, trans.arg, false);
10176             return;
10177         }
10178         this.fireEvent("load", this, o, trans.arg);
10179         trans.callback.call(trans.scope||window, result, trans.arg, true);
10180     },
10181
10182     // private
10183     handleFailure : function(trans){
10184         this.trans = false;
10185         this.destroyTrans(trans, false);
10186         this.fireEvent("loadexception", this, null, trans.arg);
10187         trans.callback.call(trans.scope||window, null, trans.arg, false);
10188     }
10189 });/*
10190  * Based on:
10191  * Ext JS Library 1.1.1
10192  * Copyright(c) 2006-2007, Ext JS, LLC.
10193  *
10194  * Originally Released Under LGPL - original licence link has changed is not relivant.
10195  *
10196  * Fork - LGPL
10197  * <script type="text/javascript">
10198  */
10199
10200 /**
10201  * @class Roo.data.JsonReader
10202  * @extends Roo.data.DataReader
10203  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10204  * based on mappings in a provided Roo.data.Record constructor.
10205  * 
10206  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10207  * in the reply previously. 
10208  * 
10209  * <p>
10210  * Example code:
10211  * <pre><code>
10212 var RecordDef = Roo.data.Record.create([
10213     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10214     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10215 ]);
10216 var myReader = new Roo.data.JsonReader({
10217     totalProperty: "results",    // The property which contains the total dataset size (optional)
10218     root: "rows",                // The property which contains an Array of row objects
10219     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10220 }, RecordDef);
10221 </code></pre>
10222  * <p>
10223  * This would consume a JSON file like this:
10224  * <pre><code>
10225 { 'results': 2, 'rows': [
10226     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10227     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10228 }
10229 </code></pre>
10230  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10231  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10232  * paged from the remote server.
10233  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10234  * @cfg {String} root name of the property which contains the Array of row objects.
10235  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10236  * @constructor
10237  * Create a new JsonReader
10238  * @param {Object} meta Metadata configuration options
10239  * @param {Object} recordType Either an Array of field definition objects,
10240  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10241  */
10242 Roo.data.JsonReader = function(meta, recordType){
10243     
10244     meta = meta || {};
10245     // set some defaults:
10246     Roo.applyIf(meta, {
10247         totalProperty: 'total',
10248         successProperty : 'success',
10249         root : 'data',
10250         id : 'id'
10251     });
10252     
10253     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10254 };
10255 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10256     
10257     /**
10258      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10259      * Used by Store query builder to append _requestMeta to params.
10260      * 
10261      */
10262     metaFromRemote : false,
10263     /**
10264      * This method is only used by a DataProxy which has retrieved data from a remote server.
10265      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10266      * @return {Object} data A data block which is used by an Roo.data.Store object as
10267      * a cache of Roo.data.Records.
10268      */
10269     read : function(response){
10270         var json = response.responseText;
10271        
10272         var o = /* eval:var:o */ eval("("+json+")");
10273         if(!o) {
10274             throw {message: "JsonReader.read: Json object not found"};
10275         }
10276         
10277         if(o.metaData){
10278             
10279             delete this.ef;
10280             this.metaFromRemote = true;
10281             this.meta = o.metaData;
10282             this.recordType = Roo.data.Record.create(o.metaData.fields);
10283             this.onMetaChange(this.meta, this.recordType, o);
10284         }
10285         return this.readRecords(o);
10286     },
10287
10288     // private function a store will implement
10289     onMetaChange : function(meta, recordType, o){
10290
10291     },
10292
10293     /**
10294          * @ignore
10295          */
10296     simpleAccess: function(obj, subsc) {
10297         return obj[subsc];
10298     },
10299
10300         /**
10301          * @ignore
10302          */
10303     getJsonAccessor: function(){
10304         var re = /[\[\.]/;
10305         return function(expr) {
10306             try {
10307                 return(re.test(expr))
10308                     ? new Function("obj", "return obj." + expr)
10309                     : function(obj){
10310                         return obj[expr];
10311                     };
10312             } catch(e){}
10313             return Roo.emptyFn;
10314         };
10315     }(),
10316
10317     /**
10318      * Create a data block containing Roo.data.Records from an XML document.
10319      * @param {Object} o An object which contains an Array of row objects in the property specified
10320      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10321      * which contains the total size of the dataset.
10322      * @return {Object} data A data block which is used by an Roo.data.Store object as
10323      * a cache of Roo.data.Records.
10324      */
10325     readRecords : function(o){
10326         /**
10327          * After any data loads, the raw JSON data is available for further custom processing.
10328          * @type Object
10329          */
10330         this.o = o;
10331         var s = this.meta, Record = this.recordType,
10332             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10333
10334 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10335         if (!this.ef) {
10336             if(s.totalProperty) {
10337                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10338                 }
10339                 if(s.successProperty) {
10340                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10341                 }
10342                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10343                 if (s.id) {
10344                         var g = this.getJsonAccessor(s.id);
10345                         this.getId = function(rec) {
10346                                 var r = g(rec);  
10347                                 return (r === undefined || r === "") ? null : r;
10348                         };
10349                 } else {
10350                         this.getId = function(){return null;};
10351                 }
10352             this.ef = [];
10353             for(var jj = 0; jj < fl; jj++){
10354                 f = fi[jj];
10355                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10356                 this.ef[jj] = this.getJsonAccessor(map);
10357             }
10358         }
10359
10360         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10361         if(s.totalProperty){
10362             var vt = parseInt(this.getTotal(o), 10);
10363             if(!isNaN(vt)){
10364                 totalRecords = vt;
10365             }
10366         }
10367         if(s.successProperty){
10368             var vs = this.getSuccess(o);
10369             if(vs === false || vs === 'false'){
10370                 success = false;
10371             }
10372         }
10373         var records = [];
10374         for(var i = 0; i < c; i++){
10375                 var n = root[i];
10376             var values = {};
10377             var id = this.getId(n);
10378             for(var j = 0; j < fl; j++){
10379                 f = fi[j];
10380             var v = this.ef[j](n);
10381             if (!f.convert) {
10382                 Roo.log('missing convert for ' + f.name);
10383                 Roo.log(f);
10384                 continue;
10385             }
10386             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10387             }
10388             var record = new Record(values, id);
10389             record.json = n;
10390             records[i] = record;
10391         }
10392         return {
10393             raw : o,
10394             success : success,
10395             records : records,
10396             totalRecords : totalRecords
10397         };
10398     }
10399 });/*
10400  * Based on:
10401  * Ext JS Library 1.1.1
10402  * Copyright(c) 2006-2007, Ext JS, LLC.
10403  *
10404  * Originally Released Under LGPL - original licence link has changed is not relivant.
10405  *
10406  * Fork - LGPL
10407  * <script type="text/javascript">
10408  */
10409
10410 /**
10411  * @class Roo.data.ArrayReader
10412  * @extends Roo.data.DataReader
10413  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10414  * Each element of that Array represents a row of data fields. The
10415  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10416  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10417  * <p>
10418  * Example code:.
10419  * <pre><code>
10420 var RecordDef = Roo.data.Record.create([
10421     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10422     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10423 ]);
10424 var myReader = new Roo.data.ArrayReader({
10425     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10426 }, RecordDef);
10427 </code></pre>
10428  * <p>
10429  * This would consume an Array like this:
10430  * <pre><code>
10431 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10432   </code></pre>
10433  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10434  * @constructor
10435  * Create a new JsonReader
10436  * @param {Object} meta Metadata configuration options.
10437  * @param {Object} recordType Either an Array of field definition objects
10438  * as specified to {@link Roo.data.Record#create},
10439  * or an {@link Roo.data.Record} object
10440  * created using {@link Roo.data.Record#create}.
10441  */
10442 Roo.data.ArrayReader = function(meta, recordType){
10443     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10444 };
10445
10446 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10447     /**
10448      * Create a data block containing Roo.data.Records from an XML document.
10449      * @param {Object} o An Array of row objects which represents the dataset.
10450      * @return {Object} data A data block which is used by an Roo.data.Store object as
10451      * a cache of Roo.data.Records.
10452      */
10453     readRecords : function(o){
10454         var sid = this.meta ? this.meta.id : null;
10455         var recordType = this.recordType, fields = recordType.prototype.fields;
10456         var records = [];
10457         var root = o;
10458             for(var i = 0; i < root.length; i++){
10459                     var n = root[i];
10460                 var values = {};
10461                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10462                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10463                 var f = fields.items[j];
10464                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10465                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10466                 v = f.convert(v);
10467                 values[f.name] = v;
10468             }
10469                 var record = new recordType(values, id);
10470                 record.json = n;
10471                 records[records.length] = record;
10472             }
10473             return {
10474                 records : records,
10475                 totalRecords : records.length
10476             };
10477     }
10478 });/*
10479  * - LGPL
10480  * * 
10481  */
10482
10483 /**
10484  * @class Roo.bootstrap.ComboBox
10485  * @extends Roo.bootstrap.TriggerField
10486  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10487  * @cfg {Boolean} append (true|false) default false
10488  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10489  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10490  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10491  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10492  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10493  * @constructor
10494  * Create a new ComboBox.
10495  * @param {Object} config Configuration options
10496  */
10497 Roo.bootstrap.ComboBox = function(config){
10498     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10499     this.addEvents({
10500         /**
10501          * @event expand
10502          * Fires when the dropdown list is expanded
10503              * @param {Roo.bootstrap.ComboBox} combo This combo box
10504              */
10505         'expand' : true,
10506         /**
10507          * @event collapse
10508          * Fires when the dropdown list is collapsed
10509              * @param {Roo.bootstrap.ComboBox} combo This combo box
10510              */
10511         'collapse' : true,
10512         /**
10513          * @event beforeselect
10514          * Fires before a list item is selected. Return false to cancel the selection.
10515              * @param {Roo.bootstrap.ComboBox} combo This combo box
10516              * @param {Roo.data.Record} record The data record returned from the underlying store
10517              * @param {Number} index The index of the selected item in the dropdown list
10518              */
10519         'beforeselect' : true,
10520         /**
10521          * @event select
10522          * Fires when a list item is selected
10523              * @param {Roo.bootstrap.ComboBox} combo This combo box
10524              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10525              * @param {Number} index The index of the selected item in the dropdown list
10526              */
10527         'select' : true,
10528         /**
10529          * @event beforequery
10530          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10531          * The event object passed has these properties:
10532              * @param {Roo.bootstrap.ComboBox} combo This combo box
10533              * @param {String} query The query
10534              * @param {Boolean} forceAll true to force "all" query
10535              * @param {Boolean} cancel true to cancel the query
10536              * @param {Object} e The query event object
10537              */
10538         'beforequery': true,
10539          /**
10540          * @event add
10541          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10542              * @param {Roo.bootstrap.ComboBox} combo This combo box
10543              */
10544         'add' : true,
10545         /**
10546          * @event edit
10547          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10548              * @param {Roo.bootstrap.ComboBox} combo This combo box
10549              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10550              */
10551         'edit' : true,
10552         /**
10553          * @event remove
10554          * Fires when the remove value from the combobox array
10555              * @param {Roo.bootstrap.ComboBox} combo This combo box
10556              */
10557         'remove' : true
10558         
10559     });
10560     
10561     this.item = [];
10562     this.tickItems = [];
10563     
10564     this.selectedIndex = -1;
10565     if(this.mode == 'local'){
10566         if(config.queryDelay === undefined){
10567             this.queryDelay = 10;
10568         }
10569         if(config.minChars === undefined){
10570             this.minChars = 0;
10571         }
10572     }
10573 };
10574
10575 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10576      
10577     /**
10578      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10579      * rendering into an Roo.Editor, defaults to false)
10580      */
10581     /**
10582      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10583      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10584      */
10585     /**
10586      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10587      */
10588     /**
10589      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10590      * the dropdown list (defaults to undefined, with no header element)
10591      */
10592
10593      /**
10594      * @cfg {String/Roo.Template} tpl The template to use to render the output
10595      */
10596      
10597      /**
10598      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10599      */
10600     listWidth: undefined,
10601     /**
10602      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10603      * mode = 'remote' or 'text' if mode = 'local')
10604      */
10605     displayField: undefined,
10606     /**
10607      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10608      * mode = 'remote' or 'value' if mode = 'local'). 
10609      * Note: use of a valueField requires the user make a selection
10610      * in order for a value to be mapped.
10611      */
10612     valueField: undefined,
10613     
10614     
10615     /**
10616      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10617      * field's data value (defaults to the underlying DOM element's name)
10618      */
10619     hiddenName: undefined,
10620     /**
10621      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10622      */
10623     listClass: '',
10624     /**
10625      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10626      */
10627     selectedClass: 'active',
10628     
10629     /**
10630      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10631      */
10632     shadow:'sides',
10633     /**
10634      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10635      * anchor positions (defaults to 'tl-bl')
10636      */
10637     listAlign: 'tl-bl?',
10638     /**
10639      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10640      */
10641     maxHeight: 300,
10642     /**
10643      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10644      * query specified by the allQuery config option (defaults to 'query')
10645      */
10646     triggerAction: 'query',
10647     /**
10648      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10649      * (defaults to 4, does not apply if editable = false)
10650      */
10651     minChars : 4,
10652     /**
10653      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10654      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10655      */
10656     typeAhead: false,
10657     /**
10658      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10659      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10660      */
10661     queryDelay: 500,
10662     /**
10663      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10664      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10665      */
10666     pageSize: 0,
10667     /**
10668      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10669      * when editable = true (defaults to false)
10670      */
10671     selectOnFocus:false,
10672     /**
10673      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10674      */
10675     queryParam: 'query',
10676     /**
10677      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10678      * when mode = 'remote' (defaults to 'Loading...')
10679      */
10680     loadingText: 'Loading...',
10681     /**
10682      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10683      */
10684     resizable: false,
10685     /**
10686      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10687      */
10688     handleHeight : 8,
10689     /**
10690      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10691      * traditional select (defaults to true)
10692      */
10693     editable: true,
10694     /**
10695      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10696      */
10697     allQuery: '',
10698     /**
10699      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10700      */
10701     mode: 'remote',
10702     /**
10703      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10704      * listWidth has a higher value)
10705      */
10706     minListWidth : 70,
10707     /**
10708      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10709      * allow the user to set arbitrary text into the field (defaults to false)
10710      */
10711     forceSelection:false,
10712     /**
10713      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10714      * if typeAhead = true (defaults to 250)
10715      */
10716     typeAheadDelay : 250,
10717     /**
10718      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10719      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10720      */
10721     valueNotFoundText : undefined,
10722     /**
10723      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10724      */
10725     blockFocus : false,
10726     
10727     /**
10728      * @cfg {Boolean} disableClear Disable showing of clear button.
10729      */
10730     disableClear : false,
10731     /**
10732      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10733      */
10734     alwaysQuery : false,
10735     
10736     /**
10737      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10738      */
10739     multiple : false,
10740     
10741     //private
10742     addicon : false,
10743     editicon: false,
10744     
10745     page: 0,
10746     hasQuery: false,
10747     append: false,
10748     loadNext: false,
10749     autoFocus : true,
10750     tickable : false,
10751     btnPosition : 'right',
10752     triggerList : true,
10753     showToggleBtn : true,
10754     // element that contains real text value.. (when hidden is used..)
10755     
10756     getAutoCreate : function()
10757     {
10758         var cfg = false;
10759         
10760         /*
10761          *  Normal ComboBox
10762          */
10763         if(!this.tickable){
10764             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10765             return cfg;
10766         }
10767         
10768         /*
10769          *  ComboBox with tickable selections
10770          */
10771              
10772         var align = this.labelAlign || this.parentLabelAlign();
10773         
10774         cfg = {
10775             cls : 'form-group roo-combobox-tickable' //input-group
10776         };
10777         
10778         
10779         var buttons = {
10780             tag : 'div',
10781             cls : 'tickable-buttons',
10782             cn : [
10783                 {
10784                     tag : 'button',
10785                     type : 'button',
10786                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10787                     html : 'Edit'
10788                 },
10789                 {
10790                     tag : 'button',
10791                     type : 'button',
10792                     name : 'ok',
10793                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10794                     html : 'Done'
10795                 },
10796                 {
10797                     tag : 'button',
10798                     type : 'button',
10799                     name : 'cancel',
10800                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
10801                     html : 'Cancel'
10802                 }
10803             ]
10804         };
10805         
10806         var _this = this;
10807         Roo.each(buttons.cn, function(c){
10808             if (_this.size) {
10809                 c.cls += ' btn-' + _this.size;
10810             }
10811
10812             if (_this.disabled) {
10813                 c.disabled = true;
10814             }
10815         });
10816         
10817         var box = {
10818             tag: 'div',
10819             cn: [
10820                 {
10821                     tag: 'input',
10822                     type : 'hidden',
10823                     cls: 'form-hidden-field'
10824                 },
10825                 {
10826                     tag: 'ul',
10827                     cls: 'select2-choices',
10828                     cn:[
10829                         {
10830                             tag: 'li',
10831                             cls: 'select2-search-field',
10832                             cn: [
10833
10834                                 buttons
10835                             ]
10836                         }
10837                     ]
10838                 }
10839             ]
10840         }
10841         
10842         var combobox = {
10843             cls: 'select2-container input-group select2-container-multi',
10844             cn: [
10845                 box
10846 //                {
10847 //                    tag: 'ul',
10848 //                    cls: 'typeahead typeahead-long dropdown-menu',
10849 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
10850 //                }
10851             ]
10852         };
10853         
10854         if (align ==='left' && this.fieldLabel.length) {
10855             
10856                 Roo.log("left and has label");
10857                 cfg.cn = [
10858                     
10859                     {
10860                         tag: 'label',
10861                         'for' :  id,
10862                         cls : 'control-label col-sm-' + this.labelWidth,
10863                         html : this.fieldLabel
10864                         
10865                     },
10866                     {
10867                         cls : "col-sm-" + (12 - this.labelWidth), 
10868                         cn: [
10869                             combobox
10870                         ]
10871                     }
10872                     
10873                 ];
10874         } else if ( this.fieldLabel.length) {
10875                 Roo.log(" label");
10876                  cfg.cn = [
10877                    
10878                     {
10879                         tag: 'label',
10880                         //cls : 'input-group-addon',
10881                         html : this.fieldLabel
10882                         
10883                     },
10884                     
10885                     combobox
10886                     
10887                 ];
10888
10889         } else {
10890             
10891                 Roo.log(" no label && no align");
10892                 cfg = combobox
10893                      
10894                 
10895         }
10896          
10897         var settings=this;
10898         ['xs','sm','md','lg'].map(function(size){
10899             if (settings[size]) {
10900                 cfg.cls += ' col-' + size + '-' + settings[size];
10901             }
10902         });
10903         
10904         return cfg;
10905         
10906     },
10907     
10908     // private
10909     initEvents: function()
10910     {
10911         
10912         if (!this.store) {
10913             throw "can not find store for combo";
10914         }
10915         this.store = Roo.factory(this.store, Roo.data);
10916         
10917         if(this.tickable){
10918             this.initTickableEvents();
10919             return;
10920         }
10921         
10922         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
10923         
10924         if(this.hiddenName){
10925             
10926             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10927             
10928             this.hiddenField.dom.value =
10929                 this.hiddenValue !== undefined ? this.hiddenValue :
10930                 this.value !== undefined ? this.value : '';
10931
10932             // prevent input submission
10933             this.el.dom.removeAttribute('name');
10934             this.hiddenField.dom.setAttribute('name', this.hiddenName);
10935              
10936              
10937         }
10938         //if(Roo.isGecko){
10939         //    this.el.dom.setAttribute('autocomplete', 'off');
10940         //}
10941         
10942         var cls = 'x-combo-list';
10943         
10944         //this.list = new Roo.Layer({
10945         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10946         //});
10947         
10948         var _this = this;
10949         
10950         (function(){
10951             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
10952             _this.list.setWidth(lw);
10953         }).defer(100);
10954         
10955         this.list.on('mouseover', this.onViewOver, this);
10956         this.list.on('mousemove', this.onViewMove, this);
10957         
10958         this.list.on('scroll', this.onViewScroll, this);
10959         
10960         /*
10961         this.list.swallowEvent('mousewheel');
10962         this.assetHeight = 0;
10963
10964         if(this.title){
10965             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10966             this.assetHeight += this.header.getHeight();
10967         }
10968
10969         this.innerList = this.list.createChild({cls:cls+'-inner'});
10970         this.innerList.on('mouseover', this.onViewOver, this);
10971         this.innerList.on('mousemove', this.onViewMove, this);
10972         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10973         
10974         if(this.allowBlank && !this.pageSize && !this.disableClear){
10975             this.footer = this.list.createChild({cls:cls+'-ft'});
10976             this.pageTb = new Roo.Toolbar(this.footer);
10977            
10978         }
10979         if(this.pageSize){
10980             this.footer = this.list.createChild({cls:cls+'-ft'});
10981             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10982                     {pageSize: this.pageSize});
10983             
10984         }
10985         
10986         if (this.pageTb && this.allowBlank && !this.disableClear) {
10987             var _this = this;
10988             this.pageTb.add(new Roo.Toolbar.Fill(), {
10989                 cls: 'x-btn-icon x-btn-clear',
10990                 text: '&#160;',
10991                 handler: function()
10992                 {
10993                     _this.collapse();
10994                     _this.clearValue();
10995                     _this.onSelect(false, -1);
10996                 }
10997             });
10998         }
10999         if (this.footer) {
11000             this.assetHeight += this.footer.getHeight();
11001         }
11002         */
11003             
11004         if(!this.tpl){
11005             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11006         }
11007
11008         this.view = new Roo.View(this.list, this.tpl, {
11009             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11010         });
11011         //this.view.wrapEl.setDisplayed(false);
11012         this.view.on('click', this.onViewClick, this);
11013         
11014         
11015         
11016         this.store.on('beforeload', this.onBeforeLoad, this);
11017         this.store.on('load', this.onLoad, this);
11018         this.store.on('loadexception', this.onLoadException, this);
11019         /*
11020         if(this.resizable){
11021             this.resizer = new Roo.Resizable(this.list,  {
11022                pinned:true, handles:'se'
11023             });
11024             this.resizer.on('resize', function(r, w, h){
11025                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11026                 this.listWidth = w;
11027                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11028                 this.restrictHeight();
11029             }, this);
11030             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11031         }
11032         */
11033         if(!this.editable){
11034             this.editable = true;
11035             this.setEditable(false);
11036         }
11037         
11038         /*
11039         
11040         if (typeof(this.events.add.listeners) != 'undefined') {
11041             
11042             this.addicon = this.wrap.createChild(
11043                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11044        
11045             this.addicon.on('click', function(e) {
11046                 this.fireEvent('add', this);
11047             }, this);
11048         }
11049         if (typeof(this.events.edit.listeners) != 'undefined') {
11050             
11051             this.editicon = this.wrap.createChild(
11052                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11053             if (this.addicon) {
11054                 this.editicon.setStyle('margin-left', '40px');
11055             }
11056             this.editicon.on('click', function(e) {
11057                 
11058                 // we fire even  if inothing is selected..
11059                 this.fireEvent('edit', this, this.lastData );
11060                 
11061             }, this);
11062         }
11063         */
11064         
11065         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11066             "up" : function(e){
11067                 this.inKeyMode = true;
11068                 this.selectPrev();
11069             },
11070
11071             "down" : function(e){
11072                 if(!this.isExpanded()){
11073                     this.onTriggerClick();
11074                 }else{
11075                     this.inKeyMode = true;
11076                     this.selectNext();
11077                 }
11078             },
11079
11080             "enter" : function(e){
11081 //                this.onViewClick();
11082                 //return true;
11083                 this.collapse();
11084                 
11085                 if(this.fireEvent("specialkey", this, e)){
11086                     this.onViewClick(false);
11087                 }
11088                 
11089                 return true;
11090             },
11091
11092             "esc" : function(e){
11093                 this.collapse();
11094             },
11095
11096             "tab" : function(e){
11097                 this.collapse();
11098                 
11099                 if(this.fireEvent("specialkey", this, e)){
11100                     this.onViewClick(false);
11101                 }
11102                 
11103                 return true;
11104             },
11105
11106             scope : this,
11107
11108             doRelay : function(foo, bar, hname){
11109                 if(hname == 'down' || this.scope.isExpanded()){
11110                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11111                 }
11112                 return true;
11113             },
11114
11115             forceKeyDown: true
11116         });
11117         
11118         
11119         this.queryDelay = Math.max(this.queryDelay || 10,
11120                 this.mode == 'local' ? 10 : 250);
11121         
11122         
11123         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11124         
11125         if(this.typeAhead){
11126             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11127         }
11128         if(this.editable !== false){
11129             this.inputEl().on("keyup", this.onKeyUp, this);
11130         }
11131         if(this.forceSelection){
11132             this.inputEl().on('blur', this.doForce, this);
11133         }
11134         
11135         if(this.multiple){
11136             this.choices = this.el.select('ul.select2-choices', true).first();
11137             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11138         }
11139     },
11140     
11141     initTickableEvents: function()
11142     {   
11143         this.createList();
11144         
11145         if(this.hiddenName){
11146             
11147             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11148             
11149             this.hiddenField.dom.value =
11150                 this.hiddenValue !== undefined ? this.hiddenValue :
11151                 this.value !== undefined ? this.value : '';
11152
11153             // prevent input submission
11154             this.el.dom.removeAttribute('name');
11155             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11156              
11157              
11158         }
11159         
11160 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11161         
11162         this.choices = this.el.select('ul.select2-choices', true).first();
11163         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11164         if(this.triggerList){
11165             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11166         }
11167          
11168         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11169         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11170         
11171         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11172         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11173         
11174         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11175         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11176         
11177         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11178         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11179         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11180         
11181         this.okBtn.hide();
11182         this.cancelBtn.hide();
11183         
11184         var _this = this;
11185         
11186         (function(){
11187             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11188             _this.list.setWidth(lw);
11189         }).defer(100);
11190         
11191         this.list.on('mouseover', this.onViewOver, this);
11192         this.list.on('mousemove', this.onViewMove, this);
11193         
11194         this.list.on('scroll', this.onViewScroll, this);
11195         
11196         if(!this.tpl){
11197             this.tpl = '<li class="select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></li>';
11198         }
11199
11200         this.view = new Roo.View(this.list, this.tpl, {
11201             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11202         });
11203         
11204         //this.view.wrapEl.setDisplayed(false);
11205         this.view.on('click', this.onViewClick, this);
11206         
11207         
11208         
11209         this.store.on('beforeload', this.onBeforeLoad, this);
11210         this.store.on('load', this.onLoad, this);
11211         this.store.on('loadexception', this.onLoadException, this);
11212         
11213 //        this.keyNav = new Roo.KeyNav(this.inputEl(), {
11214 //            "up" : function(e){
11215 //                this.inKeyMode = true;
11216 //                this.selectPrev();
11217 //            },
11218 //
11219 //            "down" : function(e){
11220 //                if(!this.isExpanded()){
11221 //                    this.onTriggerClick();
11222 //                }else{
11223 //                    this.inKeyMode = true;
11224 //                    this.selectNext();
11225 //                }
11226 //            },
11227 //
11228 //            "enter" : function(e){
11229 ////                this.onViewClick();
11230 //                //return true;
11231 //                this.collapse();
11232 //                
11233 //                if(this.fireEvent("specialkey", this, e)){
11234 //                    this.onViewClick(false);
11235 //                }
11236 //                
11237 //                return true;
11238 //            },
11239 //
11240 //            "esc" : function(e){
11241 //                this.collapse();
11242 //            },
11243 //
11244 //            "tab" : function(e){
11245 //                this.collapse();
11246 //                
11247 //                if(this.fireEvent("specialkey", this, e)){
11248 //                    this.onViewClick(false);
11249 //                }
11250 //                
11251 //                return true;
11252 //            },
11253 //
11254 //            scope : this,
11255 //
11256 //            doRelay : function(foo, bar, hname){
11257 //                if(hname == 'down' || this.scope.isExpanded()){
11258 //                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11259 //                }
11260 //                return true;
11261 //            },
11262 //
11263 //            forceKeyDown: true
11264 //        });
11265         
11266         
11267         this.queryDelay = Math.max(this.queryDelay || 10,
11268                 this.mode == 'local' ? 10 : 250);
11269         
11270         
11271         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11272         
11273         if(this.typeAhead){
11274             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11275         }
11276         
11277     },
11278
11279     onDestroy : function(){
11280         if(this.view){
11281             this.view.setStore(null);
11282             this.view.el.removeAllListeners();
11283             this.view.el.remove();
11284             this.view.purgeListeners();
11285         }
11286         if(this.list){
11287             this.list.dom.innerHTML  = '';
11288         }
11289         
11290         if(this.store){
11291             this.store.un('beforeload', this.onBeforeLoad, this);
11292             this.store.un('load', this.onLoad, this);
11293             this.store.un('loadexception', this.onLoadException, this);
11294         }
11295         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11296     },
11297
11298     // private
11299     fireKey : function(e){
11300         if(e.isNavKeyPress() && !this.list.isVisible()){
11301             this.fireEvent("specialkey", this, e);
11302         }
11303     },
11304
11305     // private
11306     onResize: function(w, h){
11307 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11308 //        
11309 //        if(typeof w != 'number'){
11310 //            // we do not handle it!?!?
11311 //            return;
11312 //        }
11313 //        var tw = this.trigger.getWidth();
11314 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11315 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11316 //        var x = w - tw;
11317 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11318 //            
11319 //        //this.trigger.setStyle('left', x+'px');
11320 //        
11321 //        if(this.list && this.listWidth === undefined){
11322 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11323 //            this.list.setWidth(lw);
11324 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11325 //        }
11326         
11327     
11328         
11329     },
11330
11331     /**
11332      * Allow or prevent the user from directly editing the field text.  If false is passed,
11333      * the user will only be able to select from the items defined in the dropdown list.  This method
11334      * is the runtime equivalent of setting the 'editable' config option at config time.
11335      * @param {Boolean} value True to allow the user to directly edit the field text
11336      */
11337     setEditable : function(value){
11338         if(value == this.editable){
11339             return;
11340         }
11341         this.editable = value;
11342         if(!value){
11343             this.inputEl().dom.setAttribute('readOnly', true);
11344             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11345             this.inputEl().addClass('x-combo-noedit');
11346         }else{
11347             this.inputEl().dom.setAttribute('readOnly', false);
11348             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11349             this.inputEl().removeClass('x-combo-noedit');
11350         }
11351     },
11352
11353     // private
11354     
11355     onBeforeLoad : function(combo,opts){
11356         if(!this.hasFocus){
11357             return;
11358         }
11359          if (!opts.add) {
11360             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11361          }
11362         this.restrictHeight();
11363         this.selectedIndex = -1;
11364     },
11365
11366     // private
11367     onLoad : function(){
11368         
11369         this.hasQuery = false;
11370         
11371         if(!this.hasFocus){
11372             return;
11373         }
11374         
11375         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11376             this.loading.hide();
11377         }
11378         
11379         if(this.store.getCount() > 0){
11380             this.expand();
11381 //            this.restrictHeight();
11382             if(this.lastQuery == this.allQuery){
11383                 if(this.editable && !this.tickable){
11384                     this.inputEl().dom.select();
11385                 }
11386                 
11387                 if(
11388                     !this.selectByValue(this.value, true) &&
11389                     this.autoFocus && (typeof(this.store.lastOptions.add) == 'undefined' || 
11390                     this.store.lastOptions.add != true)
11391                 ){
11392                     this.select(0, true);
11393                 }
11394             }else{
11395                 if(this.autoFocus){
11396                     this.selectNext();
11397                 }
11398                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11399                     this.taTask.delay(this.typeAheadDelay);
11400                 }
11401             }
11402         }else{
11403             this.onEmptyResults();
11404         }
11405         
11406         //this.el.focus();
11407     },
11408     // private
11409     onLoadException : function()
11410     {
11411         this.hasQuery = false;
11412         
11413         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11414             this.loading.hide();
11415         }
11416         
11417         this.collapse();
11418         Roo.log(this.store.reader.jsonData);
11419         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11420             // fixme
11421             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11422         }
11423         
11424         
11425     },
11426     // private
11427     onTypeAhead : function(){
11428         if(this.store.getCount() > 0){
11429             var r = this.store.getAt(0);
11430             var newValue = r.data[this.displayField];
11431             var len = newValue.length;
11432             var selStart = this.getRawValue().length;
11433             
11434             if(selStart != len){
11435                 this.setRawValue(newValue);
11436                 this.selectText(selStart, newValue.length);
11437             }
11438         }
11439     },
11440
11441     // private
11442     onSelect : function(record, index){
11443         
11444         if(this.fireEvent('beforeselect', this, record, index) !== false){
11445         
11446             this.setFromData(index > -1 ? record.data : false);
11447             
11448             this.collapse();
11449             this.fireEvent('select', this, record, index);
11450         }
11451     },
11452
11453     /**
11454      * Returns the currently selected field value or empty string if no value is set.
11455      * @return {String} value The selected value
11456      */
11457     getValue : function(){
11458         
11459         if(this.multiple){
11460             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11461         }
11462         
11463         if(this.valueField){
11464             return typeof this.value != 'undefined' ? this.value : '';
11465         }else{
11466             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11467         }
11468     },
11469
11470     /**
11471      * Clears any text/value currently set in the field
11472      */
11473     clearValue : function(){
11474         if(this.hiddenField){
11475             this.hiddenField.dom.value = '';
11476         }
11477         this.value = '';
11478         this.setRawValue('');
11479         this.lastSelectionText = '';
11480         
11481     },
11482
11483     /**
11484      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11485      * will be displayed in the field.  If the value does not match the data value of an existing item,
11486      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11487      * Otherwise the field will be blank (although the value will still be set).
11488      * @param {String} value The value to match
11489      */
11490     setValue : function(v){
11491         if(this.multiple){
11492             this.syncValue();
11493             return;
11494         }
11495         
11496         var text = v;
11497         if(this.valueField){
11498             var r = this.findRecord(this.valueField, v);
11499             if(r){
11500                 text = r.data[this.displayField];
11501             }else if(this.valueNotFoundText !== undefined){
11502                 text = this.valueNotFoundText;
11503             }
11504         }
11505         this.lastSelectionText = text;
11506         if(this.hiddenField){
11507             this.hiddenField.dom.value = v;
11508         }
11509         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11510         this.value = v;
11511     },
11512     /**
11513      * @property {Object} the last set data for the element
11514      */
11515     
11516     lastData : false,
11517     /**
11518      * Sets the value of the field based on a object which is related to the record format for the store.
11519      * @param {Object} value the value to set as. or false on reset?
11520      */
11521     setFromData : function(o){
11522         
11523         if(this.multiple){
11524             this.addItem(o);
11525             return;
11526         }
11527             
11528         var dv = ''; // display value
11529         var vv = ''; // value value..
11530         this.lastData = o;
11531         if (this.displayField) {
11532             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11533         } else {
11534             // this is an error condition!!!
11535             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11536         }
11537         
11538         if(this.valueField){
11539             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11540         }
11541         
11542         if(this.hiddenField){
11543             this.hiddenField.dom.value = vv;
11544             
11545             this.lastSelectionText = dv;
11546             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11547             this.value = vv;
11548             return;
11549         }
11550         // no hidden field.. - we store the value in 'value', but still display
11551         // display field!!!!
11552         this.lastSelectionText = dv;
11553         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11554         this.value = vv;
11555         
11556         
11557     },
11558     // private
11559     reset : function(){
11560         // overridden so that last data is reset..
11561         this.setValue(this.originalValue);
11562         this.clearInvalid();
11563         this.lastData = false;
11564         if (this.view) {
11565             this.view.clearSelections();
11566         }
11567     },
11568     // private
11569     findRecord : function(prop, value){
11570         var record;
11571         if(this.store.getCount() > 0){
11572             this.store.each(function(r){
11573                 if(r.data[prop] == value){
11574                     record = r;
11575                     return false;
11576                 }
11577                 return true;
11578             });
11579         }
11580         return record;
11581     },
11582     
11583     getName: function()
11584     {
11585         // returns hidden if it's set..
11586         if (!this.rendered) {return ''};
11587         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11588         
11589     },
11590     // private
11591     onViewMove : function(e, t){
11592         this.inKeyMode = false;
11593     },
11594
11595     // private
11596     onViewOver : function(e, t){
11597         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11598             return;
11599         }
11600         var item = this.view.findItemFromChild(t);
11601         
11602         if(item){
11603             var index = this.view.indexOf(item);
11604             this.select(index, false);
11605         }
11606     },
11607
11608     // private
11609     onViewClick : function(view, doFocus, el, e)
11610     {
11611         var index = this.view.getSelectedIndexes()[0];
11612         
11613         var r = this.store.getAt(index);
11614         
11615         if(this.tickable){
11616             
11617             if(e.getTarget().nodeName.toLowerCase() != 'input'){
11618                 return;
11619             }
11620             
11621             var rm = false;
11622             var _this = this;
11623             
11624             Roo.each(this.tickItems, function(v,k){
11625                 
11626                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11627                     _this.tickItems.splice(k, 1);
11628                     rm = true;
11629                     return;
11630                 }
11631             });
11632             
11633             if(rm){
11634                 return;
11635             }
11636             
11637             this.tickItems.push(r.data);
11638             return;
11639         }
11640         
11641         if(r){
11642             this.onSelect(r, index);
11643         }
11644         if(doFocus !== false && !this.blockFocus){
11645             this.inputEl().focus();
11646         }
11647     },
11648
11649     // private
11650     restrictHeight : function(){
11651         //this.innerList.dom.style.height = '';
11652         //var inner = this.innerList.dom;
11653         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11654         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11655         //this.list.beginUpdate();
11656         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11657         this.list.alignTo(this.inputEl(), this.listAlign);
11658         this.list.alignTo(this.inputEl(), this.listAlign);
11659         //this.list.endUpdate();
11660     },
11661
11662     // private
11663     onEmptyResults : function(){
11664         this.collapse();
11665     },
11666
11667     /**
11668      * Returns true if the dropdown list is expanded, else false.
11669      */
11670     isExpanded : function(){
11671         return this.list.isVisible();
11672     },
11673
11674     /**
11675      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11676      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11677      * @param {String} value The data value of the item to select
11678      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11679      * selected item if it is not currently in view (defaults to true)
11680      * @return {Boolean} True if the value matched an item in the list, else false
11681      */
11682     selectByValue : function(v, scrollIntoView){
11683         if(v !== undefined && v !== null){
11684             var r = this.findRecord(this.valueField || this.displayField, v);
11685             if(r){
11686                 this.select(this.store.indexOf(r), scrollIntoView);
11687                 return true;
11688             }
11689         }
11690         return false;
11691     },
11692
11693     /**
11694      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11695      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11696      * @param {Number} index The zero-based index of the list item to select
11697      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11698      * selected item if it is not currently in view (defaults to true)
11699      */
11700     select : function(index, scrollIntoView){
11701         this.selectedIndex = index;
11702         this.view.select(index);
11703         if(scrollIntoView !== false){
11704             var el = this.view.getNode(index);
11705             if(el && !this.multiple && !this.tickable){
11706                 this.list.scrollChildIntoView(el, false);
11707             }
11708         }
11709     },
11710
11711     // private
11712     selectNext : function(){
11713         var ct = this.store.getCount();
11714         if(ct > 0){
11715             if(this.selectedIndex == -1){
11716                 this.select(0);
11717             }else if(this.selectedIndex < ct-1){
11718                 this.select(this.selectedIndex+1);
11719             }
11720         }
11721     },
11722
11723     // private
11724     selectPrev : function(){
11725         var ct = this.store.getCount();
11726         if(ct > 0){
11727             if(this.selectedIndex == -1){
11728                 this.select(0);
11729             }else if(this.selectedIndex != 0){
11730                 this.select(this.selectedIndex-1);
11731             }
11732         }
11733     },
11734
11735     // private
11736     onKeyUp : function(e){
11737         if(this.editable !== false && !e.isSpecialKey()){
11738             this.lastKey = e.getKey();
11739             this.dqTask.delay(this.queryDelay);
11740         }
11741     },
11742
11743     // private
11744     validateBlur : function(){
11745         return !this.list || !this.list.isVisible();   
11746     },
11747
11748     // private
11749     initQuery : function(){
11750         this.doQuery(this.getRawValue());
11751     },
11752
11753     // private
11754     doForce : function(){
11755         if(this.inputEl().dom.value.length > 0){
11756             this.inputEl().dom.value =
11757                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
11758              
11759         }
11760     },
11761
11762     /**
11763      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
11764      * query allowing the query action to be canceled if needed.
11765      * @param {String} query The SQL query to execute
11766      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
11767      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
11768      * saved in the current store (defaults to false)
11769      */
11770     doQuery : function(q, forceAll){
11771         
11772         if(q === undefined || q === null){
11773             q = '';
11774         }
11775         var qe = {
11776             query: q,
11777             forceAll: forceAll,
11778             combo: this,
11779             cancel:false
11780         };
11781         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
11782             return false;
11783         }
11784         q = qe.query;
11785         
11786         forceAll = qe.forceAll;
11787         if(forceAll === true || (q.length >= this.minChars)){
11788             
11789             this.hasQuery = true;
11790             
11791             if(this.lastQuery != q || this.alwaysQuery){
11792                 this.lastQuery = q;
11793                 if(this.mode == 'local'){
11794                     this.selectedIndex = -1;
11795                     if(forceAll){
11796                         this.store.clearFilter();
11797                     }else{
11798                         this.store.filter(this.displayField, q);
11799                     }
11800                     this.onLoad();
11801                 }else{
11802                     this.store.baseParams[this.queryParam] = q;
11803                     
11804                     var options = {params : this.getParams(q)};
11805                     
11806                     if(this.loadNext){
11807                         options.add = true;
11808                         options.params.start = this.page * this.pageSize;
11809                     }
11810                     
11811                     this.store.load(options);
11812                     /*
11813                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
11814                      *  we should expand the list on onLoad
11815                      *  so command out it
11816                      */
11817 //                    this.expand();
11818                 }
11819             }else{
11820                 this.selectedIndex = -1;
11821                 this.onLoad();   
11822             }
11823         }
11824         
11825         this.loadNext = false;
11826     },
11827
11828     // private
11829     getParams : function(q){
11830         var p = {};
11831         //p[this.queryParam] = q;
11832         
11833         if(this.pageSize){
11834             p.start = 0;
11835             p.limit = this.pageSize;
11836         }
11837         return p;
11838     },
11839
11840     /**
11841      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
11842      */
11843     collapse : function(){
11844         if(!this.isExpanded()){
11845             return;
11846         }
11847         
11848         this.list.hide();
11849         
11850         if(this.tickable){
11851             this.hasFocus = false;
11852             this.okBtn.hide();
11853             this.cancelBtn.hide();
11854             this.trigger.show();
11855         }
11856         
11857         Roo.get(document).un('mousedown', this.collapseIf, this);
11858         Roo.get(document).un('mousewheel', this.collapseIf, this);
11859         if (!this.editable) {
11860             Roo.get(document).un('keydown', this.listKeyPress, this);
11861         }
11862         this.fireEvent('collapse', this);
11863     },
11864
11865     // private
11866     collapseIf : function(e){
11867         var in_combo  = e.within(this.el);
11868         var in_list =  e.within(this.list);
11869         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
11870         
11871         if (in_combo || in_list || is_list) {
11872             //e.stopPropagation();
11873             return;
11874         }
11875         
11876         if(this.tickable){
11877             this.onTickableFooterButtonClick(e, false, false);
11878         }
11879
11880         this.collapse();
11881         
11882     },
11883
11884     /**
11885      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
11886      */
11887     expand : function(){
11888        
11889         if(this.isExpanded() || !this.hasFocus){
11890             return;
11891         }
11892         
11893         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
11894         this.list.setWidth(lw);
11895         
11896         
11897          Roo.log('expand');
11898         
11899         this.list.show();
11900         
11901         this.restrictHeight();
11902         
11903         if(this.tickable){
11904             
11905             this.tickItems = Roo.apply([], this.item);
11906             
11907             this.okBtn.show();
11908             this.cancelBtn.show();
11909             this.trigger.hide();
11910             
11911         }
11912         
11913         Roo.get(document).on('mousedown', this.collapseIf, this);
11914         Roo.get(document).on('mousewheel', this.collapseIf, this);
11915         if (!this.editable) {
11916             Roo.get(document).on('keydown', this.listKeyPress, this);
11917         }
11918         
11919         this.fireEvent('expand', this);
11920     },
11921
11922     // private
11923     // Implements the default empty TriggerField.onTriggerClick function
11924     onTriggerClick : function(e)
11925     {
11926         Roo.log('trigger click');
11927         
11928         if(this.disabled || !this.triggerList){
11929             return;
11930         }
11931         
11932         this.page = 0;
11933         this.loadNext = false;
11934         
11935         if(this.isExpanded()){
11936             this.collapse();
11937             if (!this.blockFocus) {
11938                 this.inputEl().focus();
11939             }
11940             
11941         }else {
11942             this.hasFocus = true;
11943             if(this.triggerAction == 'all') {
11944                 this.doQuery(this.allQuery, true);
11945             } else {
11946                 this.doQuery(this.getRawValue());
11947             }
11948             if (!this.blockFocus) {
11949                 this.inputEl().focus();
11950             }
11951         }
11952     },
11953     
11954     onTickableTriggerClick : function(e)
11955     {
11956         if(this.disabled){
11957             return;
11958         }
11959         
11960         this.page = 0;
11961         this.loadNext = false;
11962         this.hasFocus = true;
11963         
11964         if(this.triggerAction == 'all') {
11965             this.doQuery(this.allQuery, true);
11966         } else {
11967             this.doQuery(this.getRawValue());
11968         }
11969     },
11970     
11971     onSearchFieldClick : function(e)
11972     {
11973         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
11974             this.onTickableFooterButtonClick(e, false, false);
11975             return;
11976         }
11977         
11978         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
11979             return;
11980         }
11981         
11982         this.page = 0;
11983         this.loadNext = false;
11984         this.hasFocus = true;
11985         
11986         if(this.triggerAction == 'all') {
11987             this.doQuery(this.allQuery, true);
11988         } else {
11989             this.doQuery(this.getRawValue());
11990         }
11991     },
11992     
11993     listKeyPress : function(e)
11994     {
11995         //Roo.log('listkeypress');
11996         // scroll to first matching element based on key pres..
11997         if (e.isSpecialKey()) {
11998             return false;
11999         }
12000         var k = String.fromCharCode(e.getKey()).toUpperCase();
12001         //Roo.log(k);
12002         var match  = false;
12003         var csel = this.view.getSelectedNodes();
12004         var cselitem = false;
12005         if (csel.length) {
12006             var ix = this.view.indexOf(csel[0]);
12007             cselitem  = this.store.getAt(ix);
12008             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12009                 cselitem = false;
12010             }
12011             
12012         }
12013         
12014         this.store.each(function(v) { 
12015             if (cselitem) {
12016                 // start at existing selection.
12017                 if (cselitem.id == v.id) {
12018                     cselitem = false;
12019                 }
12020                 return true;
12021             }
12022                 
12023             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12024                 match = this.store.indexOf(v);
12025                 return false;
12026             }
12027             return true;
12028         }, this);
12029         
12030         if (match === false) {
12031             return true; // no more action?
12032         }
12033         // scroll to?
12034         this.view.select(match);
12035         var sn = Roo.get(this.view.getSelectedNodes()[0])
12036         sn.scrollIntoView(sn.dom.parentNode, false);
12037     },
12038     
12039     onViewScroll : function(e, t){
12040         
12041         if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
12042             return;
12043         }
12044         
12045         this.hasQuery = true;
12046         
12047         this.loading = this.list.select('.loading', true).first();
12048         
12049         if(this.loading === null){
12050             this.list.createChild({
12051                 tag: 'div',
12052                 cls: 'loading select2-more-results select2-active',
12053                 html: 'Loading more results...'
12054             })
12055             
12056             this.loading = this.list.select('.loading', true).first();
12057             
12058             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12059             
12060             this.loading.hide();
12061         }
12062         
12063         this.loading.show();
12064         
12065         var _combo = this;
12066         
12067         this.page++;
12068         this.loadNext = true;
12069         
12070         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12071         
12072         return;
12073     },
12074     
12075     addItem : function(o)
12076     {   
12077         var dv = ''; // display value
12078         
12079         if (this.displayField) {
12080             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12081         } else {
12082             // this is an error condition!!!
12083             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12084         }
12085         
12086         if(!dv.length){
12087             return;
12088         }
12089         
12090         var choice = this.choices.createChild({
12091             tag: 'li',
12092             cls: 'select2-search-choice',
12093             cn: [
12094                 {
12095                     tag: 'div',
12096                     html: dv
12097                 },
12098                 {
12099                     tag: 'a',
12100                     href: '#',
12101                     cls: 'select2-search-choice-close',
12102                     tabindex: '-1'
12103                 }
12104             ]
12105             
12106         }, this.searchField);
12107         
12108         var close = choice.select('a.select2-search-choice-close', true).first()
12109         
12110         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12111         
12112         this.item.push(o);
12113         
12114         this.lastData = o;
12115         
12116         this.syncValue();
12117         
12118         this.inputEl().dom.value = '';
12119         
12120     },
12121     
12122     onRemoveItem : function(e, _self, o)
12123     {
12124         e.preventDefault();
12125         var index = this.item.indexOf(o.data) * 1;
12126         
12127         if( index < 0){
12128             Roo.log('not this item?!');
12129             return;
12130         }
12131         
12132         this.item.splice(index, 1);
12133         o.item.remove();
12134         
12135         this.syncValue();
12136         
12137         this.fireEvent('remove', this, e);
12138         
12139     },
12140     
12141     syncValue : function()
12142     {
12143         if(!this.item.length){
12144             this.clearValue();
12145             return;
12146         }
12147             
12148         var value = [];
12149         var _this = this;
12150         Roo.each(this.item, function(i){
12151             if(_this.valueField){
12152                 value.push(i[_this.valueField]);
12153                 return;
12154             }
12155
12156             value.push(i);
12157         });
12158
12159         this.value = value.join(',');
12160
12161         if(this.hiddenField){
12162             this.hiddenField.dom.value = this.value;
12163         }
12164     },
12165     
12166     clearItem : function()
12167     {
12168         if(!this.multiple){
12169             return;
12170         }
12171         
12172         this.item = [];
12173         
12174         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12175            c.remove();
12176         });
12177         
12178         this.syncValue();
12179     },
12180     
12181     inputEl: function ()
12182     {
12183         if(this.tickable){
12184             return this.searchField;
12185         }
12186         return this.el.select('input.form-control',true).first();
12187     },
12188     
12189     
12190     onTickableFooterButtonClick : function(e, btn, el)
12191     {
12192         e.preventDefault();
12193         
12194         if(btn && btn.name == 'cancel'){
12195             this.tickItems = Roo.apply([], this.item);
12196             this.collapse();
12197             return;
12198         }
12199         
12200         this.clearItem();
12201         
12202         var _this = this;
12203         
12204         Roo.each(this.tickItems, function(o){
12205             _this.addItem(o);
12206         });
12207         
12208         this.collapse();
12209         
12210     },
12211     
12212     validate : function()
12213     {
12214         var v = this.getRawValue();
12215         
12216         if(this.multiple){
12217             v = this.getValue();
12218         }
12219         
12220         if(this.disabled || this.validateValue(v)){
12221             this.clearInvalid();
12222             return true;
12223         }
12224         return false;
12225     }
12226     
12227     
12228
12229     /** 
12230     * @cfg {Boolean} grow 
12231     * @hide 
12232     */
12233     /** 
12234     * @cfg {Number} growMin 
12235     * @hide 
12236     */
12237     /** 
12238     * @cfg {Number} growMax 
12239     * @hide 
12240     */
12241     /**
12242      * @hide
12243      * @method autoSize
12244      */
12245 });
12246 /*
12247  * Based on:
12248  * Ext JS Library 1.1.1
12249  * Copyright(c) 2006-2007, Ext JS, LLC.
12250  *
12251  * Originally Released Under LGPL - original licence link has changed is not relivant.
12252  *
12253  * Fork - LGPL
12254  * <script type="text/javascript">
12255  */
12256
12257 /**
12258  * @class Roo.View
12259  * @extends Roo.util.Observable
12260  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12261  * This class also supports single and multi selection modes. <br>
12262  * Create a data model bound view:
12263  <pre><code>
12264  var store = new Roo.data.Store(...);
12265
12266  var view = new Roo.View({
12267     el : "my-element",
12268     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12269  
12270     singleSelect: true,
12271     selectedClass: "ydataview-selected",
12272     store: store
12273  });
12274
12275  // listen for node click?
12276  view.on("click", function(vw, index, node, e){
12277  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12278  });
12279
12280  // load XML data
12281  dataModel.load("foobar.xml");
12282  </code></pre>
12283  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12284  * <br><br>
12285  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12286  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12287  * 
12288  * Note: old style constructor is still suported (container, template, config)
12289  * 
12290  * @constructor
12291  * Create a new View
12292  * @param {Object} config The config object
12293  * 
12294  */
12295 Roo.View = function(config, depreciated_tpl, depreciated_config){
12296     
12297     this.parent = false;
12298     
12299     if (typeof(depreciated_tpl) == 'undefined') {
12300         // new way.. - universal constructor.
12301         Roo.apply(this, config);
12302         this.el  = Roo.get(this.el);
12303     } else {
12304         // old format..
12305         this.el  = Roo.get(config);
12306         this.tpl = depreciated_tpl;
12307         Roo.apply(this, depreciated_config);
12308     }
12309     this.wrapEl  = this.el.wrap().wrap();
12310     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12311     
12312     
12313     if(typeof(this.tpl) == "string"){
12314         this.tpl = new Roo.Template(this.tpl);
12315     } else {
12316         // support xtype ctors..
12317         this.tpl = new Roo.factory(this.tpl, Roo);
12318     }
12319     
12320     
12321     this.tpl.compile();
12322     
12323     /** @private */
12324     this.addEvents({
12325         /**
12326          * @event beforeclick
12327          * Fires before a click is processed. Returns false to cancel the default action.
12328          * @param {Roo.View} this
12329          * @param {Number} index The index of the target node
12330          * @param {HTMLElement} node The target node
12331          * @param {Roo.EventObject} e The raw event object
12332          */
12333             "beforeclick" : true,
12334         /**
12335          * @event click
12336          * Fires when a template node is clicked.
12337          * @param {Roo.View} this
12338          * @param {Number} index The index of the target node
12339          * @param {HTMLElement} node The target node
12340          * @param {Roo.EventObject} e The raw event object
12341          */
12342             "click" : true,
12343         /**
12344          * @event dblclick
12345          * Fires when a template node is double clicked.
12346          * @param {Roo.View} this
12347          * @param {Number} index The index of the target node
12348          * @param {HTMLElement} node The target node
12349          * @param {Roo.EventObject} e The raw event object
12350          */
12351             "dblclick" : true,
12352         /**
12353          * @event contextmenu
12354          * Fires when a template node is right clicked.
12355          * @param {Roo.View} this
12356          * @param {Number} index The index of the target node
12357          * @param {HTMLElement} node The target node
12358          * @param {Roo.EventObject} e The raw event object
12359          */
12360             "contextmenu" : true,
12361         /**
12362          * @event selectionchange
12363          * Fires when the selected nodes change.
12364          * @param {Roo.View} this
12365          * @param {Array} selections Array of the selected nodes
12366          */
12367             "selectionchange" : true,
12368     
12369         /**
12370          * @event beforeselect
12371          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12372          * @param {Roo.View} this
12373          * @param {HTMLElement} node The node to be selected
12374          * @param {Array} selections Array of currently selected nodes
12375          */
12376             "beforeselect" : true,
12377         /**
12378          * @event preparedata
12379          * Fires on every row to render, to allow you to change the data.
12380          * @param {Roo.View} this
12381          * @param {Object} data to be rendered (change this)
12382          */
12383           "preparedata" : true
12384           
12385           
12386         });
12387
12388
12389
12390     this.el.on({
12391         "click": this.onClick,
12392         "dblclick": this.onDblClick,
12393         "contextmenu": this.onContextMenu,
12394         scope:this
12395     });
12396
12397     this.selections = [];
12398     this.nodes = [];
12399     this.cmp = new Roo.CompositeElementLite([]);
12400     if(this.store){
12401         this.store = Roo.factory(this.store, Roo.data);
12402         this.setStore(this.store, true);
12403     }
12404     
12405     if ( this.footer && this.footer.xtype) {
12406            
12407          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12408         
12409         this.footer.dataSource = this.store
12410         this.footer.container = fctr;
12411         this.footer = Roo.factory(this.footer, Roo);
12412         fctr.insertFirst(this.el);
12413         
12414         // this is a bit insane - as the paging toolbar seems to detach the el..
12415 //        dom.parentNode.parentNode.parentNode
12416          // they get detached?
12417     }
12418     
12419     
12420     Roo.View.superclass.constructor.call(this);
12421     
12422     
12423 };
12424
12425 Roo.extend(Roo.View, Roo.util.Observable, {
12426     
12427      /**
12428      * @cfg {Roo.data.Store} store Data store to load data from.
12429      */
12430     store : false,
12431     
12432     /**
12433      * @cfg {String|Roo.Element} el The container element.
12434      */
12435     el : '',
12436     
12437     /**
12438      * @cfg {String|Roo.Template} tpl The template used by this View 
12439      */
12440     tpl : false,
12441     /**
12442      * @cfg {String} dataName the named area of the template to use as the data area
12443      *                          Works with domtemplates roo-name="name"
12444      */
12445     dataName: false,
12446     /**
12447      * @cfg {String} selectedClass The css class to add to selected nodes
12448      */
12449     selectedClass : "x-view-selected",
12450      /**
12451      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12452      */
12453     emptyText : "",
12454     
12455     /**
12456      * @cfg {String} text to display on mask (default Loading)
12457      */
12458     mask : false,
12459     /**
12460      * @cfg {Boolean} multiSelect Allow multiple selection
12461      */
12462     multiSelect : false,
12463     /**
12464      * @cfg {Boolean} singleSelect Allow single selection
12465      */
12466     singleSelect:  false,
12467     
12468     /**
12469      * @cfg {Boolean} toggleSelect - selecting 
12470      */
12471     toggleSelect : false,
12472     
12473     /**
12474      * @cfg {Boolean} tickable - selecting 
12475      */
12476     tickable : false,
12477     
12478     /**
12479      * Returns the element this view is bound to.
12480      * @return {Roo.Element}
12481      */
12482     getEl : function(){
12483         return this.wrapEl;
12484     },
12485     
12486     
12487
12488     /**
12489      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12490      */
12491     refresh : function(){
12492         //Roo.log('refresh');
12493         var t = this.tpl;
12494         
12495         // if we are using something like 'domtemplate', then
12496         // the what gets used is:
12497         // t.applySubtemplate(NAME, data, wrapping data..)
12498         // the outer template then get' applied with
12499         //     the store 'extra data'
12500         // and the body get's added to the
12501         //      roo-name="data" node?
12502         //      <span class='roo-tpl-{name}'></span> ?????
12503         
12504         
12505         
12506         this.clearSelections();
12507         this.el.update("");
12508         var html = [];
12509         var records = this.store.getRange();
12510         if(records.length < 1) {
12511             
12512             // is this valid??  = should it render a template??
12513             
12514             this.el.update(this.emptyText);
12515             return;
12516         }
12517         var el = this.el;
12518         if (this.dataName) {
12519             this.el.update(t.apply(this.store.meta)); //????
12520             el = this.el.child('.roo-tpl-' + this.dataName);
12521         }
12522         
12523         for(var i = 0, len = records.length; i < len; i++){
12524             var data = this.prepareData(records[i].data, i, records[i]);
12525             this.fireEvent("preparedata", this, data, i, records[i]);
12526             
12527             var d = Roo.apply({}, data);
12528             
12529             if(this.tickable){
12530                 Roo.apply(d, {'roo-id' : Roo.id()});
12531                 
12532                 var _this = this;
12533             
12534                 Roo.each(this.parent.item, function(item){
12535                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12536                         return;
12537                     }
12538                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12539                 });
12540             }
12541             
12542             html[html.length] = Roo.util.Format.trim(
12543                 this.dataName ?
12544                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12545                     t.apply(d)
12546             );
12547         }
12548         
12549         
12550         
12551         el.update(html.join(""));
12552         this.nodes = el.dom.childNodes;
12553         this.updateIndexes(0);
12554     },
12555     
12556
12557     /**
12558      * Function to override to reformat the data that is sent to
12559      * the template for each node.
12560      * DEPRICATED - use the preparedata event handler.
12561      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12562      * a JSON object for an UpdateManager bound view).
12563      */
12564     prepareData : function(data, index, record)
12565     {
12566         this.fireEvent("preparedata", this, data, index, record);
12567         return data;
12568     },
12569
12570     onUpdate : function(ds, record){
12571         // Roo.log('on update');   
12572         this.clearSelections();
12573         var index = this.store.indexOf(record);
12574         var n = this.nodes[index];
12575         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12576         n.parentNode.removeChild(n);
12577         this.updateIndexes(index, index);
12578     },
12579
12580     
12581     
12582 // --------- FIXME     
12583     onAdd : function(ds, records, index)
12584     {
12585         //Roo.log(['on Add', ds, records, index] );        
12586         this.clearSelections();
12587         if(this.nodes.length == 0){
12588             this.refresh();
12589             return;
12590         }
12591         var n = this.nodes[index];
12592         for(var i = 0, len = records.length; i < len; i++){
12593             var d = this.prepareData(records[i].data, i, records[i]);
12594             if(n){
12595                 this.tpl.insertBefore(n, d);
12596             }else{
12597                 
12598                 this.tpl.append(this.el, d);
12599             }
12600         }
12601         this.updateIndexes(index);
12602     },
12603
12604     onRemove : function(ds, record, index){
12605        // Roo.log('onRemove');
12606         this.clearSelections();
12607         var el = this.dataName  ?
12608             this.el.child('.roo-tpl-' + this.dataName) :
12609             this.el; 
12610         
12611         el.dom.removeChild(this.nodes[index]);
12612         this.updateIndexes(index);
12613     },
12614
12615     /**
12616      * Refresh an individual node.
12617      * @param {Number} index
12618      */
12619     refreshNode : function(index){
12620         this.onUpdate(this.store, this.store.getAt(index));
12621     },
12622
12623     updateIndexes : function(startIndex, endIndex){
12624         var ns = this.nodes;
12625         startIndex = startIndex || 0;
12626         endIndex = endIndex || ns.length - 1;
12627         for(var i = startIndex; i <= endIndex; i++){
12628             ns[i].nodeIndex = i;
12629         }
12630     },
12631
12632     /**
12633      * Changes the data store this view uses and refresh the view.
12634      * @param {Store} store
12635      */
12636     setStore : function(store, initial){
12637         if(!initial && this.store){
12638             this.store.un("datachanged", this.refresh);
12639             this.store.un("add", this.onAdd);
12640             this.store.un("remove", this.onRemove);
12641             this.store.un("update", this.onUpdate);
12642             this.store.un("clear", this.refresh);
12643             this.store.un("beforeload", this.onBeforeLoad);
12644             this.store.un("load", this.onLoad);
12645             this.store.un("loadexception", this.onLoad);
12646         }
12647         if(store){
12648           
12649             store.on("datachanged", this.refresh, this);
12650             store.on("add", this.onAdd, this);
12651             store.on("remove", this.onRemove, this);
12652             store.on("update", this.onUpdate, this);
12653             store.on("clear", this.refresh, this);
12654             store.on("beforeload", this.onBeforeLoad, this);
12655             store.on("load", this.onLoad, this);
12656             store.on("loadexception", this.onLoad, this);
12657         }
12658         
12659         if(store){
12660             this.refresh();
12661         }
12662     },
12663     /**
12664      * onbeforeLoad - masks the loading area.
12665      *
12666      */
12667     onBeforeLoad : function(store,opts)
12668     {
12669          //Roo.log('onBeforeLoad');   
12670         if (!opts.add) {
12671             this.el.update("");
12672         }
12673         this.el.mask(this.mask ? this.mask : "Loading" ); 
12674     },
12675     onLoad : function ()
12676     {
12677         this.el.unmask();
12678     },
12679     
12680
12681     /**
12682      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12683      * @param {HTMLElement} node
12684      * @return {HTMLElement} The template node
12685      */
12686     findItemFromChild : function(node){
12687         var el = this.dataName  ?
12688             this.el.child('.roo-tpl-' + this.dataName,true) :
12689             this.el.dom; 
12690         
12691         if(!node || node.parentNode == el){
12692                     return node;
12693             }
12694             var p = node.parentNode;
12695             while(p && p != el){
12696             if(p.parentNode == el){
12697                 return p;
12698             }
12699             p = p.parentNode;
12700         }
12701             return null;
12702     },
12703
12704     /** @ignore */
12705     onClick : function(e){
12706         var item = this.findItemFromChild(e.getTarget());
12707         if(item){
12708             var index = this.indexOf(item);
12709             if(this.onItemClick(item, index, e) !== false){
12710                 this.fireEvent("click", this, index, item, e);
12711             }
12712         }else{
12713             this.clearSelections();
12714         }
12715     },
12716
12717     /** @ignore */
12718     onContextMenu : function(e){
12719         var item = this.findItemFromChild(e.getTarget());
12720         if(item){
12721             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
12722         }
12723     },
12724
12725     /** @ignore */
12726     onDblClick : function(e){
12727         var item = this.findItemFromChild(e.getTarget());
12728         if(item){
12729             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
12730         }
12731     },
12732
12733     onItemClick : function(item, index, e)
12734     {
12735         if(this.fireEvent("beforeclick", this, index, item, e) === false){
12736             return false;
12737         }
12738         if (this.toggleSelect) {
12739             var m = this.isSelected(item) ? 'unselect' : 'select';
12740             //Roo.log(m);
12741             var _t = this;
12742             _t[m](item, true, false);
12743             return true;
12744         }
12745         if(this.multiSelect || this.singleSelect){
12746             if(this.multiSelect && e.shiftKey && this.lastSelection){
12747                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
12748             }else{
12749                 this.select(item, this.multiSelect && e.ctrlKey);
12750                 this.lastSelection = item;
12751             }
12752             
12753             if(!this.tickable){
12754                 e.preventDefault();
12755             }
12756             
12757         }
12758         return true;
12759     },
12760
12761     /**
12762      * Get the number of selected nodes.
12763      * @return {Number}
12764      */
12765     getSelectionCount : function(){
12766         return this.selections.length;
12767     },
12768
12769     /**
12770      * Get the currently selected nodes.
12771      * @return {Array} An array of HTMLElements
12772      */
12773     getSelectedNodes : function(){
12774         return this.selections;
12775     },
12776
12777     /**
12778      * Get the indexes of the selected nodes.
12779      * @return {Array}
12780      */
12781     getSelectedIndexes : function(){
12782         var indexes = [], s = this.selections;
12783         for(var i = 0, len = s.length; i < len; i++){
12784             indexes.push(s[i].nodeIndex);
12785         }
12786         return indexes;
12787     },
12788
12789     /**
12790      * Clear all selections
12791      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
12792      */
12793     clearSelections : function(suppressEvent){
12794         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
12795             this.cmp.elements = this.selections;
12796             this.cmp.removeClass(this.selectedClass);
12797             this.selections = [];
12798             if(!suppressEvent){
12799                 this.fireEvent("selectionchange", this, this.selections);
12800             }
12801         }
12802     },
12803
12804     /**
12805      * Returns true if the passed node is selected
12806      * @param {HTMLElement/Number} node The node or node index
12807      * @return {Boolean}
12808      */
12809     isSelected : function(node){
12810         var s = this.selections;
12811         if(s.length < 1){
12812             return false;
12813         }
12814         node = this.getNode(node);
12815         return s.indexOf(node) !== -1;
12816     },
12817
12818     /**
12819      * Selects nodes.
12820      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12821      * @param {Boolean} keepExisting (optional) true to keep existing selections
12822      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12823      */
12824     select : function(nodeInfo, keepExisting, suppressEvent){
12825         if(nodeInfo instanceof Array){
12826             if(!keepExisting){
12827                 this.clearSelections(true);
12828             }
12829             for(var i = 0, len = nodeInfo.length; i < len; i++){
12830                 this.select(nodeInfo[i], true, true);
12831             }
12832             return;
12833         } 
12834         var node = this.getNode(nodeInfo);
12835         if(!node || this.isSelected(node)){
12836             return; // already selected.
12837         }
12838         if(!keepExisting){
12839             this.clearSelections(true);
12840         }
12841         
12842         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
12843             Roo.fly(node).addClass(this.selectedClass);
12844             this.selections.push(node);
12845             if(!suppressEvent){
12846                 this.fireEvent("selectionchange", this, this.selections);
12847             }
12848         }
12849         
12850         
12851     },
12852       /**
12853      * Unselects nodes.
12854      * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
12855      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
12856      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
12857      */
12858     unselect : function(nodeInfo, keepExisting, suppressEvent)
12859     {
12860         if(nodeInfo instanceof Array){
12861             Roo.each(this.selections, function(s) {
12862                 this.unselect(s, nodeInfo);
12863             }, this);
12864             return;
12865         }
12866         var node = this.getNode(nodeInfo);
12867         if(!node || !this.isSelected(node)){
12868             //Roo.log("not selected");
12869             return; // not selected.
12870         }
12871         // fireevent???
12872         var ns = [];
12873         Roo.each(this.selections, function(s) {
12874             if (s == node ) {
12875                 Roo.fly(node).removeClass(this.selectedClass);
12876
12877                 return;
12878             }
12879             ns.push(s);
12880         },this);
12881         
12882         this.selections= ns;
12883         this.fireEvent("selectionchange", this, this.selections);
12884     },
12885
12886     /**
12887      * Gets a template node.
12888      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12889      * @return {HTMLElement} The node or null if it wasn't found
12890      */
12891     getNode : function(nodeInfo){
12892         if(typeof nodeInfo == "string"){
12893             return document.getElementById(nodeInfo);
12894         }else if(typeof nodeInfo == "number"){
12895             return this.nodes[nodeInfo];
12896         }
12897         return nodeInfo;
12898     },
12899
12900     /**
12901      * Gets a range template nodes.
12902      * @param {Number} startIndex
12903      * @param {Number} endIndex
12904      * @return {Array} An array of nodes
12905      */
12906     getNodes : function(start, end){
12907         var ns = this.nodes;
12908         start = start || 0;
12909         end = typeof end == "undefined" ? ns.length - 1 : end;
12910         var nodes = [];
12911         if(start <= end){
12912             for(var i = start; i <= end; i++){
12913                 nodes.push(ns[i]);
12914             }
12915         } else{
12916             for(var i = start; i >= end; i--){
12917                 nodes.push(ns[i]);
12918             }
12919         }
12920         return nodes;
12921     },
12922
12923     /**
12924      * Finds the index of the passed node
12925      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
12926      * @return {Number} The index of the node or -1
12927      */
12928     indexOf : function(node){
12929         node = this.getNode(node);
12930         if(typeof node.nodeIndex == "number"){
12931             return node.nodeIndex;
12932         }
12933         var ns = this.nodes;
12934         for(var i = 0, len = ns.length; i < len; i++){
12935             if(ns[i] == node){
12936                 return i;
12937             }
12938         }
12939         return -1;
12940     }
12941 });
12942 /*
12943  * - LGPL
12944  *
12945  * based on jquery fullcalendar
12946  * 
12947  */
12948
12949 Roo.bootstrap = Roo.bootstrap || {};
12950 /**
12951  * @class Roo.bootstrap.Calendar
12952  * @extends Roo.bootstrap.Component
12953  * Bootstrap Calendar class
12954  * @cfg {Boolean} loadMask (true|false) default false
12955  * @cfg {Object} header generate the user specific header of the calendar, default false
12956
12957  * @constructor
12958  * Create a new Container
12959  * @param {Object} config The config object
12960  */
12961
12962
12963
12964 Roo.bootstrap.Calendar = function(config){
12965     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
12966      this.addEvents({
12967         /**
12968              * @event select
12969              * Fires when a date is selected
12970              * @param {DatePicker} this
12971              * @param {Date} date The selected date
12972              */
12973         'select': true,
12974         /**
12975              * @event monthchange
12976              * Fires when the displayed month changes 
12977              * @param {DatePicker} this
12978              * @param {Date} date The selected month
12979              */
12980         'monthchange': true,
12981         /**
12982              * @event evententer
12983              * Fires when mouse over an event
12984              * @param {Calendar} this
12985              * @param {event} Event
12986              */
12987         'evententer': true,
12988         /**
12989              * @event eventleave
12990              * Fires when the mouse leaves an
12991              * @param {Calendar} this
12992              * @param {event}
12993              */
12994         'eventleave': true,
12995         /**
12996              * @event eventclick
12997              * Fires when the mouse click an
12998              * @param {Calendar} this
12999              * @param {event}
13000              */
13001         'eventclick': true
13002         
13003     });
13004
13005 };
13006
13007 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13008     
13009      /**
13010      * @cfg {Number} startDay
13011      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13012      */
13013     startDay : 0,
13014     
13015     loadMask : false,
13016     
13017     header : false,
13018       
13019     getAutoCreate : function(){
13020         
13021         
13022         var fc_button = function(name, corner, style, content ) {
13023             return Roo.apply({},{
13024                 tag : 'span',
13025                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13026                          (corner.length ?
13027                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13028                             ''
13029                         ),
13030                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13031                 unselectable: 'on'
13032             });
13033         };
13034         
13035         var header = {};
13036         
13037         if(!this.header){
13038             header = {
13039                 tag : 'table',
13040                 cls : 'fc-header',
13041                 style : 'width:100%',
13042                 cn : [
13043                     {
13044                         tag: 'tr',
13045                         cn : [
13046                             {
13047                                 tag : 'td',
13048                                 cls : 'fc-header-left',
13049                                 cn : [
13050                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13051                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13052                                     { tag: 'span', cls: 'fc-header-space' },
13053                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13054
13055
13056                                 ]
13057                             },
13058
13059                             {
13060                                 tag : 'td',
13061                                 cls : 'fc-header-center',
13062                                 cn : [
13063                                     {
13064                                         tag: 'span',
13065                                         cls: 'fc-header-title',
13066                                         cn : {
13067                                             tag: 'H2',
13068                                             html : 'month / year'
13069                                         }
13070                                     }
13071
13072                                 ]
13073                             },
13074                             {
13075                                 tag : 'td',
13076                                 cls : 'fc-header-right',
13077                                 cn : [
13078                               /*      fc_button('month', 'left', '', 'month' ),
13079                                     fc_button('week', '', '', 'week' ),
13080                                     fc_button('day', 'right', '', 'day' )
13081                                 */    
13082
13083                                 ]
13084                             }
13085
13086                         ]
13087                     }
13088                 ]
13089             };
13090         }
13091         
13092         header = this.header;
13093         
13094        
13095         var cal_heads = function() {
13096             var ret = [];
13097             // fixme - handle this.
13098             
13099             for (var i =0; i < Date.dayNames.length; i++) {
13100                 var d = Date.dayNames[i];
13101                 ret.push({
13102                     tag: 'th',
13103                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13104                     html : d.substring(0,3)
13105                 });
13106                 
13107             }
13108             ret[0].cls += ' fc-first';
13109             ret[6].cls += ' fc-last';
13110             return ret;
13111         };
13112         var cal_cell = function(n) {
13113             return  {
13114                 tag: 'td',
13115                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13116                 cn : [
13117                     {
13118                         cn : [
13119                             {
13120                                 cls: 'fc-day-number',
13121                                 html: 'D'
13122                             },
13123                             {
13124                                 cls: 'fc-day-content',
13125                              
13126                                 cn : [
13127                                      {
13128                                         style: 'position: relative;' // height: 17px;
13129                                     }
13130                                 ]
13131                             }
13132                             
13133                             
13134                         ]
13135                     }
13136                 ]
13137                 
13138             }
13139         };
13140         var cal_rows = function() {
13141             
13142             var ret = [];
13143             for (var r = 0; r < 6; r++) {
13144                 var row= {
13145                     tag : 'tr',
13146                     cls : 'fc-week',
13147                     cn : []
13148                 };
13149                 
13150                 for (var i =0; i < Date.dayNames.length; i++) {
13151                     var d = Date.dayNames[i];
13152                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13153
13154                 }
13155                 row.cn[0].cls+=' fc-first';
13156                 row.cn[0].cn[0].style = 'min-height:90px';
13157                 row.cn[6].cls+=' fc-last';
13158                 ret.push(row);
13159                 
13160             }
13161             ret[0].cls += ' fc-first';
13162             ret[4].cls += ' fc-prev-last';
13163             ret[5].cls += ' fc-last';
13164             return ret;
13165             
13166         };
13167         
13168         var cal_table = {
13169             tag: 'table',
13170             cls: 'fc-border-separate',
13171             style : 'width:100%',
13172             cellspacing  : 0,
13173             cn : [
13174                 { 
13175                     tag: 'thead',
13176                     cn : [
13177                         { 
13178                             tag: 'tr',
13179                             cls : 'fc-first fc-last',
13180                             cn : cal_heads()
13181                         }
13182                     ]
13183                 },
13184                 { 
13185                     tag: 'tbody',
13186                     cn : cal_rows()
13187                 }
13188                   
13189             ]
13190         };
13191          
13192          var cfg = {
13193             cls : 'fc fc-ltr',
13194             cn : [
13195                 header,
13196                 {
13197                     cls : 'fc-content',
13198                     style : "position: relative;",
13199                     cn : [
13200                         {
13201                             cls : 'fc-view fc-view-month fc-grid',
13202                             style : 'position: relative',
13203                             unselectable : 'on',
13204                             cn : [
13205                                 {
13206                                     cls : 'fc-event-container',
13207                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13208                                 },
13209                                 cal_table
13210                             ]
13211                         }
13212                     ]
13213     
13214                 }
13215            ] 
13216             
13217         };
13218         
13219          
13220         
13221         return cfg;
13222     },
13223     
13224     
13225     initEvents : function()
13226     {
13227         if(!this.store){
13228             throw "can not find store for calendar";
13229         }
13230         
13231         var mark = {
13232             tag: "div",
13233             cls:"x-dlg-mask",
13234             style: "text-align:center",
13235             cn: [
13236                 {
13237                     tag: "div",
13238                     style: "background-color:white;width:50%;margin:250 auto",
13239                     cn: [
13240                         {
13241                             tag: "img",
13242                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13243                         },
13244                         {
13245                             tag: "span",
13246                             html: "Loading"
13247                         }
13248                         
13249                     ]
13250                 }
13251             ]
13252         }
13253         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13254         
13255         var size = this.el.select('.fc-content', true).first().getSize();
13256         this.maskEl.setSize(size.width, size.height);
13257         this.maskEl.enableDisplayMode("block");
13258         if(!this.loadMask){
13259             this.maskEl.hide();
13260         }
13261         
13262         this.store = Roo.factory(this.store, Roo.data);
13263         this.store.on('load', this.onLoad, this);
13264         this.store.on('beforeload', this.onBeforeLoad, this);
13265         
13266         this.resize();
13267         
13268         this.cells = this.el.select('.fc-day',true);
13269         //Roo.log(this.cells);
13270         this.textNodes = this.el.query('.fc-day-number');
13271         this.cells.addClassOnOver('fc-state-hover');
13272         
13273         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13274         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13275         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13276         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13277         
13278         this.on('monthchange', this.onMonthChange, this);
13279         
13280         this.update(new Date().clearTime());
13281     },
13282     
13283     resize : function() {
13284         var sz  = this.el.getSize();
13285         
13286         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13287         this.el.select('.fc-day-content div',true).setHeight(34);
13288     },
13289     
13290     
13291     // private
13292     showPrevMonth : function(e){
13293         this.update(this.activeDate.add("mo", -1));
13294     },
13295     showToday : function(e){
13296         this.update(new Date().clearTime());
13297     },
13298     // private
13299     showNextMonth : function(e){
13300         this.update(this.activeDate.add("mo", 1));
13301     },
13302
13303     // private
13304     showPrevYear : function(){
13305         this.update(this.activeDate.add("y", -1));
13306     },
13307
13308     // private
13309     showNextYear : function(){
13310         this.update(this.activeDate.add("y", 1));
13311     },
13312
13313     
13314    // private
13315     update : function(date)
13316     {
13317         var vd = this.activeDate;
13318         this.activeDate = date;
13319 //        if(vd && this.el){
13320 //            var t = date.getTime();
13321 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13322 //                Roo.log('using add remove');
13323 //                
13324 //                this.fireEvent('monthchange', this, date);
13325 //                
13326 //                this.cells.removeClass("fc-state-highlight");
13327 //                this.cells.each(function(c){
13328 //                   if(c.dateValue == t){
13329 //                       c.addClass("fc-state-highlight");
13330 //                       setTimeout(function(){
13331 //                            try{c.dom.firstChild.focus();}catch(e){}
13332 //                       }, 50);
13333 //                       return false;
13334 //                   }
13335 //                   return true;
13336 //                });
13337 //                return;
13338 //            }
13339 //        }
13340         
13341         var days = date.getDaysInMonth();
13342         
13343         var firstOfMonth = date.getFirstDateOfMonth();
13344         var startingPos = firstOfMonth.getDay()-this.startDay;
13345         
13346         if(startingPos < this.startDay){
13347             startingPos += 7;
13348         }
13349         
13350         var pm = date.add(Date.MONTH, -1);
13351         var prevStart = pm.getDaysInMonth()-startingPos;
13352 //        
13353         this.cells = this.el.select('.fc-day',true);
13354         this.textNodes = this.el.query('.fc-day-number');
13355         this.cells.addClassOnOver('fc-state-hover');
13356         
13357         var cells = this.cells.elements;
13358         var textEls = this.textNodes;
13359         
13360         Roo.each(cells, function(cell){
13361             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13362         });
13363         
13364         days += startingPos;
13365
13366         // convert everything to numbers so it's fast
13367         var day = 86400000;
13368         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13369         //Roo.log(d);
13370         //Roo.log(pm);
13371         //Roo.log(prevStart);
13372         
13373         var today = new Date().clearTime().getTime();
13374         var sel = date.clearTime().getTime();
13375         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13376         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13377         var ddMatch = this.disabledDatesRE;
13378         var ddText = this.disabledDatesText;
13379         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13380         var ddaysText = this.disabledDaysText;
13381         var format = this.format;
13382         
13383         var setCellClass = function(cal, cell){
13384             cell.row = 0;
13385             cell.events = [];
13386             cell.more = [];
13387             //Roo.log('set Cell Class');
13388             cell.title = "";
13389             var t = d.getTime();
13390             
13391             //Roo.log(d);
13392             
13393             cell.dateValue = t;
13394             if(t == today){
13395                 cell.className += " fc-today";
13396                 cell.className += " fc-state-highlight";
13397                 cell.title = cal.todayText;
13398             }
13399             if(t == sel){
13400                 // disable highlight in other month..
13401                 //cell.className += " fc-state-highlight";
13402                 
13403             }
13404             // disabling
13405             if(t < min) {
13406                 cell.className = " fc-state-disabled";
13407                 cell.title = cal.minText;
13408                 return;
13409             }
13410             if(t > max) {
13411                 cell.className = " fc-state-disabled";
13412                 cell.title = cal.maxText;
13413                 return;
13414             }
13415             if(ddays){
13416                 if(ddays.indexOf(d.getDay()) != -1){
13417                     cell.title = ddaysText;
13418                     cell.className = " fc-state-disabled";
13419                 }
13420             }
13421             if(ddMatch && format){
13422                 var fvalue = d.dateFormat(format);
13423                 if(ddMatch.test(fvalue)){
13424                     cell.title = ddText.replace("%0", fvalue);
13425                     cell.className = " fc-state-disabled";
13426                 }
13427             }
13428             
13429             if (!cell.initialClassName) {
13430                 cell.initialClassName = cell.dom.className;
13431             }
13432             
13433             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13434         };
13435
13436         var i = 0;
13437         
13438         for(; i < startingPos; i++) {
13439             textEls[i].innerHTML = (++prevStart);
13440             d.setDate(d.getDate()+1);
13441             
13442             cells[i].className = "fc-past fc-other-month";
13443             setCellClass(this, cells[i]);
13444         }
13445         
13446         var intDay = 0;
13447         
13448         for(; i < days; i++){
13449             intDay = i - startingPos + 1;
13450             textEls[i].innerHTML = (intDay);
13451             d.setDate(d.getDate()+1);
13452             
13453             cells[i].className = ''; // "x-date-active";
13454             setCellClass(this, cells[i]);
13455         }
13456         var extraDays = 0;
13457         
13458         for(; i < 42; i++) {
13459             textEls[i].innerHTML = (++extraDays);
13460             d.setDate(d.getDate()+1);
13461             
13462             cells[i].className = "fc-future fc-other-month";
13463             setCellClass(this, cells[i]);
13464         }
13465         
13466         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13467         
13468         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13469         
13470         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13471         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13472         
13473         if(totalRows != 6){
13474             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13475             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13476         }
13477         
13478         this.fireEvent('monthchange', this, date);
13479         
13480         
13481         /*
13482         if(!this.internalRender){
13483             var main = this.el.dom.firstChild;
13484             var w = main.offsetWidth;
13485             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13486             Roo.fly(main).setWidth(w);
13487             this.internalRender = true;
13488             // opera does not respect the auto grow header center column
13489             // then, after it gets a width opera refuses to recalculate
13490             // without a second pass
13491             if(Roo.isOpera && !this.secondPass){
13492                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13493                 this.secondPass = true;
13494                 this.update.defer(10, this, [date]);
13495             }
13496         }
13497         */
13498         
13499     },
13500     
13501     findCell : function(dt) {
13502         dt = dt.clearTime().getTime();
13503         var ret = false;
13504         this.cells.each(function(c){
13505             //Roo.log("check " +c.dateValue + '?=' + dt);
13506             if(c.dateValue == dt){
13507                 ret = c;
13508                 return false;
13509             }
13510             return true;
13511         });
13512         
13513         return ret;
13514     },
13515     
13516     findCells : function(ev) {
13517         var s = ev.start.clone().clearTime().getTime();
13518        // Roo.log(s);
13519         var e= ev.end.clone().clearTime().getTime();
13520        // Roo.log(e);
13521         var ret = [];
13522         this.cells.each(function(c){
13523              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13524             
13525             if(c.dateValue > e){
13526                 return ;
13527             }
13528             if(c.dateValue < s){
13529                 return ;
13530             }
13531             ret.push(c);
13532         });
13533         
13534         return ret;    
13535     },
13536     
13537 //    findBestRow: function(cells)
13538 //    {
13539 //        var ret = 0;
13540 //        
13541 //        for (var i =0 ; i < cells.length;i++) {
13542 //            ret  = Math.max(cells[i].rows || 0,ret);
13543 //        }
13544 //        return ret;
13545 //        
13546 //    },
13547     
13548     
13549     addItem : function(ev)
13550     {
13551         // look for vertical location slot in
13552         var cells = this.findCells(ev);
13553         
13554 //        ev.row = this.findBestRow(cells);
13555         
13556         // work out the location.
13557         
13558         var crow = false;
13559         var rows = [];
13560         for(var i =0; i < cells.length; i++) {
13561             
13562             cells[i].row = cells[0].row;
13563             
13564             if(i == 0){
13565                 cells[i].row = cells[i].row + 1;
13566             }
13567             
13568             if (!crow) {
13569                 crow = {
13570                     start : cells[i],
13571                     end :  cells[i]
13572                 };
13573                 continue;
13574             }
13575             if (crow.start.getY() == cells[i].getY()) {
13576                 // on same row.
13577                 crow.end = cells[i];
13578                 continue;
13579             }
13580             // different row.
13581             rows.push(crow);
13582             crow = {
13583                 start: cells[i],
13584                 end : cells[i]
13585             };
13586             
13587         }
13588         
13589         rows.push(crow);
13590         ev.els = [];
13591         ev.rows = rows;
13592         ev.cells = cells;
13593         
13594         cells[0].events.push(ev);
13595         
13596         this.calevents.push(ev);
13597     },
13598     
13599     clearEvents: function() {
13600         
13601         if(!this.calevents){
13602             return;
13603         }
13604         
13605         Roo.each(this.cells.elements, function(c){
13606             c.row = 0;
13607             c.events = [];
13608             c.more = [];
13609         });
13610         
13611         Roo.each(this.calevents, function(e) {
13612             Roo.each(e.els, function(el) {
13613                 el.un('mouseenter' ,this.onEventEnter, this);
13614                 el.un('mouseleave' ,this.onEventLeave, this);
13615                 el.remove();
13616             },this);
13617         },this);
13618         
13619         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13620             e.remove();
13621         });
13622         
13623     },
13624     
13625     renderEvents: function()
13626     {   
13627         var _this = this;
13628         
13629         this.cells.each(function(c) {
13630             
13631             if(c.row < 5){
13632                 return;
13633             }
13634             
13635             var ev = c.events;
13636             
13637             var r = 4;
13638             if(c.row != c.events.length){
13639                 r = 4 - (4 - (c.row - c.events.length));
13640             }
13641             
13642             c.events = ev.slice(0, r);
13643             c.more = ev.slice(r);
13644             
13645             if(c.more.length && c.more.length == 1){
13646                 c.events.push(c.more.pop());
13647             }
13648             
13649             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13650             
13651         });
13652             
13653         this.cells.each(function(c) {
13654             
13655             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13656             
13657             
13658             for (var e = 0; e < c.events.length; e++){
13659                 var ev = c.events[e];
13660                 var rows = ev.rows;
13661                 
13662                 for(var i = 0; i < rows.length; i++) {
13663                 
13664                     // how many rows should it span..
13665
13666                     var  cfg = {
13667                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13668                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13669
13670                         unselectable : "on",
13671                         cn : [
13672                             {
13673                                 cls: 'fc-event-inner',
13674                                 cn : [
13675     //                                {
13676     //                                  tag:'span',
13677     //                                  cls: 'fc-event-time',
13678     //                                  html : cells.length > 1 ? '' : ev.time
13679     //                                },
13680                                     {
13681                                       tag:'span',
13682                                       cls: 'fc-event-title',
13683                                       html : String.format('{0}', ev.title)
13684                                     }
13685
13686
13687                                 ]
13688                             },
13689                             {
13690                                 cls: 'ui-resizable-handle ui-resizable-e',
13691                                 html : '&nbsp;&nbsp;&nbsp'
13692                             }
13693
13694                         ]
13695                     };
13696
13697                     if (i == 0) {
13698                         cfg.cls += ' fc-event-start';
13699                     }
13700                     if ((i+1) == rows.length) {
13701                         cfg.cls += ' fc-event-end';
13702                     }
13703
13704                     var ctr = _this.el.select('.fc-event-container',true).first();
13705                     var cg = ctr.createChild(cfg);
13706
13707                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13708                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13709
13710                     var r = (c.more.length) ? 1 : 0;
13711                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13712                     cg.setWidth(ebox.right - sbox.x -2);
13713
13714                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13715                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13716                     cg.on('click', _this.onEventClick, _this, ev);
13717
13718                     ev.els.push(cg);
13719                     
13720                 }
13721                 
13722             }
13723             
13724             
13725             if(c.more.length){
13726                 var  cfg = {
13727                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
13728                     style : 'position: absolute',
13729                     unselectable : "on",
13730                     cn : [
13731                         {
13732                             cls: 'fc-event-inner',
13733                             cn : [
13734                                 {
13735                                   tag:'span',
13736                                   cls: 'fc-event-title',
13737                                   html : 'More'
13738                                 }
13739
13740
13741                             ]
13742                         },
13743                         {
13744                             cls: 'ui-resizable-handle ui-resizable-e',
13745                             html : '&nbsp;&nbsp;&nbsp'
13746                         }
13747
13748                     ]
13749                 };
13750
13751                 var ctr = _this.el.select('.fc-event-container',true).first();
13752                 var cg = ctr.createChild(cfg);
13753
13754                 var sbox = c.select('.fc-day-content',true).first().getBox();
13755                 var ebox = c.select('.fc-day-content',true).first().getBox();
13756                 //Roo.log(cg);
13757                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
13758                 cg.setWidth(ebox.right - sbox.x -2);
13759
13760                 cg.on('click', _this.onMoreEventClick, _this, c.more);
13761                 
13762             }
13763             
13764         });
13765         
13766         
13767         
13768     },
13769     
13770     onEventEnter: function (e, el,event,d) {
13771         this.fireEvent('evententer', this, el, event);
13772     },
13773     
13774     onEventLeave: function (e, el,event,d) {
13775         this.fireEvent('eventleave', this, el, event);
13776     },
13777     
13778     onEventClick: function (e, el,event,d) {
13779         this.fireEvent('eventclick', this, el, event);
13780     },
13781     
13782     onMonthChange: function () {
13783         this.store.load();
13784     },
13785     
13786     onMoreEventClick: function(e, el, more)
13787     {
13788         var _this = this;
13789         
13790         this.calpopover.placement = 'right';
13791         this.calpopover.setTitle('More');
13792         
13793         this.calpopover.setContent('');
13794         
13795         var ctr = this.calpopover.el.select('.popover-content', true).first();
13796         
13797         Roo.each(more, function(m){
13798             var cfg = {
13799                 cls : 'fc-event-hori fc-event-draggable',
13800                 html : m.title
13801             }
13802             var cg = ctr.createChild(cfg);
13803             
13804             cg.on('click', _this.onEventClick, _this, m);
13805         });
13806         
13807         this.calpopover.show(el);
13808         
13809         
13810     },
13811     
13812     onLoad: function () 
13813     {   
13814         this.calevents = [];
13815         var cal = this;
13816         
13817         if(this.store.getCount() > 0){
13818             this.store.data.each(function(d){
13819                cal.addItem({
13820                     id : d.data.id,
13821                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
13822                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
13823                     time : d.data.start_time,
13824                     title : d.data.title,
13825                     description : d.data.description,
13826                     venue : d.data.venue
13827                 });
13828             });
13829         }
13830         
13831         this.renderEvents();
13832         
13833         if(this.calevents.length && this.loadMask){
13834             this.maskEl.hide();
13835         }
13836     },
13837     
13838     onBeforeLoad: function()
13839     {
13840         this.clearEvents();
13841         if(this.loadMask){
13842             this.maskEl.show();
13843         }
13844     }
13845 });
13846
13847  
13848  /*
13849  * - LGPL
13850  *
13851  * element
13852  * 
13853  */
13854
13855 /**
13856  * @class Roo.bootstrap.Popover
13857  * @extends Roo.bootstrap.Component
13858  * Bootstrap Popover class
13859  * @cfg {String} html contents of the popover   (or false to use children..)
13860  * @cfg {String} title of popover (or false to hide)
13861  * @cfg {String} placement how it is placed
13862  * @cfg {String} trigger click || hover (or false to trigger manually)
13863  * @cfg {String} over what (parent or false to trigger manually.)
13864  * @cfg {Number} delay - delay before showing
13865  
13866  * @constructor
13867  * Create a new Popover
13868  * @param {Object} config The config object
13869  */
13870
13871 Roo.bootstrap.Popover = function(config){
13872     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
13873 };
13874
13875 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
13876     
13877     title: 'Fill in a title',
13878     html: false,
13879     
13880     placement : 'right',
13881     trigger : 'hover', // hover
13882     
13883     delay : 0,
13884     
13885     over: 'parent',
13886     
13887     can_build_overlaid : false,
13888     
13889     getChildContainer : function()
13890     {
13891         return this.el.select('.popover-content',true).first();
13892     },
13893     
13894     getAutoCreate : function(){
13895          Roo.log('make popover?');
13896         var cfg = {
13897            cls : 'popover roo-dynamic',
13898            style: 'display:block',
13899            cn : [
13900                 {
13901                     cls : 'arrow'
13902                 },
13903                 {
13904                     cls : 'popover-inner',
13905                     cn : [
13906                         {
13907                             tag: 'h3',
13908                             cls: 'popover-title',
13909                             html : this.title
13910                         },
13911                         {
13912                             cls : 'popover-content',
13913                             html : this.html
13914                         }
13915                     ]
13916                     
13917                 }
13918            ]
13919         };
13920         
13921         return cfg;
13922     },
13923     setTitle: function(str)
13924     {
13925         this.el.select('.popover-title',true).first().dom.innerHTML = str;
13926     },
13927     setContent: function(str)
13928     {
13929         this.el.select('.popover-content',true).first().dom.innerHTML = str;
13930     },
13931     // as it get's added to the bottom of the page.
13932     onRender : function(ct, position)
13933     {
13934         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
13935         if(!this.el){
13936             var cfg = Roo.apply({},  this.getAutoCreate());
13937             cfg.id = Roo.id();
13938             
13939             if (this.cls) {
13940                 cfg.cls += ' ' + this.cls;
13941             }
13942             if (this.style) {
13943                 cfg.style = this.style;
13944             }
13945             Roo.log("adding to ")
13946             this.el = Roo.get(document.body).createChild(cfg, position);
13947             Roo.log(this.el);
13948         }
13949         this.initEvents();
13950     },
13951     
13952     initEvents : function()
13953     {
13954         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
13955         this.el.enableDisplayMode('block');
13956         this.el.hide();
13957         if (this.over === false) {
13958             return; 
13959         }
13960         if (this.triggers === false) {
13961             return;
13962         }
13963         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
13964         var triggers = this.trigger ? this.trigger.split(' ') : [];
13965         Roo.each(triggers, function(trigger) {
13966         
13967             if (trigger == 'click') {
13968                 on_el.on('click', this.toggle, this);
13969             } else if (trigger != 'manual') {
13970                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
13971                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
13972       
13973                 on_el.on(eventIn  ,this.enter, this);
13974                 on_el.on(eventOut, this.leave, this);
13975             }
13976         }, this);
13977         
13978     },
13979     
13980     
13981     // private
13982     timeout : null,
13983     hoverState : null,
13984     
13985     toggle : function () {
13986         this.hoverState == 'in' ? this.leave() : this.enter();
13987     },
13988     
13989     enter : function () {
13990        
13991     
13992         clearTimeout(this.timeout);
13993     
13994         this.hoverState = 'in';
13995     
13996         if (!this.delay || !this.delay.show) {
13997             this.show();
13998             return;
13999         }
14000         var _t = this;
14001         this.timeout = setTimeout(function () {
14002             if (_t.hoverState == 'in') {
14003                 _t.show();
14004             }
14005         }, this.delay.show)
14006     },
14007     leave : function() {
14008         clearTimeout(this.timeout);
14009     
14010         this.hoverState = 'out';
14011     
14012         if (!this.delay || !this.delay.hide) {
14013             this.hide();
14014             return;
14015         }
14016         var _t = this;
14017         this.timeout = setTimeout(function () {
14018             if (_t.hoverState == 'out') {
14019                 _t.hide();
14020             }
14021         }, this.delay.hide)
14022     },
14023     
14024     show : function (on_el)
14025     {
14026         if (!on_el) {
14027             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14028         }
14029         // set content.
14030         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14031         if (this.html !== false) {
14032             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14033         }
14034         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14035         if (!this.title.length) {
14036             this.el.select('.popover-title',true).hide();
14037         }
14038         
14039         var placement = typeof this.placement == 'function' ?
14040             this.placement.call(this, this.el, on_el) :
14041             this.placement;
14042             
14043         var autoToken = /\s?auto?\s?/i;
14044         var autoPlace = autoToken.test(placement);
14045         if (autoPlace) {
14046             placement = placement.replace(autoToken, '') || 'top';
14047         }
14048         
14049         //this.el.detach()
14050         //this.el.setXY([0,0]);
14051         this.el.show();
14052         this.el.dom.style.display='block';
14053         this.el.addClass(placement);
14054         
14055         //this.el.appendTo(on_el);
14056         
14057         var p = this.getPosition();
14058         var box = this.el.getBox();
14059         
14060         if (autoPlace) {
14061             // fixme..
14062         }
14063         var align = Roo.bootstrap.Popover.alignment[placement];
14064         this.el.alignTo(on_el, align[0],align[1]);
14065         //var arrow = this.el.select('.arrow',true).first();
14066         //arrow.set(align[2], 
14067         
14068         this.el.addClass('in');
14069         this.hoverState = null;
14070         
14071         if (this.el.hasClass('fade')) {
14072             // fade it?
14073         }
14074         
14075     },
14076     hide : function()
14077     {
14078         this.el.setXY([0,0]);
14079         this.el.removeClass('in');
14080         this.el.hide();
14081         
14082     }
14083     
14084 });
14085
14086 Roo.bootstrap.Popover.alignment = {
14087     'left' : ['r-l', [-10,0], 'right'],
14088     'right' : ['l-r', [10,0], 'left'],
14089     'bottom' : ['t-b', [0,10], 'top'],
14090     'top' : [ 'b-t', [0,-10], 'bottom']
14091 };
14092
14093  /*
14094  * - LGPL
14095  *
14096  * Progress
14097  * 
14098  */
14099
14100 /**
14101  * @class Roo.bootstrap.Progress
14102  * @extends Roo.bootstrap.Component
14103  * Bootstrap Progress class
14104  * @cfg {Boolean} striped striped of the progress bar
14105  * @cfg {Boolean} active animated of the progress bar
14106  * 
14107  * 
14108  * @constructor
14109  * Create a new Progress
14110  * @param {Object} config The config object
14111  */
14112
14113 Roo.bootstrap.Progress = function(config){
14114     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14115 };
14116
14117 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14118     
14119     striped : false,
14120     active: false,
14121     
14122     getAutoCreate : function(){
14123         var cfg = {
14124             tag: 'div',
14125             cls: 'progress'
14126         };
14127         
14128         
14129         if(this.striped){
14130             cfg.cls += ' progress-striped';
14131         }
14132       
14133         if(this.active){
14134             cfg.cls += ' active';
14135         }
14136         
14137         
14138         return cfg;
14139     }
14140    
14141 });
14142
14143  
14144
14145  /*
14146  * - LGPL
14147  *
14148  * ProgressBar
14149  * 
14150  */
14151
14152 /**
14153  * @class Roo.bootstrap.ProgressBar
14154  * @extends Roo.bootstrap.Component
14155  * Bootstrap ProgressBar class
14156  * @cfg {Number} aria_valuenow aria-value now
14157  * @cfg {Number} aria_valuemin aria-value min
14158  * @cfg {Number} aria_valuemax aria-value max
14159  * @cfg {String} label label for the progress bar
14160  * @cfg {String} panel (success | info | warning | danger )
14161  * @cfg {String} role role of the progress bar
14162  * @cfg {String} sr_only text
14163  * 
14164  * 
14165  * @constructor
14166  * Create a new ProgressBar
14167  * @param {Object} config The config object
14168  */
14169
14170 Roo.bootstrap.ProgressBar = function(config){
14171     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14172 };
14173
14174 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14175     
14176     aria_valuenow : 0,
14177     aria_valuemin : 0,
14178     aria_valuemax : 100,
14179     label : false,
14180     panel : false,
14181     role : false,
14182     sr_only: false,
14183     
14184     getAutoCreate : function()
14185     {
14186         
14187         var cfg = {
14188             tag: 'div',
14189             cls: 'progress-bar',
14190             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14191         };
14192         
14193         if(this.sr_only){
14194             cfg.cn = {
14195                 tag: 'span',
14196                 cls: 'sr-only',
14197                 html: this.sr_only
14198             }
14199         }
14200         
14201         if(this.role){
14202             cfg.role = this.role;
14203         }
14204         
14205         if(this.aria_valuenow){
14206             cfg['aria-valuenow'] = this.aria_valuenow;
14207         }
14208         
14209         if(this.aria_valuemin){
14210             cfg['aria-valuemin'] = this.aria_valuemin;
14211         }
14212         
14213         if(this.aria_valuemax){
14214             cfg['aria-valuemax'] = this.aria_valuemax;
14215         }
14216         
14217         if(this.label && !this.sr_only){
14218             cfg.html = this.label;
14219         }
14220         
14221         if(this.panel){
14222             cfg.cls += ' progress-bar-' + this.panel;
14223         }
14224         
14225         return cfg;
14226     },
14227     
14228     update : function(aria_valuenow)
14229     {
14230         this.aria_valuenow = aria_valuenow;
14231         
14232         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14233     }
14234    
14235 });
14236
14237  
14238
14239  /*
14240  * - LGPL
14241  *
14242  * column
14243  * 
14244  */
14245
14246 /**
14247  * @class Roo.bootstrap.TabGroup
14248  * @extends Roo.bootstrap.Column
14249  * Bootstrap Column class
14250  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14251  * @cfg {Boolean} carousel true to make the group behave like a carousel
14252  * 
14253  * @constructor
14254  * Create a new TabGroup
14255  * @param {Object} config The config object
14256  */
14257
14258 Roo.bootstrap.TabGroup = function(config){
14259     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14260     if (!this.navId) {
14261         this.navId = Roo.id();
14262     }
14263     this.tabs = [];
14264     Roo.bootstrap.TabGroup.register(this);
14265     
14266 };
14267
14268 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14269     
14270     carousel : false,
14271     transition : false,
14272      
14273     getAutoCreate : function()
14274     {
14275         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14276         
14277         cfg.cls += ' tab-content';
14278         
14279         if (this.carousel) {
14280             cfg.cls += ' carousel slide';
14281             cfg.cn = [{
14282                cls : 'carousel-inner'
14283             }]
14284         }
14285         
14286         
14287         return cfg;
14288     },
14289     getChildContainer : function()
14290     {
14291         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14292     },
14293     
14294     /**
14295     * register a Navigation item
14296     * @param {Roo.bootstrap.NavItem} the navitem to add
14297     */
14298     register : function(item)
14299     {
14300         this.tabs.push( item);
14301         item.navId = this.navId; // not really needed..
14302     
14303     },
14304     
14305     getActivePanel : function()
14306     {
14307         var r = false;
14308         Roo.each(this.tabs, function(t) {
14309             if (t.active) {
14310                 r = t;
14311                 return false;
14312             }
14313             return null;
14314         });
14315         return r;
14316         
14317     },
14318     getPanelByName : function(n)
14319     {
14320         var r = false;
14321         Roo.each(this.tabs, function(t) {
14322             if (t.tabId == n) {
14323                 r = t;
14324                 return false;
14325             }
14326             return null;
14327         });
14328         return r;
14329     },
14330     indexOfPanel : function(p)
14331     {
14332         var r = false;
14333         Roo.each(this.tabs, function(t,i) {
14334             if (t.tabId == p.tabId) {
14335                 r = i;
14336                 return false;
14337             }
14338             return null;
14339         });
14340         return r;
14341     },
14342     /**
14343      * show a specific panel
14344      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14345      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14346      */
14347     showPanel : function (pan)
14348     {
14349         
14350         if (typeof(pan) == 'number') {
14351             pan = this.tabs[pan];
14352         }
14353         if (typeof(pan) == 'string') {
14354             pan = this.getPanelByName(pan);
14355         }
14356         if (pan.tabId == this.getActivePanel().tabId) {
14357             return true;
14358         }
14359         var cur = this.getActivePanel();
14360         
14361         if (false === cur.fireEvent('beforedeactivate')) {
14362             return false;
14363         }
14364         
14365         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14366             
14367             this.transition = true;
14368             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14369             var lr = dir == 'next' ? 'left' : 'right';
14370             pan.el.addClass(dir); // or prev
14371             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14372             cur.el.addClass(lr); // or right
14373             pan.el.addClass(lr);
14374             
14375             var _this = this;
14376             cur.el.on('transitionend', function() {
14377                 Roo.log("trans end?");
14378                 
14379                 pan.el.removeClass([lr,dir]);
14380                 pan.setActive(true);
14381                 
14382                 cur.el.removeClass([lr]);
14383                 cur.setActive(false);
14384                 
14385                 _this.transition = false;
14386                 
14387             }, this, { single:  true } );
14388             return true;
14389         }
14390         
14391         cur.setActive(false);
14392         pan.setActive(true);
14393         return true;
14394         
14395     },
14396     showPanelNext : function()
14397     {
14398         var i = this.indexOfPanel(this.getActivePanel());
14399         if (i > this.tabs.length) {
14400             return;
14401         }
14402         this.showPanel(this.tabs[i+1]);
14403     },
14404     showPanelPrev : function()
14405     {
14406         var i = this.indexOfPanel(this.getActivePanel());
14407         if (i  < 1) {
14408             return;
14409         }
14410         this.showPanel(this.tabs[i-1]);
14411     }
14412     
14413     
14414   
14415 });
14416
14417  
14418
14419  
14420  
14421 Roo.apply(Roo.bootstrap.TabGroup, {
14422     
14423     groups: {},
14424      /**
14425     * register a Navigation Group
14426     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14427     */
14428     register : function(navgrp)
14429     {
14430         this.groups[navgrp.navId] = navgrp;
14431         
14432     },
14433     /**
14434     * fetch a Navigation Group based on the navigation ID
14435     * if one does not exist , it will get created.
14436     * @param {string} the navgroup to add
14437     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14438     */
14439     get: function(navId) {
14440         if (typeof(this.groups[navId]) == 'undefined') {
14441             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14442         }
14443         return this.groups[navId] ;
14444     }
14445     
14446     
14447     
14448 });
14449
14450  /*
14451  * - LGPL
14452  *
14453  * TabPanel
14454  * 
14455  */
14456
14457 /**
14458  * @class Roo.bootstrap.TabPanel
14459  * @extends Roo.bootstrap.Component
14460  * Bootstrap TabPanel class
14461  * @cfg {Boolean} active panel active
14462  * @cfg {String} html panel content
14463  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14464  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14465  * 
14466  * 
14467  * @constructor
14468  * Create a new TabPanel
14469  * @param {Object} config The config object
14470  */
14471
14472 Roo.bootstrap.TabPanel = function(config){
14473     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14474     this.addEvents({
14475         /**
14476              * @event changed
14477              * Fires when the active status changes
14478              * @param {Roo.bootstrap.TabPanel} this
14479              * @param {Boolean} state the new state
14480             
14481          */
14482         'changed': true,
14483         /**
14484              * @event beforedeactivate
14485              * Fires before a tab is de-activated - can be used to do validation on a form.
14486              * @param {Roo.bootstrap.TabPanel} this
14487              * @return {Boolean} false if there is an error
14488             
14489          */
14490         'beforedeactivate': true
14491      });
14492     
14493     this.tabId = this.tabId || Roo.id();
14494   
14495 };
14496
14497 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14498     
14499     active: false,
14500     html: false,
14501     tabId: false,
14502     navId : false,
14503     
14504     getAutoCreate : function(){
14505         var cfg = {
14506             tag: 'div',
14507             // item is needed for carousel - not sure if it has any effect otherwise
14508             cls: 'tab-pane item',
14509             html: this.html || ''
14510         };
14511         
14512         if(this.active){
14513             cfg.cls += ' active';
14514         }
14515         
14516         if(this.tabId){
14517             cfg.tabId = this.tabId;
14518         }
14519         
14520         
14521         return cfg;
14522     },
14523     
14524     initEvents:  function()
14525     {
14526         Roo.log('-------- init events on tab panel ---------');
14527         
14528         var p = this.parent();
14529         this.navId = this.navId || p.navId;
14530         
14531         if (typeof(this.navId) != 'undefined') {
14532             // not really needed.. but just in case.. parent should be a NavGroup.
14533             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14534             Roo.log(['register', tg, this]);
14535             tg.register(this);
14536         }
14537     },
14538     
14539     
14540     onRender : function(ct, position)
14541     {
14542        // Roo.log("Call onRender: " + this.xtype);
14543         
14544         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14545         
14546         
14547         
14548         
14549         
14550     },
14551     
14552     setActive: function(state)
14553     {
14554         Roo.log("panel - set active " + this.tabId + "=" + state);
14555         
14556         this.active = state;
14557         if (!state) {
14558             this.el.removeClass('active');
14559             
14560         } else  if (!this.el.hasClass('active')) {
14561             this.el.addClass('active');
14562         }
14563         this.fireEvent('changed', this, state);
14564     }
14565     
14566     
14567 });
14568  
14569
14570  
14571
14572  /*
14573  * - LGPL
14574  *
14575  * DateField
14576  * 
14577  */
14578
14579 /**
14580  * @class Roo.bootstrap.DateField
14581  * @extends Roo.bootstrap.Input
14582  * Bootstrap DateField class
14583  * @cfg {Number} weekStart default 0
14584  * @cfg {String} viewMode default empty, (months|years)
14585  * @cfg {String} minViewMode default empty, (months|years)
14586  * @cfg {Number} startDate default -Infinity
14587  * @cfg {Number} endDate default Infinity
14588  * @cfg {Boolean} todayHighlight default false
14589  * @cfg {Boolean} todayBtn default false
14590  * @cfg {Boolean} calendarWeeks default false
14591  * @cfg {Object} daysOfWeekDisabled default empty
14592  * @cfg {Boolean} singleMode default false (true | false)
14593  * 
14594  * @cfg {Boolean} keyboardNavigation default true
14595  * @cfg {String} language default en
14596  * 
14597  * @constructor
14598  * Create a new DateField
14599  * @param {Object} config The config object
14600  */
14601
14602 Roo.bootstrap.DateField = function(config){
14603     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14604      this.addEvents({
14605             /**
14606              * @event show
14607              * Fires when this field show.
14608              * @param {Roo.bootstrap.DateField} this
14609              * @param {Mixed} date The date value
14610              */
14611             show : true,
14612             /**
14613              * @event show
14614              * Fires when this field hide.
14615              * @param {Roo.bootstrap.DateField} this
14616              * @param {Mixed} date The date value
14617              */
14618             hide : true,
14619             /**
14620              * @event select
14621              * Fires when select a date.
14622              * @param {Roo.bootstrap.DateField} this
14623              * @param {Mixed} date The date value
14624              */
14625             select : true
14626         });
14627 };
14628
14629 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14630     
14631     /**
14632      * @cfg {String} format
14633      * The default date format string which can be overriden for localization support.  The format must be
14634      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14635      */
14636     format : "m/d/y",
14637     /**
14638      * @cfg {String} altFormats
14639      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14640      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14641      */
14642     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14643     
14644     weekStart : 0,
14645     
14646     viewMode : '',
14647     
14648     minViewMode : '',
14649     
14650     todayHighlight : false,
14651     
14652     todayBtn: false,
14653     
14654     language: 'en',
14655     
14656     keyboardNavigation: true,
14657     
14658     calendarWeeks: false,
14659     
14660     startDate: -Infinity,
14661     
14662     endDate: Infinity,
14663     
14664     daysOfWeekDisabled: [],
14665     
14666     _events: [],
14667     
14668     singleMode : false,
14669     
14670     UTCDate: function()
14671     {
14672         return new Date(Date.UTC.apply(Date, arguments));
14673     },
14674     
14675     UTCToday: function()
14676     {
14677         var today = new Date();
14678         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14679     },
14680     
14681     getDate: function() {
14682             var d = this.getUTCDate();
14683             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14684     },
14685     
14686     getUTCDate: function() {
14687             return this.date;
14688     },
14689     
14690     setDate: function(d) {
14691             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14692     },
14693     
14694     setUTCDate: function(d) {
14695             this.date = d;
14696             this.setValue(this.formatDate(this.date));
14697     },
14698         
14699     onRender: function(ct, position)
14700     {
14701         
14702         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14703         
14704         this.language = this.language || 'en';
14705         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14706         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14707         
14708         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14709         this.format = this.format || 'm/d/y';
14710         this.isInline = false;
14711         this.isInput = true;
14712         this.component = this.el.select('.add-on', true).first() || false;
14713         this.component = (this.component && this.component.length === 0) ? false : this.component;
14714         this.hasInput = this.component && this.inputEL().length;
14715         
14716         if (typeof(this.minViewMode === 'string')) {
14717             switch (this.minViewMode) {
14718                 case 'months':
14719                     this.minViewMode = 1;
14720                     break;
14721                 case 'years':
14722                     this.minViewMode = 2;
14723                     break;
14724                 default:
14725                     this.minViewMode = 0;
14726                     break;
14727             }
14728         }
14729         
14730         if (typeof(this.viewMode === 'string')) {
14731             switch (this.viewMode) {
14732                 case 'months':
14733                     this.viewMode = 1;
14734                     break;
14735                 case 'years':
14736                     this.viewMode = 2;
14737                     break;
14738                 default:
14739                     this.viewMode = 0;
14740                     break;
14741             }
14742         }
14743                 
14744         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
14745         
14746 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
14747         
14748         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14749         
14750         this.picker().on('mousedown', this.onMousedown, this);
14751         this.picker().on('click', this.onClick, this);
14752         
14753         this.picker().addClass('datepicker-dropdown');
14754         
14755         this.startViewMode = this.viewMode;
14756         
14757         if(this.singleMode){
14758             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
14759                 v.setVisibilityMode(Roo.Element.DISPLAY)
14760                 v.hide();
14761             })
14762             
14763             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
14764                 v.setStyle('width', '189px');
14765             });
14766         }
14767         
14768         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
14769             if(!this.calendarWeeks){
14770                 v.remove();
14771                 return;
14772             };
14773             
14774             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
14775             v.attr('colspan', function(i, val){
14776                 return parseInt(val) + 1;
14777             });
14778         })
14779                         
14780         
14781         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
14782         
14783         this.setStartDate(this.startDate);
14784         this.setEndDate(this.endDate);
14785         
14786         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
14787         
14788         this.fillDow();
14789         this.fillMonths();
14790         this.update();
14791         this.showMode();
14792         
14793         if(this.isInline) {
14794             this.show();
14795         }
14796     },
14797     
14798     picker : function()
14799     {
14800         return this.pickerEl;
14801 //        return this.el.select('.datepicker', true).first();
14802     },
14803     
14804     fillDow: function()
14805     {
14806         var dowCnt = this.weekStart;
14807         
14808         var dow = {
14809             tag: 'tr',
14810             cn: [
14811                 
14812             ]
14813         };
14814         
14815         if(this.calendarWeeks){
14816             dow.cn.push({
14817                 tag: 'th',
14818                 cls: 'cw',
14819                 html: '&nbsp;'
14820             })
14821         }
14822         
14823         while (dowCnt < this.weekStart + 7) {
14824             dow.cn.push({
14825                 tag: 'th',
14826                 cls: 'dow',
14827                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
14828             });
14829         }
14830         
14831         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
14832     },
14833     
14834     fillMonths: function()
14835     {    
14836         var i = 0
14837         var months = this.picker().select('>.datepicker-months td', true).first();
14838         
14839         months.dom.innerHTML = '';
14840         
14841         while (i < 12) {
14842             var month = {
14843                 tag: 'span',
14844                 cls: 'month',
14845                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
14846             }
14847             
14848             months.createChild(month);
14849         }
14850         
14851     },
14852     
14853     update: function()
14854     {
14855         this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
14856         
14857         if (this.date < this.startDate) {
14858             this.viewDate = new Date(this.startDate);
14859         } else if (this.date > this.endDate) {
14860             this.viewDate = new Date(this.endDate);
14861         } else {
14862             this.viewDate = new Date(this.date);
14863         }
14864         
14865         this.fill();
14866     },
14867     
14868     fill: function() 
14869     {
14870         var d = new Date(this.viewDate),
14871                 year = d.getUTCFullYear(),
14872                 month = d.getUTCMonth(),
14873                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
14874                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
14875                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
14876                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
14877                 currentDate = this.date && this.date.valueOf(),
14878                 today = this.UTCToday();
14879         
14880         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
14881         
14882 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
14883         
14884 //        this.picker.select('>tfoot th.today').
14885 //                                              .text(dates[this.language].today)
14886 //                                              .toggle(this.todayBtn !== false);
14887     
14888         this.updateNavArrows();
14889         this.fillMonths();
14890                                                 
14891         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
14892         
14893         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
14894          
14895         prevMonth.setUTCDate(day);
14896         
14897         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
14898         
14899         var nextMonth = new Date(prevMonth);
14900         
14901         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
14902         
14903         nextMonth = nextMonth.valueOf();
14904         
14905         var fillMonths = false;
14906         
14907         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
14908         
14909         while(prevMonth.valueOf() < nextMonth) {
14910             var clsName = '';
14911             
14912             if (prevMonth.getUTCDay() === this.weekStart) {
14913                 if(fillMonths){
14914                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
14915                 }
14916                     
14917                 fillMonths = {
14918                     tag: 'tr',
14919                     cn: []
14920                 };
14921                 
14922                 if(this.calendarWeeks){
14923                     // ISO 8601: First week contains first thursday.
14924                     // ISO also states week starts on Monday, but we can be more abstract here.
14925                     var
14926                     // Start of current week: based on weekstart/current date
14927                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
14928                     // Thursday of this week
14929                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
14930                     // First Thursday of year, year from thursday
14931                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
14932                     // Calendar week: ms between thursdays, div ms per day, div 7 days
14933                     calWeek =  (th - yth) / 864e5 / 7 + 1;
14934                     
14935                     fillMonths.cn.push({
14936                         tag: 'td',
14937                         cls: 'cw',
14938                         html: calWeek
14939                     });
14940                 }
14941             }
14942             
14943             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
14944                 clsName += ' old';
14945             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
14946                 clsName += ' new';
14947             }
14948             if (this.todayHighlight &&
14949                 prevMonth.getUTCFullYear() == today.getFullYear() &&
14950                 prevMonth.getUTCMonth() == today.getMonth() &&
14951                 prevMonth.getUTCDate() == today.getDate()) {
14952                 clsName += ' today';
14953             }
14954             
14955             if (currentDate && prevMonth.valueOf() === currentDate) {
14956                 clsName += ' active';
14957             }
14958             
14959             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
14960                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
14961                     clsName += ' disabled';
14962             }
14963             
14964             fillMonths.cn.push({
14965                 tag: 'td',
14966                 cls: 'day ' + clsName,
14967                 html: prevMonth.getDate()
14968             })
14969             
14970             prevMonth.setDate(prevMonth.getDate()+1);
14971         }
14972           
14973         var currentYear = this.date && this.date.getUTCFullYear();
14974         var currentMonth = this.date && this.date.getUTCMonth();
14975         
14976         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
14977         
14978         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
14979             v.removeClass('active');
14980             
14981             if(currentYear === year && k === currentMonth){
14982                 v.addClass('active');
14983             }
14984             
14985             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
14986                 v.addClass('disabled');
14987             }
14988             
14989         });
14990         
14991         
14992         year = parseInt(year/10, 10) * 10;
14993         
14994         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
14995         
14996         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
14997         
14998         year -= 1;
14999         for (var i = -1; i < 11; i++) {
15000             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15001                 tag: 'span',
15002                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15003                 html: year
15004             })
15005             
15006             year += 1;
15007         }
15008     },
15009     
15010     showMode: function(dir) 
15011     {
15012         if (dir) {
15013             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15014         }
15015         
15016         Roo.each(this.picker().select('>div',true).elements, function(v){
15017             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15018             v.hide();
15019         });
15020         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15021     },
15022     
15023     place: function()
15024     {
15025         if(this.isInline) return;
15026         
15027         this.picker().removeClass(['bottom', 'top']);
15028         
15029         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15030             /*
15031              * place to the top of element!
15032              *
15033              */
15034             
15035             this.picker().addClass('top');
15036             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15037             
15038             return;
15039         }
15040         
15041         this.picker().addClass('bottom');
15042         
15043         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15044     },
15045     
15046     parseDate : function(value)
15047     {
15048         if(!value || value instanceof Date){
15049             return value;
15050         }
15051         var v = Date.parseDate(value, this.format);
15052         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15053             v = Date.parseDate(value, 'Y-m-d');
15054         }
15055         if(!v && this.altFormats){
15056             if(!this.altFormatsArray){
15057                 this.altFormatsArray = this.altFormats.split("|");
15058             }
15059             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15060                 v = Date.parseDate(value, this.altFormatsArray[i]);
15061             }
15062         }
15063         return v;
15064     },
15065     
15066     formatDate : function(date, fmt)
15067     {   
15068         return (!date || !(date instanceof Date)) ?
15069         date : date.dateFormat(fmt || this.format);
15070     },
15071     
15072     onFocus : function()
15073     {
15074         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15075         this.show();
15076     },
15077     
15078     onBlur : function()
15079     {
15080         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15081         
15082         var d = this.inputEl().getValue();
15083         
15084         this.setValue(d);
15085                 
15086         this.hide();
15087     },
15088     
15089     show : function()
15090     {
15091         this.picker().show();
15092         this.update();
15093         this.place();
15094         
15095         this.fireEvent('show', this, this.date);
15096     },
15097     
15098     hide : function()
15099     {
15100         if(this.isInline) return;
15101         this.picker().hide();
15102         this.viewMode = this.startViewMode;
15103         this.showMode();
15104         
15105         this.fireEvent('hide', this, this.date);
15106         
15107     },
15108     
15109     onMousedown: function(e)
15110     {
15111         e.stopPropagation();
15112         e.preventDefault();
15113     },
15114     
15115     keyup: function(e)
15116     {
15117         Roo.bootstrap.DateField.superclass.keyup.call(this);
15118         this.update();
15119     },
15120
15121     setValue: function(v)
15122     {
15123         
15124         // v can be a string or a date..
15125         
15126         
15127         var d = new Date(this.parseDate(v) ).clearTime();
15128         
15129         if(isNaN(d.getTime())){
15130             this.date = this.viewDate = '';
15131             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15132             return;
15133         }
15134         
15135         v = this.formatDate(d);
15136         
15137         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15138         
15139         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15140      
15141         this.update();
15142
15143         this.fireEvent('select', this, this.date);
15144         
15145     },
15146     
15147     getValue: function()
15148     {
15149         return this.formatDate(this.date);
15150     },
15151     
15152     fireKey: function(e)
15153     {
15154         if (!this.picker().isVisible()){
15155             if (e.keyCode == 27) // allow escape to hide and re-show picker
15156                 this.show();
15157             return;
15158         }
15159         
15160         var dateChanged = false,
15161         dir, day, month,
15162         newDate, newViewDate;
15163         
15164         switch(e.keyCode){
15165             case 27: // escape
15166                 this.hide();
15167                 e.preventDefault();
15168                 break;
15169             case 37: // left
15170             case 39: // right
15171                 if (!this.keyboardNavigation) break;
15172                 dir = e.keyCode == 37 ? -1 : 1;
15173                 
15174                 if (e.ctrlKey){
15175                     newDate = this.moveYear(this.date, dir);
15176                     newViewDate = this.moveYear(this.viewDate, dir);
15177                 } else if (e.shiftKey){
15178                     newDate = this.moveMonth(this.date, dir);
15179                     newViewDate = this.moveMonth(this.viewDate, dir);
15180                 } else {
15181                     newDate = new Date(this.date);
15182                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15183                     newViewDate = new Date(this.viewDate);
15184                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15185                 }
15186                 if (this.dateWithinRange(newDate)){
15187                     this.date = newDate;
15188                     this.viewDate = newViewDate;
15189                     this.setValue(this.formatDate(this.date));
15190 //                    this.update();
15191                     e.preventDefault();
15192                     dateChanged = true;
15193                 }
15194                 break;
15195             case 38: // up
15196             case 40: // down
15197                 if (!this.keyboardNavigation) break;
15198                 dir = e.keyCode == 38 ? -1 : 1;
15199                 if (e.ctrlKey){
15200                     newDate = this.moveYear(this.date, dir);
15201                     newViewDate = this.moveYear(this.viewDate, dir);
15202                 } else if (e.shiftKey){
15203                     newDate = this.moveMonth(this.date, dir);
15204                     newViewDate = this.moveMonth(this.viewDate, dir);
15205                 } else {
15206                     newDate = new Date(this.date);
15207                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15208                     newViewDate = new Date(this.viewDate);
15209                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15210                 }
15211                 if (this.dateWithinRange(newDate)){
15212                     this.date = newDate;
15213                     this.viewDate = newViewDate;
15214                     this.setValue(this.formatDate(this.date));
15215 //                    this.update();
15216                     e.preventDefault();
15217                     dateChanged = true;
15218                 }
15219                 break;
15220             case 13: // enter
15221                 this.setValue(this.formatDate(this.date));
15222                 this.hide();
15223                 e.preventDefault();
15224                 break;
15225             case 9: // tab
15226                 this.setValue(this.formatDate(this.date));
15227                 this.hide();
15228                 break;
15229             case 16: // shift
15230             case 17: // ctrl
15231             case 18: // alt
15232                 break;
15233             default :
15234                 this.hide();
15235                 
15236         }
15237     },
15238     
15239     
15240     onClick: function(e) 
15241     {
15242         e.stopPropagation();
15243         e.preventDefault();
15244         
15245         var target = e.getTarget();
15246         
15247         if(target.nodeName.toLowerCase() === 'i'){
15248             target = Roo.get(target).dom.parentNode;
15249         }
15250         
15251         var nodeName = target.nodeName;
15252         var className = target.className;
15253         var html = target.innerHTML;
15254         //Roo.log(nodeName);
15255         
15256         switch(nodeName.toLowerCase()) {
15257             case 'th':
15258                 switch(className) {
15259                     case 'switch':
15260                         this.showMode(1);
15261                         break;
15262                     case 'prev':
15263                     case 'next':
15264                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15265                         switch(this.viewMode){
15266                                 case 0:
15267                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15268                                         break;
15269                                 case 1:
15270                                 case 2:
15271                                         this.viewDate = this.moveYear(this.viewDate, dir);
15272                                         break;
15273                         }
15274                         this.fill();
15275                         break;
15276                     case 'today':
15277                         var date = new Date();
15278                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15279 //                        this.fill()
15280                         this.setValue(this.formatDate(this.date));
15281                         
15282                         this.hide();
15283                         break;
15284                 }
15285                 break;
15286             case 'span':
15287                 if (className.indexOf('disabled') < 0) {
15288                     this.viewDate.setUTCDate(1);
15289                     if (className.indexOf('month') > -1) {
15290                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15291                     } else {
15292                         var year = parseInt(html, 10) || 0;
15293                         this.viewDate.setUTCFullYear(year);
15294                         
15295                     }
15296                     
15297                     if(this.singleMode){
15298                         this.setValue(this.formatDate(this.viewDate));
15299                         this.hide();
15300                         return;
15301                     }
15302                     
15303                     this.showMode(-1);
15304                     this.fill();
15305                 }
15306                 break;
15307                 
15308             case 'td':
15309                 //Roo.log(className);
15310                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15311                     var day = parseInt(html, 10) || 1;
15312                     var year = this.viewDate.getUTCFullYear(),
15313                         month = this.viewDate.getUTCMonth();
15314
15315                     if (className.indexOf('old') > -1) {
15316                         if(month === 0 ){
15317                             month = 11;
15318                             year -= 1;
15319                         }else{
15320                             month -= 1;
15321                         }
15322                     } else if (className.indexOf('new') > -1) {
15323                         if (month == 11) {
15324                             month = 0;
15325                             year += 1;
15326                         } else {
15327                             month += 1;
15328                         }
15329                     }
15330                     //Roo.log([year,month,day]);
15331                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15332                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15333 //                    this.fill();
15334                     //Roo.log(this.formatDate(this.date));
15335                     this.setValue(this.formatDate(this.date));
15336                     this.hide();
15337                 }
15338                 break;
15339         }
15340     },
15341     
15342     setStartDate: function(startDate)
15343     {
15344         this.startDate = startDate || -Infinity;
15345         if (this.startDate !== -Infinity) {
15346             this.startDate = this.parseDate(this.startDate);
15347         }
15348         this.update();
15349         this.updateNavArrows();
15350     },
15351
15352     setEndDate: function(endDate)
15353     {
15354         this.endDate = endDate || Infinity;
15355         if (this.endDate !== Infinity) {
15356             this.endDate = this.parseDate(this.endDate);
15357         }
15358         this.update();
15359         this.updateNavArrows();
15360     },
15361     
15362     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15363     {
15364         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15365         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15366             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15367         }
15368         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15369             return parseInt(d, 10);
15370         });
15371         this.update();
15372         this.updateNavArrows();
15373     },
15374     
15375     updateNavArrows: function() 
15376     {
15377         if(this.singleMode){
15378             return;
15379         }
15380         
15381         var d = new Date(this.viewDate),
15382         year = d.getUTCFullYear(),
15383         month = d.getUTCMonth();
15384         
15385         Roo.each(this.picker().select('.prev', true).elements, function(v){
15386             v.show();
15387             switch (this.viewMode) {
15388                 case 0:
15389
15390                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15391                         v.hide();
15392                     }
15393                     break;
15394                 case 1:
15395                 case 2:
15396                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15397                         v.hide();
15398                     }
15399                     break;
15400             }
15401         });
15402         
15403         Roo.each(this.picker().select('.next', true).elements, function(v){
15404             v.show();
15405             switch (this.viewMode) {
15406                 case 0:
15407
15408                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15409                         v.hide();
15410                     }
15411                     break;
15412                 case 1:
15413                 case 2:
15414                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15415                         v.hide();
15416                     }
15417                     break;
15418             }
15419         })
15420     },
15421     
15422     moveMonth: function(date, dir)
15423     {
15424         if (!dir) return date;
15425         var new_date = new Date(date.valueOf()),
15426         day = new_date.getUTCDate(),
15427         month = new_date.getUTCMonth(),
15428         mag = Math.abs(dir),
15429         new_month, test;
15430         dir = dir > 0 ? 1 : -1;
15431         if (mag == 1){
15432             test = dir == -1
15433             // If going back one month, make sure month is not current month
15434             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15435             ? function(){
15436                 return new_date.getUTCMonth() == month;
15437             }
15438             // If going forward one month, make sure month is as expected
15439             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15440             : function(){
15441                 return new_date.getUTCMonth() != new_month;
15442             };
15443             new_month = month + dir;
15444             new_date.setUTCMonth(new_month);
15445             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15446             if (new_month < 0 || new_month > 11)
15447                 new_month = (new_month + 12) % 12;
15448         } else {
15449             // For magnitudes >1, move one month at a time...
15450             for (var i=0; i<mag; i++)
15451                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15452                 new_date = this.moveMonth(new_date, dir);
15453             // ...then reset the day, keeping it in the new month
15454             new_month = new_date.getUTCMonth();
15455             new_date.setUTCDate(day);
15456             test = function(){
15457                 return new_month != new_date.getUTCMonth();
15458             };
15459         }
15460         // Common date-resetting loop -- if date is beyond end of month, make it
15461         // end of month
15462         while (test()){
15463             new_date.setUTCDate(--day);
15464             new_date.setUTCMonth(new_month);
15465         }
15466         return new_date;
15467     },
15468
15469     moveYear: function(date, dir)
15470     {
15471         return this.moveMonth(date, dir*12);
15472     },
15473
15474     dateWithinRange: function(date)
15475     {
15476         return date >= this.startDate && date <= this.endDate;
15477     },
15478
15479     
15480     remove: function() 
15481     {
15482         this.picker().remove();
15483     }
15484    
15485 });
15486
15487 Roo.apply(Roo.bootstrap.DateField,  {
15488     
15489     head : {
15490         tag: 'thead',
15491         cn: [
15492         {
15493             tag: 'tr',
15494             cn: [
15495             {
15496                 tag: 'th',
15497                 cls: 'prev',
15498                 html: '<i class="fa fa-arrow-left"/>'
15499             },
15500             {
15501                 tag: 'th',
15502                 cls: 'switch',
15503                 colspan: '5'
15504             },
15505             {
15506                 tag: 'th',
15507                 cls: 'next',
15508                 html: '<i class="fa fa-arrow-right"/>'
15509             }
15510
15511             ]
15512         }
15513         ]
15514     },
15515     
15516     content : {
15517         tag: 'tbody',
15518         cn: [
15519         {
15520             tag: 'tr',
15521             cn: [
15522             {
15523                 tag: 'td',
15524                 colspan: '7'
15525             }
15526             ]
15527         }
15528         ]
15529     },
15530     
15531     footer : {
15532         tag: 'tfoot',
15533         cn: [
15534         {
15535             tag: 'tr',
15536             cn: [
15537             {
15538                 tag: 'th',
15539                 colspan: '7',
15540                 cls: 'today'
15541             }
15542                     
15543             ]
15544         }
15545         ]
15546     },
15547     
15548     dates:{
15549         en: {
15550             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15551             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15552             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15553             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15554             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15555             today: "Today"
15556         }
15557     },
15558     
15559     modes: [
15560     {
15561         clsName: 'days',
15562         navFnc: 'Month',
15563         navStep: 1
15564     },
15565     {
15566         clsName: 'months',
15567         navFnc: 'FullYear',
15568         navStep: 1
15569     },
15570     {
15571         clsName: 'years',
15572         navFnc: 'FullYear',
15573         navStep: 10
15574     }]
15575 });
15576
15577 Roo.apply(Roo.bootstrap.DateField,  {
15578   
15579     template : {
15580         tag: 'div',
15581         cls: 'datepicker dropdown-menu roo-dynamic',
15582         cn: [
15583         {
15584             tag: 'div',
15585             cls: 'datepicker-days',
15586             cn: [
15587             {
15588                 tag: 'table',
15589                 cls: 'table-condensed',
15590                 cn:[
15591                 Roo.bootstrap.DateField.head,
15592                 {
15593                     tag: 'tbody'
15594                 },
15595                 Roo.bootstrap.DateField.footer
15596                 ]
15597             }
15598             ]
15599         },
15600         {
15601             tag: 'div',
15602             cls: 'datepicker-months',
15603             cn: [
15604             {
15605                 tag: 'table',
15606                 cls: 'table-condensed',
15607                 cn:[
15608                 Roo.bootstrap.DateField.head,
15609                 Roo.bootstrap.DateField.content,
15610                 Roo.bootstrap.DateField.footer
15611                 ]
15612             }
15613             ]
15614         },
15615         {
15616             tag: 'div',
15617             cls: 'datepicker-years',
15618             cn: [
15619             {
15620                 tag: 'table',
15621                 cls: 'table-condensed',
15622                 cn:[
15623                 Roo.bootstrap.DateField.head,
15624                 Roo.bootstrap.DateField.content,
15625                 Roo.bootstrap.DateField.footer
15626                 ]
15627             }
15628             ]
15629         }
15630         ]
15631     }
15632 });
15633
15634  
15635
15636  /*
15637  * - LGPL
15638  *
15639  * TimeField
15640  * 
15641  */
15642
15643 /**
15644  * @class Roo.bootstrap.TimeField
15645  * @extends Roo.bootstrap.Input
15646  * Bootstrap DateField class
15647  * 
15648  * 
15649  * @constructor
15650  * Create a new TimeField
15651  * @param {Object} config The config object
15652  */
15653
15654 Roo.bootstrap.TimeField = function(config){
15655     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15656     this.addEvents({
15657             /**
15658              * @event show
15659              * Fires when this field show.
15660              * @param {Roo.bootstrap.DateField} this
15661              * @param {Mixed} date The date value
15662              */
15663             show : true,
15664             /**
15665              * @event show
15666              * Fires when this field hide.
15667              * @param {Roo.bootstrap.DateField} this
15668              * @param {Mixed} date The date value
15669              */
15670             hide : true,
15671             /**
15672              * @event select
15673              * Fires when select a date.
15674              * @param {Roo.bootstrap.DateField} this
15675              * @param {Mixed} date The date value
15676              */
15677             select : true
15678         });
15679 };
15680
15681 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15682     
15683     /**
15684      * @cfg {String} format
15685      * The default time format string which can be overriden for localization support.  The format must be
15686      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15687      */
15688     format : "H:i",
15689        
15690     onRender: function(ct, position)
15691     {
15692         
15693         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15694                 
15695         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15696         
15697         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15698         
15699         this.pop = this.picker().select('>.datepicker-time',true).first();
15700         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block' 
15701         
15702         this.picker().on('mousedown', this.onMousedown, this);
15703         this.picker().on('click', this.onClick, this);
15704         
15705         this.picker().addClass('datepicker-dropdown');
15706     
15707         this.fillTime();
15708         this.update();
15709             
15710         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15711         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15712         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15713         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15714         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15715         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15716
15717     },
15718     
15719     fireKey: function(e){
15720         if (!this.picker().isVisible()){
15721             if (e.keyCode == 27) // allow escape to hide and re-show picker
15722                 this.show();
15723             return;
15724         }
15725
15726         e.preventDefault();
15727         
15728         switch(e.keyCode){
15729             case 27: // escape
15730                 this.hide();
15731                 break;
15732             case 37: // left
15733             case 39: // right
15734                 this.onTogglePeriod();
15735                 break;
15736             case 38: // up
15737                 this.onIncrementMinutes();
15738                 break;
15739             case 40: // down
15740                 this.onDecrementMinutes();
15741                 break;
15742             case 13: // enter
15743             case 9: // tab
15744                 this.setTime();
15745                 break;
15746         }
15747     },
15748     
15749     onClick: function(e) {
15750         e.stopPropagation();
15751         e.preventDefault();
15752     },
15753     
15754     picker : function()
15755     {
15756         return this.el.select('.datepicker', true).first();
15757     },
15758     
15759     fillTime: function()
15760     {    
15761         var time = this.pop.select('tbody', true).first();
15762         
15763         time.dom.innerHTML = '';
15764         
15765         time.createChild({
15766             tag: 'tr',
15767             cn: [
15768                 {
15769                     tag: 'td',
15770                     cn: [
15771                         {
15772                             tag: 'a',
15773                             href: '#',
15774                             cls: 'btn',
15775                             cn: [
15776                                 {
15777                                     tag: 'span',
15778                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
15779                                 }
15780                             ]
15781                         } 
15782                     ]
15783                 },
15784                 {
15785                     tag: 'td',
15786                     cls: 'separator'
15787                 },
15788                 {
15789                     tag: 'td',
15790                     cn: [
15791                         {
15792                             tag: 'a',
15793                             href: '#',
15794                             cls: 'btn',
15795                             cn: [
15796                                 {
15797                                     tag: 'span',
15798                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
15799                                 }
15800                             ]
15801                         }
15802                     ]
15803                 },
15804                 {
15805                     tag: 'td',
15806                     cls: 'separator'
15807                 }
15808             ]
15809         });
15810         
15811         time.createChild({
15812             tag: 'tr',
15813             cn: [
15814                 {
15815                     tag: 'td',
15816                     cn: [
15817                         {
15818                             tag: 'span',
15819                             cls: 'timepicker-hour',
15820                             html: '00'
15821                         }  
15822                     ]
15823                 },
15824                 {
15825                     tag: 'td',
15826                     cls: 'separator',
15827                     html: ':'
15828                 },
15829                 {
15830                     tag: 'td',
15831                     cn: [
15832                         {
15833                             tag: 'span',
15834                             cls: 'timepicker-minute',
15835                             html: '00'
15836                         }  
15837                     ]
15838                 },
15839                 {
15840                     tag: 'td',
15841                     cls: 'separator'
15842                 },
15843                 {
15844                     tag: 'td',
15845                     cn: [
15846                         {
15847                             tag: 'button',
15848                             type: 'button',
15849                             cls: 'btn btn-primary period',
15850                             html: 'AM'
15851                             
15852                         }
15853                     ]
15854                 }
15855             ]
15856         });
15857         
15858         time.createChild({
15859             tag: 'tr',
15860             cn: [
15861                 {
15862                     tag: 'td',
15863                     cn: [
15864                         {
15865                             tag: 'a',
15866                             href: '#',
15867                             cls: 'btn',
15868                             cn: [
15869                                 {
15870                                     tag: 'span',
15871                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
15872                                 }
15873                             ]
15874                         }
15875                     ]
15876                 },
15877                 {
15878                     tag: 'td',
15879                     cls: 'separator'
15880                 },
15881                 {
15882                     tag: 'td',
15883                     cn: [
15884                         {
15885                             tag: 'a',
15886                             href: '#',
15887                             cls: 'btn',
15888                             cn: [
15889                                 {
15890                                     tag: 'span',
15891                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
15892                                 }
15893                             ]
15894                         }
15895                     ]
15896                 },
15897                 {
15898                     tag: 'td',
15899                     cls: 'separator'
15900                 }
15901             ]
15902         });
15903         
15904     },
15905     
15906     update: function()
15907     {
15908         
15909         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
15910         
15911         this.fill();
15912     },
15913     
15914     fill: function() 
15915     {
15916         var hours = this.time.getHours();
15917         var minutes = this.time.getMinutes();
15918         var period = 'AM';
15919         
15920         if(hours > 11){
15921             period = 'PM';
15922         }
15923         
15924         if(hours == 0){
15925             hours = 12;
15926         }
15927         
15928         
15929         if(hours > 12){
15930             hours = hours - 12;
15931         }
15932         
15933         if(hours < 10){
15934             hours = '0' + hours;
15935         }
15936         
15937         if(minutes < 10){
15938             minutes = '0' + minutes;
15939         }
15940         
15941         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
15942         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
15943         this.pop.select('button', true).first().dom.innerHTML = period;
15944         
15945     },
15946     
15947     place: function()
15948     {   
15949         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
15950         
15951         var cls = ['bottom'];
15952         
15953         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
15954             cls.pop();
15955             cls.push('top');
15956         }
15957         
15958         cls.push('right');
15959         
15960         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
15961             cls.pop();
15962             cls.push('left');
15963         }
15964         
15965         this.picker().addClass(cls.join('-'));
15966         
15967         var _this = this;
15968         
15969         Roo.each(cls, function(c){
15970             if(c == 'bottom'){
15971                 _this.picker().setTop(_this.inputEl().getHeight());
15972                 return;
15973             }
15974             if(c == 'top'){
15975                 _this.picker().setTop(0 - _this.picker().getHeight());
15976                 return;
15977             }
15978             
15979             if(c == 'left'){
15980                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
15981                 return;
15982             }
15983             if(c == 'right'){
15984                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
15985                 return;
15986             }
15987         });
15988         
15989     },
15990   
15991     onFocus : function()
15992     {
15993         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
15994         this.show();
15995     },
15996     
15997     onBlur : function()
15998     {
15999         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16000         this.hide();
16001     },
16002     
16003     show : function()
16004     {
16005         this.picker().show();
16006         this.pop.show();
16007         this.update();
16008         this.place();
16009         
16010         this.fireEvent('show', this, this.date);
16011     },
16012     
16013     hide : function()
16014     {
16015         this.picker().hide();
16016         this.pop.hide();
16017         
16018         this.fireEvent('hide', this, this.date);
16019     },
16020     
16021     setTime : function()
16022     {
16023         this.hide();
16024         this.setValue(this.time.format(this.format));
16025         
16026         this.fireEvent('select', this, this.date);
16027         
16028         
16029     },
16030     
16031     onMousedown: function(e){
16032         e.stopPropagation();
16033         e.preventDefault();
16034     },
16035     
16036     onIncrementHours: function()
16037     {
16038         Roo.log('onIncrementHours');
16039         this.time = this.time.add(Date.HOUR, 1);
16040         this.update();
16041         
16042     },
16043     
16044     onDecrementHours: function()
16045     {
16046         Roo.log('onDecrementHours');
16047         this.time = this.time.add(Date.HOUR, -1);
16048         this.update();
16049     },
16050     
16051     onIncrementMinutes: function()
16052     {
16053         Roo.log('onIncrementMinutes');
16054         this.time = this.time.add(Date.MINUTE, 1);
16055         this.update();
16056     },
16057     
16058     onDecrementMinutes: function()
16059     {
16060         Roo.log('onDecrementMinutes');
16061         this.time = this.time.add(Date.MINUTE, -1);
16062         this.update();
16063     },
16064     
16065     onTogglePeriod: function()
16066     {
16067         Roo.log('onTogglePeriod');
16068         this.time = this.time.add(Date.HOUR, 12);
16069         this.update();
16070     }
16071     
16072    
16073 });
16074
16075 Roo.apply(Roo.bootstrap.TimeField,  {
16076     
16077     content : {
16078         tag: 'tbody',
16079         cn: [
16080             {
16081                 tag: 'tr',
16082                 cn: [
16083                 {
16084                     tag: 'td',
16085                     colspan: '7'
16086                 }
16087                 ]
16088             }
16089         ]
16090     },
16091     
16092     footer : {
16093         tag: 'tfoot',
16094         cn: [
16095             {
16096                 tag: 'tr',
16097                 cn: [
16098                 {
16099                     tag: 'th',
16100                     colspan: '7',
16101                     cls: '',
16102                     cn: [
16103                         {
16104                             tag: 'button',
16105                             cls: 'btn btn-info ok',
16106                             html: 'OK'
16107                         }
16108                     ]
16109                 }
16110
16111                 ]
16112             }
16113         ]
16114     }
16115 });
16116
16117 Roo.apply(Roo.bootstrap.TimeField,  {
16118   
16119     template : {
16120         tag: 'div',
16121         cls: 'datepicker dropdown-menu',
16122         cn: [
16123             {
16124                 tag: 'div',
16125                 cls: 'datepicker-time',
16126                 cn: [
16127                 {
16128                     tag: 'table',
16129                     cls: 'table-condensed',
16130                     cn:[
16131                     Roo.bootstrap.TimeField.content,
16132                     Roo.bootstrap.TimeField.footer
16133                     ]
16134                 }
16135                 ]
16136             }
16137         ]
16138     }
16139 });
16140
16141  
16142
16143  /*
16144  * - LGPL
16145  *
16146  * CheckBox
16147  * 
16148  */
16149
16150 /**
16151  * @class Roo.bootstrap.CheckBox
16152  * @extends Roo.bootstrap.Input
16153  * Bootstrap CheckBox class
16154  * 
16155  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16156  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16157  * @cfg {String} boxLabel The text that appears beside the checkbox
16158  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16159  * @cfg {Boolean} checked initnal the element
16160  * @cfg {Boolean} inline inline the element (default false)
16161  * 
16162  * @constructor
16163  * Create a new CheckBox
16164  * @param {Object} config The config object
16165  */
16166
16167 Roo.bootstrap.CheckBox = function(config){
16168     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16169    
16170         this.addEvents({
16171             /**
16172             * @event check
16173             * Fires when the element is checked or unchecked.
16174             * @param {Roo.bootstrap.CheckBox} this This input
16175             * @param {Boolean} checked The new checked value
16176             */
16177            check : true
16178         });
16179 };
16180
16181 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16182     
16183     inputType: 'checkbox',
16184     inputValue: 1,
16185     valueOff: 0,
16186     boxLabel: false,
16187     checked: false,
16188     weight : false,
16189     inline: false,
16190     
16191     getAutoCreate : function()
16192     {
16193         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16194         
16195         var id = Roo.id();
16196         
16197         var cfg = {};
16198         
16199         cfg.cls = 'form-group ' + this.inputType //input-group
16200         
16201         if(this.inline){
16202             cfg.cls += ' ' + this.inputType + '-inline';
16203         }
16204         
16205         var input =  {
16206             tag: 'input',
16207             id : id,
16208             type : this.inputType,
16209             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16210             cls : 'roo-' + this.inputType, //'form-box',
16211             placeholder : this.placeholder || ''
16212             
16213         };
16214         
16215         if (this.weight) { // Validity check?
16216             cfg.cls += " " + this.inputType + "-" + this.weight;
16217         }
16218         
16219         if (this.disabled) {
16220             input.disabled=true;
16221         }
16222         
16223         if(this.checked){
16224             input.checked = this.checked;
16225         }
16226         
16227         if (this.name) {
16228             input.name = this.name;
16229         }
16230         
16231         if (this.size) {
16232             input.cls += ' input-' + this.size;
16233         }
16234         
16235         var settings=this;
16236         ['xs','sm','md','lg'].map(function(size){
16237             if (settings[size]) {
16238                 cfg.cls += ' col-' + size + '-' + settings[size];
16239             }
16240         });
16241         
16242        
16243         
16244         var inputblock = input;
16245         
16246         
16247         
16248         
16249         if (this.before || this.after) {
16250             
16251             inputblock = {
16252                 cls : 'input-group',
16253                 cn :  [] 
16254             };
16255             if (this.before) {
16256                 inputblock.cn.push({
16257                     tag :'span',
16258                     cls : 'input-group-addon',
16259                     html : this.before
16260                 });
16261             }
16262             inputblock.cn.push(input);
16263             if (this.after) {
16264                 inputblock.cn.push({
16265                     tag :'span',
16266                     cls : 'input-group-addon',
16267                     html : this.after
16268                 });
16269             }
16270             
16271         };
16272         
16273         if (align ==='left' && this.fieldLabel.length) {
16274                 Roo.log("left and has label");
16275                 cfg.cn = [
16276                     
16277                     {
16278                         tag: 'label',
16279                         'for' :  id,
16280                         cls : 'control-label col-md-' + this.labelWidth,
16281                         html : this.fieldLabel
16282                         
16283                     },
16284                     {
16285                         cls : "col-md-" + (12 - this.labelWidth), 
16286                         cn: [
16287                             inputblock
16288                         ]
16289                     }
16290                     
16291                 ];
16292         } else if ( this.fieldLabel.length) {
16293                 Roo.log(" label");
16294                 cfg.cn = [
16295                    
16296                     {
16297                         tag: this.boxLabel ? 'span' : 'label',
16298                         'for': id,
16299                         cls: 'control-label box-input-label',
16300                         //cls : 'input-group-addon',
16301                         html : this.fieldLabel
16302                         
16303                     },
16304                     
16305                     inputblock
16306                     
16307                 ];
16308
16309         } else {
16310             
16311                 Roo.log(" no label && no align");
16312                 cfg.cn = [  inputblock ] ;
16313                 
16314                 
16315         };
16316          if(this.boxLabel){
16317              var boxLabelCfg = {
16318                 tag: 'label',
16319                 //'for': id, // box label is handled by onclick - so no for...
16320                 cls: 'box-label',
16321                 html: this.boxLabel
16322             }
16323             
16324             if(this.tooltip){
16325                 boxLabelCfg.tooltip = this.tooltip;
16326             }
16327              
16328             cfg.cn.push(boxLabelCfg);
16329         }
16330         
16331         
16332        
16333         return cfg;
16334         
16335     },
16336     
16337     /**
16338      * return the real input element.
16339      */
16340     inputEl: function ()
16341     {
16342         return this.el.select('input.roo-' + this.inputType,true).first();
16343     },
16344     
16345     labelEl: function()
16346     {
16347         return this.el.select('label.control-label',true).first();
16348     },
16349     /* depricated... */
16350     
16351     label: function()
16352     {
16353         return this.labelEl();
16354     },
16355     
16356     initEvents : function()
16357     {
16358 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16359         
16360         this.inputEl().on('click', this.onClick,  this);
16361         if (this.boxLabel) { 
16362             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
16363         }
16364         
16365     },
16366     
16367     onClick : function()
16368     {   
16369         this.setChecked(!this.checked);
16370     },
16371     
16372     setChecked : function(state,suppressEvent)
16373     {
16374         if(this.inputType == 'radio'){
16375             
16376             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16377                 e.dom.checked = false;
16378             });
16379             
16380             this.inputEl().dom.checked = true;
16381             
16382             if(suppressEvent !== true){
16383                 this.fireEvent('check', this, true);
16384             }
16385             
16386             this.inputEl().dom.value = this.inputValue;
16387             
16388             return;
16389         }
16390         
16391         this.checked = state;
16392         
16393         if(suppressEvent !== true){
16394             this.fireEvent('check', this, state);
16395         }
16396         
16397         this.inputEl().dom.checked = state;
16398         
16399         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16400         
16401     },
16402     
16403     getValue : function()
16404     {
16405         if(this.inputType == 'radio'){
16406             return this.getGroupValue();
16407         }
16408         
16409         return this.inputEl().getValue();
16410         
16411     },
16412     
16413     getGroupValue : function()
16414     {
16415         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
16416             return '';
16417         }
16418         
16419         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
16420     },
16421     
16422     setValue : function(v,suppressEvent)
16423     {
16424         if(this.inputType == 'radio'){
16425             this.setGroupValue(v, suppressEvent);
16426             return;
16427         }
16428         
16429         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
16430     },
16431     
16432     setGroupValue : function(v, suppressEvent)
16433     {
16434         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
16435             e.dom.checked = false;
16436             
16437             if(e.dom.value == v){
16438                 e.dom.checked = true;
16439             }
16440         });
16441         
16442         if(suppressEvent !== true){
16443             this.fireEvent('check', this, true);
16444         }
16445
16446         return;
16447     }
16448     
16449 });
16450
16451  
16452 /*
16453  * - LGPL
16454  *
16455  * Radio
16456  *
16457  *
16458  * not inline
16459  *<div class="radio">
16460   <label>
16461     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
16462     Option one is this and that&mdash;be sure to include why it's great
16463   </label>
16464 </div>
16465  *
16466  *
16467  *inline
16468  *<span>
16469  *<label class="radio-inline">fieldLabel</label>
16470  *<label class="radio-inline">
16471   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
16472 </label>
16473 <span>
16474  * 
16475  * 
16476  */
16477
16478 /**
16479  * @class Roo.bootstrap.Radio
16480  * @extends Roo.bootstrap.CheckBox
16481  * Bootstrap Radio class
16482
16483  * @constructor
16484  * Create a new Radio
16485  * @param {Object} config The config object
16486  */
16487
16488 Roo.bootstrap.Radio = function(config){
16489     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
16490    
16491 };
16492
16493 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
16494     
16495     inputType: 'radio',
16496     inputValue: '',
16497     valueOff: '',
16498     
16499     getAutoCreate : function()
16500     {
16501         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16502         align = align || 'left'; // default...
16503         
16504         
16505         
16506         var id = Roo.id();
16507         
16508         var cfg = {
16509                 tag : this.inline ? 'span' : 'div',
16510                 cls : '',
16511                 cn : []
16512         };
16513         
16514         var inline = this.inline ? ' radio-inline' : '';
16515         
16516         var lbl = {
16517                 tag: 'label' ,
16518                 // does not need for, as we wrap the input with it..
16519                 'for' : id,
16520                 cls : 'control-label box-label' + inline,
16521                 cn : []
16522         };
16523         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
16524         
16525         var fieldLabel = {
16526             tag: 'label' ,
16527             //cls : 'control-label' + inline,
16528             html : this.fieldLabel,
16529             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
16530         };
16531         
16532  
16533         
16534         
16535         var input =  {
16536             tag: 'input',
16537             id : id,
16538             type : this.inputType,
16539             //value : (!this.checked) ? this.valueOff : this.inputValue,
16540             value : this.inputValue,
16541             cls : 'roo-radio',
16542             placeholder : this.placeholder || '' // ?? needed????
16543             
16544         };
16545         if (this.weight) { // Validity check?
16546             input.cls += " radio-" + this.weight;
16547         }
16548         if (this.disabled) {
16549             input.disabled=true;
16550         }
16551         
16552         if(this.checked){
16553             input.checked = this.checked;
16554         }
16555         
16556         if (this.name) {
16557             input.name = this.name;
16558         }
16559         
16560         if (this.size) {
16561             input.cls += ' input-' + this.size;
16562         }
16563         
16564         //?? can span's inline have a width??
16565         
16566         var settings=this;
16567         ['xs','sm','md','lg'].map(function(size){
16568             if (settings[size]) {
16569                 cfg.cls += ' col-' + size + '-' + settings[size];
16570             }
16571         });
16572         
16573         var inputblock = input;
16574         
16575         if (this.before || this.after) {
16576             
16577             inputblock = {
16578                 cls : 'input-group',
16579                 tag : 'span',
16580                 cn :  [] 
16581             };
16582             if (this.before) {
16583                 inputblock.cn.push({
16584                     tag :'span',
16585                     cls : 'input-group-addon',
16586                     html : this.before
16587                 });
16588             }
16589             inputblock.cn.push(input);
16590             if (this.after) {
16591                 inputblock.cn.push({
16592                     tag :'span',
16593                     cls : 'input-group-addon',
16594                     html : this.after
16595                 });
16596             }
16597             
16598         };
16599         
16600         
16601         if (this.fieldLabel && this.fieldLabel.length) {
16602             cfg.cn.push(fieldLabel);
16603         }
16604        
16605         // normal bootstrap puts the input inside the label.
16606         // however with our styled version - it has to go after the input.
16607        
16608         //lbl.cn.push(inputblock);
16609         
16610         var lblwrap =  {
16611             tag: 'span',
16612             cls: 'radio' + inline,
16613             cn: [
16614                 inputblock,
16615                 lbl
16616             ]
16617         };
16618         
16619         cfg.cn.push( lblwrap);
16620         
16621         if(this.boxLabel){
16622             lbl.cn.push({
16623                 tag: 'span',
16624                 html: this.boxLabel
16625             })
16626         }
16627          
16628         
16629         return cfg;
16630         
16631     },
16632     
16633     initEvents : function()
16634     {
16635 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
16636         
16637         this.inputEl().on('click', this.onClick,  this);
16638         if (this.boxLabel) {
16639             Roo.log('find label')
16640             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
16641         }
16642         
16643     },
16644     
16645     inputEl: function ()
16646     {
16647         return this.el.select('input.roo-radio',true).first();
16648     },
16649     onClick : function()
16650     {   
16651         Roo.log("click");
16652         this.setChecked(true);
16653     },
16654     
16655     setChecked : function(state,suppressEvent)
16656     {
16657         if(state){
16658             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16659                 v.dom.checked = false;
16660             });
16661         }
16662         Roo.log(this.inputEl().dom);
16663         this.checked = state;
16664         this.inputEl().dom.checked = state;
16665         
16666         if(suppressEvent !== true){
16667             this.fireEvent('check', this, state);
16668         }
16669         
16670         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
16671         
16672     },
16673     
16674     getGroupValue : function()
16675     {
16676         var value = ''
16677         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
16678             if(v.dom.checked == true){
16679                 value = v.dom.value;
16680             }
16681         });
16682         
16683         return value;
16684     },
16685     
16686     /**
16687      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
16688      * @return {Mixed} value The field value
16689      */
16690     getValue : function(){
16691         return this.getGroupValue();
16692     }
16693     
16694 });
16695
16696  
16697 //<script type="text/javascript">
16698
16699 /*
16700  * Based  Ext JS Library 1.1.1
16701  * Copyright(c) 2006-2007, Ext JS, LLC.
16702  * LGPL
16703  *
16704  */
16705  
16706 /**
16707  * @class Roo.HtmlEditorCore
16708  * @extends Roo.Component
16709  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
16710  *
16711  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
16712  */
16713
16714 Roo.HtmlEditorCore = function(config){
16715     
16716     
16717     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
16718     
16719     
16720     this.addEvents({
16721         /**
16722          * @event initialize
16723          * Fires when the editor is fully initialized (including the iframe)
16724          * @param {Roo.HtmlEditorCore} this
16725          */
16726         initialize: true,
16727         /**
16728          * @event activate
16729          * Fires when the editor is first receives the focus. Any insertion must wait
16730          * until after this event.
16731          * @param {Roo.HtmlEditorCore} this
16732          */
16733         activate: true,
16734          /**
16735          * @event beforesync
16736          * Fires before the textarea is updated with content from the editor iframe. Return false
16737          * to cancel the sync.
16738          * @param {Roo.HtmlEditorCore} this
16739          * @param {String} html
16740          */
16741         beforesync: true,
16742          /**
16743          * @event beforepush
16744          * Fires before the iframe editor is updated with content from the textarea. Return false
16745          * to cancel the push.
16746          * @param {Roo.HtmlEditorCore} this
16747          * @param {String} html
16748          */
16749         beforepush: true,
16750          /**
16751          * @event sync
16752          * Fires when the textarea is updated with content from the editor iframe.
16753          * @param {Roo.HtmlEditorCore} this
16754          * @param {String} html
16755          */
16756         sync: true,
16757          /**
16758          * @event push
16759          * Fires when the iframe editor is updated with content from the textarea.
16760          * @param {Roo.HtmlEditorCore} this
16761          * @param {String} html
16762          */
16763         push: true,
16764         
16765         /**
16766          * @event editorevent
16767          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16768          * @param {Roo.HtmlEditorCore} this
16769          */
16770         editorevent: true
16771         
16772     });
16773     
16774     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
16775     
16776     // defaults : white / black...
16777     this.applyBlacklists();
16778     
16779     
16780     
16781 };
16782
16783
16784 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
16785
16786
16787      /**
16788      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
16789      */
16790     
16791     owner : false,
16792     
16793      /**
16794      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
16795      *                        Roo.resizable.
16796      */
16797     resizable : false,
16798      /**
16799      * @cfg {Number} height (in pixels)
16800      */   
16801     height: 300,
16802    /**
16803      * @cfg {Number} width (in pixels)
16804      */   
16805     width: 500,
16806     
16807     /**
16808      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16809      * 
16810      */
16811     stylesheets: false,
16812     
16813     // id of frame..
16814     frameId: false,
16815     
16816     // private properties
16817     validationEvent : false,
16818     deferHeight: true,
16819     initialized : false,
16820     activated : false,
16821     sourceEditMode : false,
16822     onFocus : Roo.emptyFn,
16823     iframePad:3,
16824     hideMode:'offsets',
16825     
16826     clearUp: true,
16827     
16828     // blacklist + whitelisted elements..
16829     black: false,
16830     white: false,
16831      
16832     
16833
16834     /**
16835      * Protected method that will not generally be called directly. It
16836      * is called when the editor initializes the iframe with HTML contents. Override this method if you
16837      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
16838      */
16839     getDocMarkup : function(){
16840         // body styles..
16841         var st = '';
16842         
16843         // inherit styels from page...?? 
16844         if (this.stylesheets === false) {
16845             
16846             Roo.get(document.head).select('style').each(function(node) {
16847                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16848             });
16849             
16850             Roo.get(document.head).select('link').each(function(node) { 
16851                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
16852             });
16853             
16854         } else if (!this.stylesheets.length) {
16855                 // simple..
16856                 st = '<style type="text/css">' +
16857                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16858                    '</style>';
16859         } else { 
16860             
16861         }
16862         
16863         st +=  '<style type="text/css">' +
16864             'IMG { cursor: pointer } ' +
16865         '</style>';
16866
16867         
16868         return '<html><head>' + st  +
16869             //<style type="text/css">' +
16870             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
16871             //'</style>' +
16872             ' </head><body class="roo-htmleditor-body"></body></html>';
16873     },
16874
16875     // private
16876     onRender : function(ct, position)
16877     {
16878         var _t = this;
16879         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
16880         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
16881         
16882         
16883         this.el.dom.style.border = '0 none';
16884         this.el.dom.setAttribute('tabIndex', -1);
16885         this.el.addClass('x-hidden hide');
16886         
16887         
16888         
16889         if(Roo.isIE){ // fix IE 1px bogus margin
16890             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
16891         }
16892        
16893         
16894         this.frameId = Roo.id();
16895         
16896          
16897         
16898         var iframe = this.owner.wrap.createChild({
16899             tag: 'iframe',
16900             cls: 'form-control', // bootstrap..
16901             id: this.frameId,
16902             name: this.frameId,
16903             frameBorder : 'no',
16904             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
16905         }, this.el
16906         );
16907         
16908         
16909         this.iframe = iframe.dom;
16910
16911          this.assignDocWin();
16912         
16913         this.doc.designMode = 'on';
16914        
16915         this.doc.open();
16916         this.doc.write(this.getDocMarkup());
16917         this.doc.close();
16918
16919         
16920         var task = { // must defer to wait for browser to be ready
16921             run : function(){
16922                 //console.log("run task?" + this.doc.readyState);
16923                 this.assignDocWin();
16924                 if(this.doc.body || this.doc.readyState == 'complete'){
16925                     try {
16926                         this.doc.designMode="on";
16927                     } catch (e) {
16928                         return;
16929                     }
16930                     Roo.TaskMgr.stop(task);
16931                     this.initEditor.defer(10, this);
16932                 }
16933             },
16934             interval : 10,
16935             duration: 10000,
16936             scope: this
16937         };
16938         Roo.TaskMgr.start(task);
16939
16940     },
16941
16942     // private
16943     onResize : function(w, h)
16944     {
16945          Roo.log('resize: ' +w + ',' + h );
16946         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
16947         if(!this.iframe){
16948             return;
16949         }
16950         if(typeof w == 'number'){
16951             
16952             this.iframe.style.width = w + 'px';
16953         }
16954         if(typeof h == 'number'){
16955             
16956             this.iframe.style.height = h + 'px';
16957             if(this.doc){
16958                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
16959             }
16960         }
16961         
16962     },
16963
16964     /**
16965      * Toggles the editor between standard and source edit mode.
16966      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16967      */
16968     toggleSourceEdit : function(sourceEditMode){
16969         
16970         this.sourceEditMode = sourceEditMode === true;
16971         
16972         if(this.sourceEditMode){
16973  
16974             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
16975             
16976         }else{
16977             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
16978             //this.iframe.className = '';
16979             this.deferFocus();
16980         }
16981         //this.setSize(this.owner.wrap.getSize());
16982         //this.fireEvent('editmodechange', this, this.sourceEditMode);
16983     },
16984
16985     
16986   
16987
16988     /**
16989      * Protected method that will not generally be called directly. If you need/want
16990      * custom HTML cleanup, this is the method you should override.
16991      * @param {String} html The HTML to be cleaned
16992      * return {String} The cleaned HTML
16993      */
16994     cleanHtml : function(html){
16995         html = String(html);
16996         if(html.length > 5){
16997             if(Roo.isSafari){ // strip safari nonsense
16998                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
16999             }
17000         }
17001         if(html == '&nbsp;'){
17002             html = '';
17003         }
17004         return html;
17005     },
17006
17007     /**
17008      * HTML Editor -> Textarea
17009      * Protected method that will not generally be called directly. Syncs the contents
17010      * of the editor iframe with the textarea.
17011      */
17012     syncValue : function(){
17013         if(this.initialized){
17014             var bd = (this.doc.body || this.doc.documentElement);
17015             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17016             var html = bd.innerHTML;
17017             if(Roo.isSafari){
17018                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17019                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17020                 if(m && m[1]){
17021                     html = '<div style="'+m[0]+'">' + html + '</div>';
17022                 }
17023             }
17024             html = this.cleanHtml(html);
17025             // fix up the special chars.. normaly like back quotes in word...
17026             // however we do not want to do this with chinese..
17027             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17028                 var cc = b.charCodeAt();
17029                 if (
17030                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17031                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17032                     (cc >= 0xf900 && cc < 0xfb00 )
17033                 ) {
17034                         return b;
17035                 }
17036                 return "&#"+cc+";" 
17037             });
17038             if(this.owner.fireEvent('beforesync', this, html) !== false){
17039                 this.el.dom.value = html;
17040                 this.owner.fireEvent('sync', this, html);
17041             }
17042         }
17043     },
17044
17045     /**
17046      * Protected method that will not generally be called directly. Pushes the value of the textarea
17047      * into the iframe editor.
17048      */
17049     pushValue : function(){
17050         if(this.initialized){
17051             var v = this.el.dom.value.trim();
17052             
17053 //            if(v.length < 1){
17054 //                v = '&#160;';
17055 //            }
17056             
17057             if(this.owner.fireEvent('beforepush', this, v) !== false){
17058                 var d = (this.doc.body || this.doc.documentElement);
17059                 d.innerHTML = v;
17060                 this.cleanUpPaste();
17061                 this.el.dom.value = d.innerHTML;
17062                 this.owner.fireEvent('push', this, v);
17063             }
17064         }
17065     },
17066
17067     // private
17068     deferFocus : function(){
17069         this.focus.defer(10, this);
17070     },
17071
17072     // doc'ed in Field
17073     focus : function(){
17074         if(this.win && !this.sourceEditMode){
17075             this.win.focus();
17076         }else{
17077             this.el.focus();
17078         }
17079     },
17080     
17081     assignDocWin: function()
17082     {
17083         var iframe = this.iframe;
17084         
17085          if(Roo.isIE){
17086             this.doc = iframe.contentWindow.document;
17087             this.win = iframe.contentWindow;
17088         } else {
17089 //            if (!Roo.get(this.frameId)) {
17090 //                return;
17091 //            }
17092 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17093 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17094             
17095             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17096                 return;
17097             }
17098             
17099             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17100             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17101         }
17102     },
17103     
17104     // private
17105     initEditor : function(){
17106         //console.log("INIT EDITOR");
17107         this.assignDocWin();
17108         
17109         
17110         
17111         this.doc.designMode="on";
17112         this.doc.open();
17113         this.doc.write(this.getDocMarkup());
17114         this.doc.close();
17115         
17116         var dbody = (this.doc.body || this.doc.documentElement);
17117         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17118         // this copies styles from the containing element into thsi one..
17119         // not sure why we need all of this..
17120         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17121         
17122         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17123         //ss['background-attachment'] = 'fixed'; // w3c
17124         dbody.bgProperties = 'fixed'; // ie
17125         //Roo.DomHelper.applyStyles(dbody, ss);
17126         Roo.EventManager.on(this.doc, {
17127             //'mousedown': this.onEditorEvent,
17128             'mouseup': this.onEditorEvent,
17129             'dblclick': this.onEditorEvent,
17130             'click': this.onEditorEvent,
17131             'keyup': this.onEditorEvent,
17132             buffer:100,
17133             scope: this
17134         });
17135         if(Roo.isGecko){
17136             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
17137         }
17138         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
17139             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
17140         }
17141         this.initialized = true;
17142
17143         this.owner.fireEvent('initialize', this);
17144         this.pushValue();
17145     },
17146
17147     // private
17148     onDestroy : function(){
17149         
17150         
17151         
17152         if(this.rendered){
17153             
17154             //for (var i =0; i < this.toolbars.length;i++) {
17155             //    // fixme - ask toolbars for heights?
17156             //    this.toolbars[i].onDestroy();
17157            // }
17158             
17159             //this.wrap.dom.innerHTML = '';
17160             //this.wrap.remove();
17161         }
17162     },
17163
17164     // private
17165     onFirstFocus : function(){
17166         
17167         this.assignDocWin();
17168         
17169         
17170         this.activated = true;
17171          
17172     
17173         if(Roo.isGecko){ // prevent silly gecko errors
17174             this.win.focus();
17175             var s = this.win.getSelection();
17176             if(!s.focusNode || s.focusNode.nodeType != 3){
17177                 var r = s.getRangeAt(0);
17178                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
17179                 r.collapse(true);
17180                 this.deferFocus();
17181             }
17182             try{
17183                 this.execCmd('useCSS', true);
17184                 this.execCmd('styleWithCSS', false);
17185             }catch(e){}
17186         }
17187         this.owner.fireEvent('activate', this);
17188     },
17189
17190     // private
17191     adjustFont: function(btn){
17192         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
17193         //if(Roo.isSafari){ // safari
17194         //    adjust *= 2;
17195        // }
17196         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
17197         if(Roo.isSafari){ // safari
17198             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
17199             v =  (v < 10) ? 10 : v;
17200             v =  (v > 48) ? 48 : v;
17201             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
17202             
17203         }
17204         
17205         
17206         v = Math.max(1, v+adjust);
17207         
17208         this.execCmd('FontSize', v  );
17209     },
17210
17211     onEditorEvent : function(e){
17212         this.owner.fireEvent('editorevent', this, e);
17213       //  this.updateToolbar();
17214         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
17215     },
17216
17217     insertTag : function(tg)
17218     {
17219         // could be a bit smarter... -> wrap the current selected tRoo..
17220         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
17221             
17222             range = this.createRange(this.getSelection());
17223             var wrappingNode = this.doc.createElement(tg.toLowerCase());
17224             wrappingNode.appendChild(range.extractContents());
17225             range.insertNode(wrappingNode);
17226
17227             return;
17228             
17229             
17230             
17231         }
17232         this.execCmd("formatblock",   tg);
17233         
17234     },
17235     
17236     insertText : function(txt)
17237     {
17238         
17239         
17240         var range = this.createRange();
17241         range.deleteContents();
17242                //alert(Sender.getAttribute('label'));
17243                
17244         range.insertNode(this.doc.createTextNode(txt));
17245     } ,
17246     
17247      
17248
17249     /**
17250      * Executes a Midas editor command on the editor document and performs necessary focus and
17251      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
17252      * @param {String} cmd The Midas command
17253      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17254      */
17255     relayCmd : function(cmd, value){
17256         this.win.focus();
17257         this.execCmd(cmd, value);
17258         this.owner.fireEvent('editorevent', this);
17259         //this.updateToolbar();
17260         this.owner.deferFocus();
17261     },
17262
17263     /**
17264      * Executes a Midas editor command directly on the editor document.
17265      * For visual commands, you should use {@link #relayCmd} instead.
17266      * <b>This should only be called after the editor is initialized.</b>
17267      * @param {String} cmd The Midas command
17268      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
17269      */
17270     execCmd : function(cmd, value){
17271         this.doc.execCommand(cmd, false, value === undefined ? null : value);
17272         this.syncValue();
17273     },
17274  
17275  
17276    
17277     /**
17278      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
17279      * to insert tRoo.
17280      * @param {String} text | dom node.. 
17281      */
17282     insertAtCursor : function(text)
17283     {
17284         
17285         
17286         
17287         if(!this.activated){
17288             return;
17289         }
17290         /*
17291         if(Roo.isIE){
17292             this.win.focus();
17293             var r = this.doc.selection.createRange();
17294             if(r){
17295                 r.collapse(true);
17296                 r.pasteHTML(text);
17297                 this.syncValue();
17298                 this.deferFocus();
17299             
17300             }
17301             return;
17302         }
17303         */
17304         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
17305             this.win.focus();
17306             
17307             
17308             // from jquery ui (MIT licenced)
17309             var range, node;
17310             var win = this.win;
17311             
17312             if (win.getSelection && win.getSelection().getRangeAt) {
17313                 range = win.getSelection().getRangeAt(0);
17314                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
17315                 range.insertNode(node);
17316             } else if (win.document.selection && win.document.selection.createRange) {
17317                 // no firefox support
17318                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17319                 win.document.selection.createRange().pasteHTML(txt);
17320             } else {
17321                 // no firefox support
17322                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
17323                 this.execCmd('InsertHTML', txt);
17324             } 
17325             
17326             this.syncValue();
17327             
17328             this.deferFocus();
17329         }
17330     },
17331  // private
17332     mozKeyPress : function(e){
17333         if(e.ctrlKey){
17334             var c = e.getCharCode(), cmd;
17335           
17336             if(c > 0){
17337                 c = String.fromCharCode(c).toLowerCase();
17338                 switch(c){
17339                     case 'b':
17340                         cmd = 'bold';
17341                         break;
17342                     case 'i':
17343                         cmd = 'italic';
17344                         break;
17345                     
17346                     case 'u':
17347                         cmd = 'underline';
17348                         break;
17349                     
17350                     case 'v':
17351                         this.cleanUpPaste.defer(100, this);
17352                         return;
17353                         
17354                 }
17355                 if(cmd){
17356                     this.win.focus();
17357                     this.execCmd(cmd);
17358                     this.deferFocus();
17359                     e.preventDefault();
17360                 }
17361                 
17362             }
17363         }
17364     },
17365
17366     // private
17367     fixKeys : function(){ // load time branching for fastest keydown performance
17368         if(Roo.isIE){
17369             return function(e){
17370                 var k = e.getKey(), r;
17371                 if(k == e.TAB){
17372                     e.stopEvent();
17373                     r = this.doc.selection.createRange();
17374                     if(r){
17375                         r.collapse(true);
17376                         r.pasteHTML('&#160;&#160;&#160;&#160;');
17377                         this.deferFocus();
17378                     }
17379                     return;
17380                 }
17381                 
17382                 if(k == e.ENTER){
17383                     r = this.doc.selection.createRange();
17384                     if(r){
17385                         var target = r.parentElement();
17386                         if(!target || target.tagName.toLowerCase() != 'li'){
17387                             e.stopEvent();
17388                             r.pasteHTML('<br />');
17389                             r.collapse(false);
17390                             r.select();
17391                         }
17392                     }
17393                 }
17394                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17395                     this.cleanUpPaste.defer(100, this);
17396                     return;
17397                 }
17398                 
17399                 
17400             };
17401         }else if(Roo.isOpera){
17402             return function(e){
17403                 var k = e.getKey();
17404                 if(k == e.TAB){
17405                     e.stopEvent();
17406                     this.win.focus();
17407                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
17408                     this.deferFocus();
17409                 }
17410                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17411                     this.cleanUpPaste.defer(100, this);
17412                     return;
17413                 }
17414                 
17415             };
17416         }else if(Roo.isSafari){
17417             return function(e){
17418                 var k = e.getKey();
17419                 
17420                 if(k == e.TAB){
17421                     e.stopEvent();
17422                     this.execCmd('InsertText','\t');
17423                     this.deferFocus();
17424                     return;
17425                 }
17426                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
17427                     this.cleanUpPaste.defer(100, this);
17428                     return;
17429                 }
17430                 
17431              };
17432         }
17433     }(),
17434     
17435     getAllAncestors: function()
17436     {
17437         var p = this.getSelectedNode();
17438         var a = [];
17439         if (!p) {
17440             a.push(p); // push blank onto stack..
17441             p = this.getParentElement();
17442         }
17443         
17444         
17445         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
17446             a.push(p);
17447             p = p.parentNode;
17448         }
17449         a.push(this.doc.body);
17450         return a;
17451     },
17452     lastSel : false,
17453     lastSelNode : false,
17454     
17455     
17456     getSelection : function() 
17457     {
17458         this.assignDocWin();
17459         return Roo.isIE ? this.doc.selection : this.win.getSelection();
17460     },
17461     
17462     getSelectedNode: function() 
17463     {
17464         // this may only work on Gecko!!!
17465         
17466         // should we cache this!!!!
17467         
17468         
17469         
17470          
17471         var range = this.createRange(this.getSelection()).cloneRange();
17472         
17473         if (Roo.isIE) {
17474             var parent = range.parentElement();
17475             while (true) {
17476                 var testRange = range.duplicate();
17477                 testRange.moveToElementText(parent);
17478                 if (testRange.inRange(range)) {
17479                     break;
17480                 }
17481                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
17482                     break;
17483                 }
17484                 parent = parent.parentElement;
17485             }
17486             return parent;
17487         }
17488         
17489         // is ancestor a text element.
17490         var ac =  range.commonAncestorContainer;
17491         if (ac.nodeType == 3) {
17492             ac = ac.parentNode;
17493         }
17494         
17495         var ar = ac.childNodes;
17496          
17497         var nodes = [];
17498         var other_nodes = [];
17499         var has_other_nodes = false;
17500         for (var i=0;i<ar.length;i++) {
17501             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
17502                 continue;
17503             }
17504             // fullly contained node.
17505             
17506             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
17507                 nodes.push(ar[i]);
17508                 continue;
17509             }
17510             
17511             // probably selected..
17512             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
17513                 other_nodes.push(ar[i]);
17514                 continue;
17515             }
17516             // outer..
17517             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
17518                 continue;
17519             }
17520             
17521             
17522             has_other_nodes = true;
17523         }
17524         if (!nodes.length && other_nodes.length) {
17525             nodes= other_nodes;
17526         }
17527         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
17528             return false;
17529         }
17530         
17531         return nodes[0];
17532     },
17533     createRange: function(sel)
17534     {
17535         // this has strange effects when using with 
17536         // top toolbar - not sure if it's a great idea.
17537         //this.editor.contentWindow.focus();
17538         if (typeof sel != "undefined") {
17539             try {
17540                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
17541             } catch(e) {
17542                 return this.doc.createRange();
17543             }
17544         } else {
17545             return this.doc.createRange();
17546         }
17547     },
17548     getParentElement: function()
17549     {
17550         
17551         this.assignDocWin();
17552         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
17553         
17554         var range = this.createRange(sel);
17555          
17556         try {
17557             var p = range.commonAncestorContainer;
17558             while (p.nodeType == 3) { // text node
17559                 p = p.parentNode;
17560             }
17561             return p;
17562         } catch (e) {
17563             return null;
17564         }
17565     
17566     },
17567     /***
17568      *
17569      * Range intersection.. the hard stuff...
17570      *  '-1' = before
17571      *  '0' = hits..
17572      *  '1' = after.
17573      *         [ -- selected range --- ]
17574      *   [fail]                        [fail]
17575      *
17576      *    basically..
17577      *      if end is before start or  hits it. fail.
17578      *      if start is after end or hits it fail.
17579      *
17580      *   if either hits (but other is outside. - then it's not 
17581      *   
17582      *    
17583      **/
17584     
17585     
17586     // @see http://www.thismuchiknow.co.uk/?p=64.
17587     rangeIntersectsNode : function(range, node)
17588     {
17589         var nodeRange = node.ownerDocument.createRange();
17590         try {
17591             nodeRange.selectNode(node);
17592         } catch (e) {
17593             nodeRange.selectNodeContents(node);
17594         }
17595     
17596         var rangeStartRange = range.cloneRange();
17597         rangeStartRange.collapse(true);
17598     
17599         var rangeEndRange = range.cloneRange();
17600         rangeEndRange.collapse(false);
17601     
17602         var nodeStartRange = nodeRange.cloneRange();
17603         nodeStartRange.collapse(true);
17604     
17605         var nodeEndRange = nodeRange.cloneRange();
17606         nodeEndRange.collapse(false);
17607     
17608         return rangeStartRange.compareBoundaryPoints(
17609                  Range.START_TO_START, nodeEndRange) == -1 &&
17610                rangeEndRange.compareBoundaryPoints(
17611                  Range.START_TO_START, nodeStartRange) == 1;
17612         
17613          
17614     },
17615     rangeCompareNode : function(range, node)
17616     {
17617         var nodeRange = node.ownerDocument.createRange();
17618         try {
17619             nodeRange.selectNode(node);
17620         } catch (e) {
17621             nodeRange.selectNodeContents(node);
17622         }
17623         
17624         
17625         range.collapse(true);
17626     
17627         nodeRange.collapse(true);
17628      
17629         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
17630         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
17631          
17632         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
17633         
17634         var nodeIsBefore   =  ss == 1;
17635         var nodeIsAfter    = ee == -1;
17636         
17637         if (nodeIsBefore && nodeIsAfter)
17638             return 0; // outer
17639         if (!nodeIsBefore && nodeIsAfter)
17640             return 1; //right trailed.
17641         
17642         if (nodeIsBefore && !nodeIsAfter)
17643             return 2;  // left trailed.
17644         // fully contined.
17645         return 3;
17646     },
17647
17648     // private? - in a new class?
17649     cleanUpPaste :  function()
17650     {
17651         // cleans up the whole document..
17652         Roo.log('cleanuppaste');
17653         
17654         this.cleanUpChildren(this.doc.body);
17655         var clean = this.cleanWordChars(this.doc.body.innerHTML);
17656         if (clean != this.doc.body.innerHTML) {
17657             this.doc.body.innerHTML = clean;
17658         }
17659         
17660     },
17661     
17662     cleanWordChars : function(input) {// change the chars to hex code
17663         var he = Roo.HtmlEditorCore;
17664         
17665         var output = input;
17666         Roo.each(he.swapCodes, function(sw) { 
17667             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
17668             
17669             output = output.replace(swapper, sw[1]);
17670         });
17671         
17672         return output;
17673     },
17674     
17675     
17676     cleanUpChildren : function (n)
17677     {
17678         if (!n.childNodes.length) {
17679             return;
17680         }
17681         for (var i = n.childNodes.length-1; i > -1 ; i--) {
17682            this.cleanUpChild(n.childNodes[i]);
17683         }
17684     },
17685     
17686     
17687         
17688     
17689     cleanUpChild : function (node)
17690     {
17691         var ed = this;
17692         //console.log(node);
17693         if (node.nodeName == "#text") {
17694             // clean up silly Windows -- stuff?
17695             return; 
17696         }
17697         if (node.nodeName == "#comment") {
17698             node.parentNode.removeChild(node);
17699             // clean up silly Windows -- stuff?
17700             return; 
17701         }
17702         var lcname = node.tagName.toLowerCase();
17703         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
17704         // whitelist of tags..
17705         
17706         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
17707             // remove node.
17708             node.parentNode.removeChild(node);
17709             return;
17710             
17711         }
17712         
17713         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
17714         
17715         // remove <a name=....> as rendering on yahoo mailer is borked with this.
17716         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
17717         
17718         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
17719         //    remove_keep_children = true;
17720         //}
17721         
17722         if (remove_keep_children) {
17723             this.cleanUpChildren(node);
17724             // inserts everything just before this node...
17725             while (node.childNodes.length) {
17726                 var cn = node.childNodes[0];
17727                 node.removeChild(cn);
17728                 node.parentNode.insertBefore(cn, node);
17729             }
17730             node.parentNode.removeChild(node);
17731             return;
17732         }
17733         
17734         if (!node.attributes || !node.attributes.length) {
17735             this.cleanUpChildren(node);
17736             return;
17737         }
17738         
17739         function cleanAttr(n,v)
17740         {
17741             
17742             if (v.match(/^\./) || v.match(/^\//)) {
17743                 return;
17744             }
17745             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
17746                 return;
17747             }
17748             if (v.match(/^#/)) {
17749                 return;
17750             }
17751 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
17752             node.removeAttribute(n);
17753             
17754         }
17755         
17756         var cwhite = this.cwhite;
17757         var cblack = this.cblack;
17758             
17759         function cleanStyle(n,v)
17760         {
17761             if (v.match(/expression/)) { //XSS?? should we even bother..
17762                 node.removeAttribute(n);
17763                 return;
17764             }
17765             
17766             var parts = v.split(/;/);
17767             var clean = [];
17768             
17769             Roo.each(parts, function(p) {
17770                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
17771                 if (!p.length) {
17772                     return true;
17773                 }
17774                 var l = p.split(':').shift().replace(/\s+/g,'');
17775                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
17776                 
17777                 if ( cwhite.length && cblack.indexOf(l) > -1) {
17778 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17779                     //node.removeAttribute(n);
17780                     return true;
17781                 }
17782                 //Roo.log()
17783                 // only allow 'c whitelisted system attributes'
17784                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
17785 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
17786                     //node.removeAttribute(n);
17787                     return true;
17788                 }
17789                 
17790                 
17791                  
17792                 
17793                 clean.push(p);
17794                 return true;
17795             });
17796             if (clean.length) { 
17797                 node.setAttribute(n, clean.join(';'));
17798             } else {
17799                 node.removeAttribute(n);
17800             }
17801             
17802         }
17803         
17804         
17805         for (var i = node.attributes.length-1; i > -1 ; i--) {
17806             var a = node.attributes[i];
17807             //console.log(a);
17808             
17809             if (a.name.toLowerCase().substr(0,2)=='on')  {
17810                 node.removeAttribute(a.name);
17811                 continue;
17812             }
17813             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
17814                 node.removeAttribute(a.name);
17815                 continue;
17816             }
17817             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
17818                 cleanAttr(a.name,a.value); // fixme..
17819                 continue;
17820             }
17821             if (a.name == 'style') {
17822                 cleanStyle(a.name,a.value);
17823                 continue;
17824             }
17825             /// clean up MS crap..
17826             // tecnically this should be a list of valid class'es..
17827             
17828             
17829             if (a.name == 'class') {
17830                 if (a.value.match(/^Mso/)) {
17831                     node.className = '';
17832                 }
17833                 
17834                 if (a.value.match(/body/)) {
17835                     node.className = '';
17836                 }
17837                 continue;
17838             }
17839             
17840             // style cleanup!?
17841             // class cleanup?
17842             
17843         }
17844         
17845         
17846         this.cleanUpChildren(node);
17847         
17848         
17849     },
17850     /**
17851      * Clean up MS wordisms...
17852      */
17853     cleanWord : function(node)
17854     {
17855         var _t = this;
17856         var cleanWordChildren = function()
17857         {
17858             if (!node.childNodes.length) {
17859                 return;
17860             }
17861             for (var i = node.childNodes.length-1; i > -1 ; i--) {
17862                _t.cleanWord(node.childNodes[i]);
17863             }
17864         }
17865         
17866         
17867         if (!node) {
17868             this.cleanWord(this.doc.body);
17869             return;
17870         }
17871         if (node.nodeName == "#text") {
17872             // clean up silly Windows -- stuff?
17873             return; 
17874         }
17875         if (node.nodeName == "#comment") {
17876             node.parentNode.removeChild(node);
17877             // clean up silly Windows -- stuff?
17878             return; 
17879         }
17880         
17881         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
17882             node.parentNode.removeChild(node);
17883             return;
17884         }
17885         
17886         // remove - but keep children..
17887         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
17888             while (node.childNodes.length) {
17889                 var cn = node.childNodes[0];
17890                 node.removeChild(cn);
17891                 node.parentNode.insertBefore(cn, node);
17892             }
17893             node.parentNode.removeChild(node);
17894             cleanWordChildren();
17895             return;
17896         }
17897         // clean styles
17898         if (node.className.length) {
17899             
17900             var cn = node.className.split(/\W+/);
17901             var cna = [];
17902             Roo.each(cn, function(cls) {
17903                 if (cls.match(/Mso[a-zA-Z]+/)) {
17904                     return;
17905                 }
17906                 cna.push(cls);
17907             });
17908             node.className = cna.length ? cna.join(' ') : '';
17909             if (!cna.length) {
17910                 node.removeAttribute("class");
17911             }
17912         }
17913         
17914         if (node.hasAttribute("lang")) {
17915             node.removeAttribute("lang");
17916         }
17917         
17918         if (node.hasAttribute("style")) {
17919             
17920             var styles = node.getAttribute("style").split(";");
17921             var nstyle = [];
17922             Roo.each(styles, function(s) {
17923                 if (!s.match(/:/)) {
17924                     return;
17925                 }
17926                 var kv = s.split(":");
17927                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
17928                     return;
17929                 }
17930                 // what ever is left... we allow.
17931                 nstyle.push(s);
17932             });
17933             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
17934             if (!nstyle.length) {
17935                 node.removeAttribute('style');
17936             }
17937         }
17938         
17939         cleanWordChildren();
17940         
17941         
17942     },
17943     domToHTML : function(currentElement, depth, nopadtext) {
17944         
17945         depth = depth || 0;
17946         nopadtext = nopadtext || false;
17947     
17948         if (!currentElement) {
17949             return this.domToHTML(this.doc.body);
17950         }
17951         
17952         //Roo.log(currentElement);
17953         var j;
17954         var allText = false;
17955         var nodeName = currentElement.nodeName;
17956         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
17957         
17958         if  (nodeName == '#text') {
17959             
17960             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
17961         }
17962         
17963         
17964         var ret = '';
17965         if (nodeName != 'BODY') {
17966              
17967             var i = 0;
17968             // Prints the node tagName, such as <A>, <IMG>, etc
17969             if (tagName) {
17970                 var attr = [];
17971                 for(i = 0; i < currentElement.attributes.length;i++) {
17972                     // quoting?
17973                     var aname = currentElement.attributes.item(i).name;
17974                     if (!currentElement.attributes.item(i).value.length) {
17975                         continue;
17976                     }
17977                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
17978                 }
17979                 
17980                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
17981             } 
17982             else {
17983                 
17984                 // eack
17985             }
17986         } else {
17987             tagName = false;
17988         }
17989         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
17990             return ret;
17991         }
17992         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
17993             nopadtext = true;
17994         }
17995         
17996         
17997         // Traverse the tree
17998         i = 0;
17999         var currentElementChild = currentElement.childNodes.item(i);
18000         var allText = true;
18001         var innerHTML  = '';
18002         lastnode = '';
18003         while (currentElementChild) {
18004             // Formatting code (indent the tree so it looks nice on the screen)
18005             var nopad = nopadtext;
18006             if (lastnode == 'SPAN') {
18007                 nopad  = true;
18008             }
18009             // text
18010             if  (currentElementChild.nodeName == '#text') {
18011                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18012                 toadd = nopadtext ? toadd : toadd.trim();
18013                 if (!nopad && toadd.length > 80) {
18014                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18015                 }
18016                 innerHTML  += toadd;
18017                 
18018                 i++;
18019                 currentElementChild = currentElement.childNodes.item(i);
18020                 lastNode = '';
18021                 continue;
18022             }
18023             allText = false;
18024             
18025             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18026                 
18027             // Recursively traverse the tree structure of the child node
18028             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18029             lastnode = currentElementChild.nodeName;
18030             i++;
18031             currentElementChild=currentElement.childNodes.item(i);
18032         }
18033         
18034         ret += innerHTML;
18035         
18036         if (!allText) {
18037                 // The remaining code is mostly for formatting the tree
18038             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18039         }
18040         
18041         
18042         if (tagName) {
18043             ret+= "</"+tagName+">";
18044         }
18045         return ret;
18046         
18047     },
18048         
18049     applyBlacklists : function()
18050     {
18051         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18052         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18053         
18054         this.white = [];
18055         this.black = [];
18056         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18057             if (b.indexOf(tag) > -1) {
18058                 return;
18059             }
18060             this.white.push(tag);
18061             
18062         }, this);
18063         
18064         Roo.each(w, function(tag) {
18065             if (b.indexOf(tag) > -1) {
18066                 return;
18067             }
18068             if (this.white.indexOf(tag) > -1) {
18069                 return;
18070             }
18071             this.white.push(tag);
18072             
18073         }, this);
18074         
18075         
18076         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18077             if (w.indexOf(tag) > -1) {
18078                 return;
18079             }
18080             this.black.push(tag);
18081             
18082         }, this);
18083         
18084         Roo.each(b, function(tag) {
18085             if (w.indexOf(tag) > -1) {
18086                 return;
18087             }
18088             if (this.black.indexOf(tag) > -1) {
18089                 return;
18090             }
18091             this.black.push(tag);
18092             
18093         }, this);
18094         
18095         
18096         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18097         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18098         
18099         this.cwhite = [];
18100         this.cblack = [];
18101         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18102             if (b.indexOf(tag) > -1) {
18103                 return;
18104             }
18105             this.cwhite.push(tag);
18106             
18107         }, this);
18108         
18109         Roo.each(w, function(tag) {
18110             if (b.indexOf(tag) > -1) {
18111                 return;
18112             }
18113             if (this.cwhite.indexOf(tag) > -1) {
18114                 return;
18115             }
18116             this.cwhite.push(tag);
18117             
18118         }, this);
18119         
18120         
18121         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18122             if (w.indexOf(tag) > -1) {
18123                 return;
18124             }
18125             this.cblack.push(tag);
18126             
18127         }, this);
18128         
18129         Roo.each(b, function(tag) {
18130             if (w.indexOf(tag) > -1) {
18131                 return;
18132             }
18133             if (this.cblack.indexOf(tag) > -1) {
18134                 return;
18135             }
18136             this.cblack.push(tag);
18137             
18138         }, this);
18139     },
18140     
18141     setStylesheets : function(stylesheets)
18142     {
18143         if(typeof(stylesheets) == 'string'){
18144             Roo.get(this.iframe.contentDocument.head).createChild({
18145                 tag : 'link',
18146                 rel : 'stylesheet',
18147                 type : 'text/css',
18148                 href : stylesheets
18149             });
18150             
18151             return;
18152         }
18153         var _this = this;
18154      
18155         Roo.each(stylesheets, function(s) {
18156             if(!s.length){
18157                 return;
18158             }
18159             
18160             Roo.get(_this.iframe.contentDocument.head).createChild({
18161                 tag : 'link',
18162                 rel : 'stylesheet',
18163                 type : 'text/css',
18164                 href : s
18165             });
18166         });
18167
18168         
18169     },
18170     
18171     removeStylesheets : function()
18172     {
18173         var _this = this;
18174         
18175         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
18176             s.remove();
18177         });
18178     }
18179     
18180     // hide stuff that is not compatible
18181     /**
18182      * @event blur
18183      * @hide
18184      */
18185     /**
18186      * @event change
18187      * @hide
18188      */
18189     /**
18190      * @event focus
18191      * @hide
18192      */
18193     /**
18194      * @event specialkey
18195      * @hide
18196      */
18197     /**
18198      * @cfg {String} fieldClass @hide
18199      */
18200     /**
18201      * @cfg {String} focusClass @hide
18202      */
18203     /**
18204      * @cfg {String} autoCreate @hide
18205      */
18206     /**
18207      * @cfg {String} inputType @hide
18208      */
18209     /**
18210      * @cfg {String} invalidClass @hide
18211      */
18212     /**
18213      * @cfg {String} invalidText @hide
18214      */
18215     /**
18216      * @cfg {String} msgFx @hide
18217      */
18218     /**
18219      * @cfg {String} validateOnBlur @hide
18220      */
18221 });
18222
18223 Roo.HtmlEditorCore.white = [
18224         'area', 'br', 'img', 'input', 'hr', 'wbr',
18225         
18226        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
18227        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
18228        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
18229        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
18230        'table',   'ul',         'xmp', 
18231        
18232        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
18233       'thead',   'tr', 
18234      
18235       'dir', 'menu', 'ol', 'ul', 'dl',
18236        
18237       'embed',  'object'
18238 ];
18239
18240
18241 Roo.HtmlEditorCore.black = [
18242     //    'embed',  'object', // enable - backend responsiblity to clean thiese
18243         'applet', // 
18244         'base',   'basefont', 'bgsound', 'blink',  'body', 
18245         'frame',  'frameset', 'head',    'html',   'ilayer', 
18246         'iframe', 'layer',  'link',     'meta',    'object',   
18247         'script', 'style' ,'title',  'xml' // clean later..
18248 ];
18249 Roo.HtmlEditorCore.clean = [
18250     'script', 'style', 'title', 'xml'
18251 ];
18252 Roo.HtmlEditorCore.remove = [
18253     'font'
18254 ];
18255 // attributes..
18256
18257 Roo.HtmlEditorCore.ablack = [
18258     'on'
18259 ];
18260     
18261 Roo.HtmlEditorCore.aclean = [ 
18262     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
18263 ];
18264
18265 // protocols..
18266 Roo.HtmlEditorCore.pwhite= [
18267         'http',  'https',  'mailto'
18268 ];
18269
18270 // white listed style attributes.
18271 Roo.HtmlEditorCore.cwhite= [
18272       //  'text-align', /// default is to allow most things..
18273       
18274          
18275 //        'font-size'//??
18276 ];
18277
18278 // black listed style attributes.
18279 Roo.HtmlEditorCore.cblack= [
18280       //  'font-size' -- this can be set by the project 
18281 ];
18282
18283
18284 Roo.HtmlEditorCore.swapCodes   =[ 
18285     [    8211, "--" ], 
18286     [    8212, "--" ], 
18287     [    8216,  "'" ],  
18288     [    8217, "'" ],  
18289     [    8220, '"' ],  
18290     [    8221, '"' ],  
18291     [    8226, "*" ],  
18292     [    8230, "..." ]
18293 ]; 
18294
18295     /*
18296  * - LGPL
18297  *
18298  * HtmlEditor
18299  * 
18300  */
18301
18302 /**
18303  * @class Roo.bootstrap.HtmlEditor
18304  * @extends Roo.bootstrap.TextArea
18305  * Bootstrap HtmlEditor class
18306
18307  * @constructor
18308  * Create a new HtmlEditor
18309  * @param {Object} config The config object
18310  */
18311
18312 Roo.bootstrap.HtmlEditor = function(config){
18313     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
18314     if (!this.toolbars) {
18315         this.toolbars = [];
18316     }
18317     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
18318     this.addEvents({
18319             /**
18320              * @event initialize
18321              * Fires when the editor is fully initialized (including the iframe)
18322              * @param {HtmlEditor} this
18323              */
18324             initialize: true,
18325             /**
18326              * @event activate
18327              * Fires when the editor is first receives the focus. Any insertion must wait
18328              * until after this event.
18329              * @param {HtmlEditor} this
18330              */
18331             activate: true,
18332              /**
18333              * @event beforesync
18334              * Fires before the textarea is updated with content from the editor iframe. Return false
18335              * to cancel the sync.
18336              * @param {HtmlEditor} this
18337              * @param {String} html
18338              */
18339             beforesync: true,
18340              /**
18341              * @event beforepush
18342              * Fires before the iframe editor is updated with content from the textarea. Return false
18343              * to cancel the push.
18344              * @param {HtmlEditor} this
18345              * @param {String} html
18346              */
18347             beforepush: true,
18348              /**
18349              * @event sync
18350              * Fires when the textarea is updated with content from the editor iframe.
18351              * @param {HtmlEditor} this
18352              * @param {String} html
18353              */
18354             sync: true,
18355              /**
18356              * @event push
18357              * Fires when the iframe editor is updated with content from the textarea.
18358              * @param {HtmlEditor} this
18359              * @param {String} html
18360              */
18361             push: true,
18362              /**
18363              * @event editmodechange
18364              * Fires when the editor switches edit modes
18365              * @param {HtmlEditor} this
18366              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
18367              */
18368             editmodechange: true,
18369             /**
18370              * @event editorevent
18371              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18372              * @param {HtmlEditor} this
18373              */
18374             editorevent: true,
18375             /**
18376              * @event firstfocus
18377              * Fires when on first focus - needed by toolbars..
18378              * @param {HtmlEditor} this
18379              */
18380             firstfocus: true,
18381             /**
18382              * @event autosave
18383              * Auto save the htmlEditor value as a file into Events
18384              * @param {HtmlEditor} this
18385              */
18386             autosave: true,
18387             /**
18388              * @event savedpreview
18389              * preview the saved version of htmlEditor
18390              * @param {HtmlEditor} this
18391              */
18392             savedpreview: true
18393         });
18394 };
18395
18396
18397 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
18398     
18399     
18400       /**
18401      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
18402      */
18403     toolbars : false,
18404    
18405      /**
18406      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
18407      *                        Roo.resizable.
18408      */
18409     resizable : false,
18410      /**
18411      * @cfg {Number} height (in pixels)
18412      */   
18413     height: 300,
18414    /**
18415      * @cfg {Number} width (in pixels)
18416      */   
18417     width: false,
18418     
18419     /**
18420      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18421      * 
18422      */
18423     stylesheets: false,
18424     
18425     // id of frame..
18426     frameId: false,
18427     
18428     // private properties
18429     validationEvent : false,
18430     deferHeight: true,
18431     initialized : false,
18432     activated : false,
18433     
18434     onFocus : Roo.emptyFn,
18435     iframePad:3,
18436     hideMode:'offsets',
18437     
18438     
18439     tbContainer : false,
18440     
18441     toolbarContainer :function() {
18442         return this.wrap.select('.x-html-editor-tb',true).first();
18443     },
18444
18445     /**
18446      * Protected method that will not generally be called directly. It
18447      * is called when the editor creates its toolbar. Override this method if you need to
18448      * add custom toolbar buttons.
18449      * @param {HtmlEditor} editor
18450      */
18451     createToolbar : function(){
18452         
18453         Roo.log("create toolbars");
18454         
18455         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
18456         this.toolbars[0].render(this.toolbarContainer());
18457         
18458         return;
18459         
18460 //        if (!editor.toolbars || !editor.toolbars.length) {
18461 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
18462 //        }
18463 //        
18464 //        for (var i =0 ; i < editor.toolbars.length;i++) {
18465 //            editor.toolbars[i] = Roo.factory(
18466 //                    typeof(editor.toolbars[i]) == 'string' ?
18467 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
18468 //                Roo.bootstrap.HtmlEditor);
18469 //            editor.toolbars[i].init(editor);
18470 //        }
18471     },
18472
18473      
18474     // private
18475     onRender : function(ct, position)
18476     {
18477        // Roo.log("Call onRender: " + this.xtype);
18478         var _t = this;
18479         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
18480       
18481         this.wrap = this.inputEl().wrap({
18482             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
18483         });
18484         
18485         this.editorcore.onRender(ct, position);
18486          
18487         if (this.resizable) {
18488             this.resizeEl = new Roo.Resizable(this.wrap, {
18489                 pinned : true,
18490                 wrap: true,
18491                 dynamic : true,
18492                 minHeight : this.height,
18493                 height: this.height,
18494                 handles : this.resizable,
18495                 width: this.width,
18496                 listeners : {
18497                     resize : function(r, w, h) {
18498                         _t.onResize(w,h); // -something
18499                     }
18500                 }
18501             });
18502             
18503         }
18504         this.createToolbar(this);
18505        
18506         
18507         if(!this.width && this.resizable){
18508             this.setSize(this.wrap.getSize());
18509         }
18510         if (this.resizeEl) {
18511             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
18512             // should trigger onReize..
18513         }
18514         
18515     },
18516
18517     // private
18518     onResize : function(w, h)
18519     {
18520         Roo.log('resize: ' +w + ',' + h );
18521         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
18522         var ew = false;
18523         var eh = false;
18524         
18525         if(this.inputEl() ){
18526             if(typeof w == 'number'){
18527                 var aw = w - this.wrap.getFrameWidth('lr');
18528                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
18529                 ew = aw;
18530             }
18531             if(typeof h == 'number'){
18532                  var tbh = -11;  // fixme it needs to tool bar size!
18533                 for (var i =0; i < this.toolbars.length;i++) {
18534                     // fixme - ask toolbars for heights?
18535                     tbh += this.toolbars[i].el.getHeight();
18536                     //if (this.toolbars[i].footer) {
18537                     //    tbh += this.toolbars[i].footer.el.getHeight();
18538                     //}
18539                 }
18540               
18541                 
18542                 
18543                 
18544                 
18545                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
18546                 ah -= 5; // knock a few pixes off for look..
18547                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
18548                 var eh = ah;
18549             }
18550         }
18551         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
18552         this.editorcore.onResize(ew,eh);
18553         
18554     },
18555
18556     /**
18557      * Toggles the editor between standard and source edit mode.
18558      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18559      */
18560     toggleSourceEdit : function(sourceEditMode)
18561     {
18562         this.editorcore.toggleSourceEdit(sourceEditMode);
18563         
18564         if(this.editorcore.sourceEditMode){
18565             Roo.log('editor - showing textarea');
18566             
18567 //            Roo.log('in');
18568 //            Roo.log(this.syncValue());
18569             this.syncValue();
18570             this.inputEl().removeClass(['hide', 'x-hidden']);
18571             this.inputEl().dom.removeAttribute('tabIndex');
18572             this.inputEl().focus();
18573         }else{
18574             Roo.log('editor - hiding textarea');
18575 //            Roo.log('out')
18576 //            Roo.log(this.pushValue()); 
18577             this.pushValue();
18578             
18579             this.inputEl().addClass(['hide', 'x-hidden']);
18580             this.inputEl().dom.setAttribute('tabIndex', -1);
18581             //this.deferFocus();
18582         }
18583          
18584         if(this.resizable){
18585             this.setSize(this.wrap.getSize());
18586         }
18587         
18588         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
18589     },
18590  
18591     // private (for BoxComponent)
18592     adjustSize : Roo.BoxComponent.prototype.adjustSize,
18593
18594     // private (for BoxComponent)
18595     getResizeEl : function(){
18596         return this.wrap;
18597     },
18598
18599     // private (for BoxComponent)
18600     getPositionEl : function(){
18601         return this.wrap;
18602     },
18603
18604     // private
18605     initEvents : function(){
18606         this.originalValue = this.getValue();
18607     },
18608
18609 //    /**
18610 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18611 //     * @method
18612 //     */
18613 //    markInvalid : Roo.emptyFn,
18614 //    /**
18615 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
18616 //     * @method
18617 //     */
18618 //    clearInvalid : Roo.emptyFn,
18619
18620     setValue : function(v){
18621         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
18622         this.editorcore.pushValue();
18623     },
18624
18625      
18626     // private
18627     deferFocus : function(){
18628         this.focus.defer(10, this);
18629     },
18630
18631     // doc'ed in Field
18632     focus : function(){
18633         this.editorcore.focus();
18634         
18635     },
18636       
18637
18638     // private
18639     onDestroy : function(){
18640         
18641         
18642         
18643         if(this.rendered){
18644             
18645             for (var i =0; i < this.toolbars.length;i++) {
18646                 // fixme - ask toolbars for heights?
18647                 this.toolbars[i].onDestroy();
18648             }
18649             
18650             this.wrap.dom.innerHTML = '';
18651             this.wrap.remove();
18652         }
18653     },
18654
18655     // private
18656     onFirstFocus : function(){
18657         //Roo.log("onFirstFocus");
18658         this.editorcore.onFirstFocus();
18659          for (var i =0; i < this.toolbars.length;i++) {
18660             this.toolbars[i].onFirstFocus();
18661         }
18662         
18663     },
18664     
18665     // private
18666     syncValue : function()
18667     {   
18668         this.editorcore.syncValue();
18669     },
18670     
18671     pushValue : function()
18672     {   
18673         this.editorcore.pushValue();
18674     }
18675      
18676     
18677     // hide stuff that is not compatible
18678     /**
18679      * @event blur
18680      * @hide
18681      */
18682     /**
18683      * @event change
18684      * @hide
18685      */
18686     /**
18687      * @event focus
18688      * @hide
18689      */
18690     /**
18691      * @event specialkey
18692      * @hide
18693      */
18694     /**
18695      * @cfg {String} fieldClass @hide
18696      */
18697     /**
18698      * @cfg {String} focusClass @hide
18699      */
18700     /**
18701      * @cfg {String} autoCreate @hide
18702      */
18703     /**
18704      * @cfg {String} inputType @hide
18705      */
18706     /**
18707      * @cfg {String} invalidClass @hide
18708      */
18709     /**
18710      * @cfg {String} invalidText @hide
18711      */
18712     /**
18713      * @cfg {String} msgFx @hide
18714      */
18715     /**
18716      * @cfg {String} validateOnBlur @hide
18717      */
18718 });
18719  
18720     
18721    
18722    
18723    
18724       
18725 Roo.namespace('Roo.bootstrap.htmleditor');
18726 /**
18727  * @class Roo.bootstrap.HtmlEditorToolbar1
18728  * Basic Toolbar
18729  * 
18730  * Usage:
18731  *
18732  new Roo.bootstrap.HtmlEditor({
18733     ....
18734     toolbars : [
18735         new Roo.bootstrap.HtmlEditorToolbar1({
18736             disable : { fonts: 1 , format: 1, ..., ... , ...],
18737             btns : [ .... ]
18738         })
18739     }
18740      
18741  * 
18742  * @cfg {Object} disable List of elements to disable..
18743  * @cfg {Array} btns List of additional buttons.
18744  * 
18745  * 
18746  * NEEDS Extra CSS? 
18747  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
18748  */
18749  
18750 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
18751 {
18752     
18753     Roo.apply(this, config);
18754     
18755     // default disabled, based on 'good practice'..
18756     this.disable = this.disable || {};
18757     Roo.applyIf(this.disable, {
18758         fontSize : true,
18759         colors : true,
18760         specialElements : true
18761     });
18762     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
18763     
18764     this.editor = config.editor;
18765     this.editorcore = config.editor.editorcore;
18766     
18767     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
18768     
18769     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
18770     // dont call parent... till later.
18771 }
18772 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
18773      
18774     bar : true,
18775     
18776     editor : false,
18777     editorcore : false,
18778     
18779     
18780     formats : [
18781         "p" ,  
18782         "h1","h2","h3","h4","h5","h6", 
18783         "pre", "code", 
18784         "abbr", "acronym", "address", "cite", "samp", "var",
18785         'div','span'
18786     ],
18787     
18788     onRender : function(ct, position)
18789     {
18790        // Roo.log("Call onRender: " + this.xtype);
18791         
18792        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
18793        Roo.log(this.el);
18794        this.el.dom.style.marginBottom = '0';
18795        var _this = this;
18796        var editorcore = this.editorcore;
18797        var editor= this.editor;
18798        
18799        var children = [];
18800        var btn = function(id,cmd , toggle, handler){
18801        
18802             var  event = toggle ? 'toggle' : 'click';
18803        
18804             var a = {
18805                 size : 'sm',
18806                 xtype: 'Button',
18807                 xns: Roo.bootstrap,
18808                 glyphicon : id,
18809                 cmd : id || cmd,
18810                 enableToggle:toggle !== false,
18811                 //html : 'submit'
18812                 pressed : toggle ? false : null,
18813                 listeners : {}
18814             }
18815             a.listeners[toggle ? 'toggle' : 'click'] = function() {
18816                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
18817             }
18818             children.push(a);
18819             return a;
18820        }
18821         
18822         var style = {
18823                 xtype: 'Button',
18824                 size : 'sm',
18825                 xns: Roo.bootstrap,
18826                 glyphicon : 'font',
18827                 //html : 'submit'
18828                 menu : {
18829                     xtype: 'Menu',
18830                     xns: Roo.bootstrap,
18831                     items:  []
18832                 }
18833         };
18834         Roo.each(this.formats, function(f) {
18835             style.menu.items.push({
18836                 xtype :'MenuItem',
18837                 xns: Roo.bootstrap,
18838                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
18839                 tagname : f,
18840                 listeners : {
18841                     click : function()
18842                     {
18843                         editorcore.insertTag(this.tagname);
18844                         editor.focus();
18845                     }
18846                 }
18847                 
18848             });
18849         });
18850          children.push(style);   
18851             
18852             
18853         btn('bold',false,true);
18854         btn('italic',false,true);
18855         btn('align-left', 'justifyleft',true);
18856         btn('align-center', 'justifycenter',true);
18857         btn('align-right' , 'justifyright',true);
18858         btn('link', false, false, function(btn) {
18859             //Roo.log("create link?");
18860             var url = prompt(this.createLinkText, this.defaultLinkValue);
18861             if(url && url != 'http:/'+'/'){
18862                 this.editorcore.relayCmd('createlink', url);
18863             }
18864         }),
18865         btn('list','insertunorderedlist',true);
18866         btn('pencil', false,true, function(btn){
18867                 Roo.log(this);
18868                 
18869                 this.toggleSourceEdit(btn.pressed);
18870         });
18871         /*
18872         var cog = {
18873                 xtype: 'Button',
18874                 size : 'sm',
18875                 xns: Roo.bootstrap,
18876                 glyphicon : 'cog',
18877                 //html : 'submit'
18878                 menu : {
18879                     xtype: 'Menu',
18880                     xns: Roo.bootstrap,
18881                     items:  []
18882                 }
18883         };
18884         
18885         cog.menu.items.push({
18886             xtype :'MenuItem',
18887             xns: Roo.bootstrap,
18888             html : Clean styles,
18889             tagname : f,
18890             listeners : {
18891                 click : function()
18892                 {
18893                     editorcore.insertTag(this.tagname);
18894                     editor.focus();
18895                 }
18896             }
18897             
18898         });
18899        */
18900         
18901          
18902        this.xtype = 'NavSimplebar';
18903         
18904         for(var i=0;i< children.length;i++) {
18905             
18906             this.buttons.add(this.addxtypeChild(children[i]));
18907             
18908         }
18909         
18910         editor.on('editorevent', this.updateToolbar, this);
18911     },
18912     onBtnClick : function(id)
18913     {
18914        this.editorcore.relayCmd(id);
18915        this.editorcore.focus();
18916     },
18917     
18918     /**
18919      * Protected method that will not generally be called directly. It triggers
18920      * a toolbar update by reading the markup state of the current selection in the editor.
18921      */
18922     updateToolbar: function(){
18923
18924         if(!this.editorcore.activated){
18925             this.editor.onFirstFocus(); // is this neeed?
18926             return;
18927         }
18928
18929         var btns = this.buttons; 
18930         var doc = this.editorcore.doc;
18931         btns.get('bold').setActive(doc.queryCommandState('bold'));
18932         btns.get('italic').setActive(doc.queryCommandState('italic'));
18933         //btns.get('underline').setActive(doc.queryCommandState('underline'));
18934         
18935         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
18936         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
18937         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
18938         
18939         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
18940         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
18941          /*
18942         
18943         var ans = this.editorcore.getAllAncestors();
18944         if (this.formatCombo) {
18945             
18946             
18947             var store = this.formatCombo.store;
18948             this.formatCombo.setValue("");
18949             for (var i =0; i < ans.length;i++) {
18950                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
18951                     // select it..
18952                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
18953                     break;
18954                 }
18955             }
18956         }
18957         
18958         
18959         
18960         // hides menus... - so this cant be on a menu...
18961         Roo.bootstrap.MenuMgr.hideAll();
18962         */
18963         Roo.bootstrap.MenuMgr.hideAll();
18964         //this.editorsyncValue();
18965     },
18966     onFirstFocus: function() {
18967         this.buttons.each(function(item){
18968            item.enable();
18969         });
18970     },
18971     toggleSourceEdit : function(sourceEditMode){
18972         
18973           
18974         if(sourceEditMode){
18975             Roo.log("disabling buttons");
18976            this.buttons.each( function(item){
18977                 if(item.cmd != 'pencil'){
18978                     item.disable();
18979                 }
18980             });
18981           
18982         }else{
18983             Roo.log("enabling buttons");
18984             if(this.editorcore.initialized){
18985                 this.buttons.each( function(item){
18986                     item.enable();
18987                 });
18988             }
18989             
18990         }
18991         Roo.log("calling toggole on editor");
18992         // tell the editor that it's been pressed..
18993         this.editor.toggleSourceEdit(sourceEditMode);
18994        
18995     }
18996 });
18997
18998
18999
19000
19001
19002 /**
19003  * @class Roo.bootstrap.Table.AbstractSelectionModel
19004  * @extends Roo.util.Observable
19005  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19006  * implemented by descendant classes.  This class should not be directly instantiated.
19007  * @constructor
19008  */
19009 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19010     this.locked = false;
19011     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19012 };
19013
19014
19015 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19016     /** @ignore Called by the grid automatically. Do not call directly. */
19017     init : function(grid){
19018         this.grid = grid;
19019         this.initEvents();
19020     },
19021
19022     /**
19023      * Locks the selections.
19024      */
19025     lock : function(){
19026         this.locked = true;
19027     },
19028
19029     /**
19030      * Unlocks the selections.
19031      */
19032     unlock : function(){
19033         this.locked = false;
19034     },
19035
19036     /**
19037      * Returns true if the selections are locked.
19038      * @return {Boolean}
19039      */
19040     isLocked : function(){
19041         return this.locked;
19042     }
19043 });
19044 /**
19045  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19046  * @class Roo.bootstrap.Table.RowSelectionModel
19047  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19048  * It supports multiple selections and keyboard selection/navigation. 
19049  * @constructor
19050  * @param {Object} config
19051  */
19052
19053 Roo.bootstrap.Table.RowSelectionModel = function(config){
19054     Roo.apply(this, config);
19055     this.selections = new Roo.util.MixedCollection(false, function(o){
19056         return o.id;
19057     });
19058
19059     this.last = false;
19060     this.lastActive = false;
19061
19062     this.addEvents({
19063         /**
19064              * @event selectionchange
19065              * Fires when the selection changes
19066              * @param {SelectionModel} this
19067              */
19068             "selectionchange" : true,
19069         /**
19070              * @event afterselectionchange
19071              * Fires after the selection changes (eg. by key press or clicking)
19072              * @param {SelectionModel} this
19073              */
19074             "afterselectionchange" : true,
19075         /**
19076              * @event beforerowselect
19077              * Fires when a row is selected being selected, return false to cancel.
19078              * @param {SelectionModel} this
19079              * @param {Number} rowIndex The selected index
19080              * @param {Boolean} keepExisting False if other selections will be cleared
19081              */
19082             "beforerowselect" : true,
19083         /**
19084              * @event rowselect
19085              * Fires when a row is selected.
19086              * @param {SelectionModel} this
19087              * @param {Number} rowIndex The selected index
19088              * @param {Roo.data.Record} r The record
19089              */
19090             "rowselect" : true,
19091         /**
19092              * @event rowdeselect
19093              * Fires when a row is deselected.
19094              * @param {SelectionModel} this
19095              * @param {Number} rowIndex The selected index
19096              */
19097         "rowdeselect" : true
19098     });
19099     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19100     this.locked = false;
19101 };
19102
19103 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19104     /**
19105      * @cfg {Boolean} singleSelect
19106      * True to allow selection of only one row at a time (defaults to false)
19107      */
19108     singleSelect : false,
19109
19110     // private
19111     initEvents : function(){
19112
19113         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19114             this.grid.on("mousedown", this.handleMouseDown, this);
19115         }else{ // allow click to work like normal
19116             this.grid.on("rowclick", this.handleDragableRowClick, this);
19117         }
19118
19119         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19120             "up" : function(e){
19121                 if(!e.shiftKey){
19122                     this.selectPrevious(e.shiftKey);
19123                 }else if(this.last !== false && this.lastActive !== false){
19124                     var last = this.last;
19125                     this.selectRange(this.last,  this.lastActive-1);
19126                     this.grid.getView().focusRow(this.lastActive);
19127                     if(last !== false){
19128                         this.last = last;
19129                     }
19130                 }else{
19131                     this.selectFirstRow();
19132                 }
19133                 this.fireEvent("afterselectionchange", this);
19134             },
19135             "down" : function(e){
19136                 if(!e.shiftKey){
19137                     this.selectNext(e.shiftKey);
19138                 }else if(this.last !== false && this.lastActive !== false){
19139                     var last = this.last;
19140                     this.selectRange(this.last,  this.lastActive+1);
19141                     this.grid.getView().focusRow(this.lastActive);
19142                     if(last !== false){
19143                         this.last = last;
19144                     }
19145                 }else{
19146                     this.selectFirstRow();
19147                 }
19148                 this.fireEvent("afterselectionchange", this);
19149             },
19150             scope: this
19151         });
19152
19153         var view = this.grid.view;
19154         view.on("refresh", this.onRefresh, this);
19155         view.on("rowupdated", this.onRowUpdated, this);
19156         view.on("rowremoved", this.onRemove, this);
19157     },
19158
19159     // private
19160     onRefresh : function(){
19161         var ds = this.grid.dataSource, i, v = this.grid.view;
19162         var s = this.selections;
19163         s.each(function(r){
19164             if((i = ds.indexOfId(r.id)) != -1){
19165                 v.onRowSelect(i);
19166             }else{
19167                 s.remove(r);
19168             }
19169         });
19170     },
19171
19172     // private
19173     onRemove : function(v, index, r){
19174         this.selections.remove(r);
19175     },
19176
19177     // private
19178     onRowUpdated : function(v, index, r){
19179         if(this.isSelected(r)){
19180             v.onRowSelect(index);
19181         }
19182     },
19183
19184     /**
19185      * Select records.
19186      * @param {Array} records The records to select
19187      * @param {Boolean} keepExisting (optional) True to keep existing selections
19188      */
19189     selectRecords : function(records, keepExisting){
19190         if(!keepExisting){
19191             this.clearSelections();
19192         }
19193         var ds = this.grid.dataSource;
19194         for(var i = 0, len = records.length; i < len; i++){
19195             this.selectRow(ds.indexOf(records[i]), true);
19196         }
19197     },
19198
19199     /**
19200      * Gets the number of selected rows.
19201      * @return {Number}
19202      */
19203     getCount : function(){
19204         return this.selections.length;
19205     },
19206
19207     /**
19208      * Selects the first row in the grid.
19209      */
19210     selectFirstRow : function(){
19211         this.selectRow(0);
19212     },
19213
19214     /**
19215      * Select the last row.
19216      * @param {Boolean} keepExisting (optional) True to keep existing selections
19217      */
19218     selectLastRow : function(keepExisting){
19219         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
19220     },
19221
19222     /**
19223      * Selects the row immediately following the last selected row.
19224      * @param {Boolean} keepExisting (optional) True to keep existing selections
19225      */
19226     selectNext : function(keepExisting){
19227         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
19228             this.selectRow(this.last+1, keepExisting);
19229             this.grid.getView().focusRow(this.last);
19230         }
19231     },
19232
19233     /**
19234      * Selects the row that precedes the last selected row.
19235      * @param {Boolean} keepExisting (optional) True to keep existing selections
19236      */
19237     selectPrevious : function(keepExisting){
19238         if(this.last){
19239             this.selectRow(this.last-1, keepExisting);
19240             this.grid.getView().focusRow(this.last);
19241         }
19242     },
19243
19244     /**
19245      * Returns the selected records
19246      * @return {Array} Array of selected records
19247      */
19248     getSelections : function(){
19249         return [].concat(this.selections.items);
19250     },
19251
19252     /**
19253      * Returns the first selected record.
19254      * @return {Record}
19255      */
19256     getSelected : function(){
19257         return this.selections.itemAt(0);
19258     },
19259
19260
19261     /**
19262      * Clears all selections.
19263      */
19264     clearSelections : function(fast){
19265         if(this.locked) return;
19266         if(fast !== true){
19267             var ds = this.grid.dataSource;
19268             var s = this.selections;
19269             s.each(function(r){
19270                 this.deselectRow(ds.indexOfId(r.id));
19271             }, this);
19272             s.clear();
19273         }else{
19274             this.selections.clear();
19275         }
19276         this.last = false;
19277     },
19278
19279
19280     /**
19281      * Selects all rows.
19282      */
19283     selectAll : function(){
19284         if(this.locked) return;
19285         this.selections.clear();
19286         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
19287             this.selectRow(i, true);
19288         }
19289     },
19290
19291     /**
19292      * Returns True if there is a selection.
19293      * @return {Boolean}
19294      */
19295     hasSelection : function(){
19296         return this.selections.length > 0;
19297     },
19298
19299     /**
19300      * Returns True if the specified row is selected.
19301      * @param {Number/Record} record The record or index of the record to check
19302      * @return {Boolean}
19303      */
19304     isSelected : function(index){
19305         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
19306         return (r && this.selections.key(r.id) ? true : false);
19307     },
19308
19309     /**
19310      * Returns True if the specified record id is selected.
19311      * @param {String} id The id of record to check
19312      * @return {Boolean}
19313      */
19314     isIdSelected : function(id){
19315         return (this.selections.key(id) ? true : false);
19316     },
19317
19318     // private
19319     handleMouseDown : function(e, t){
19320         var view = this.grid.getView(), rowIndex;
19321         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
19322             return;
19323         };
19324         if(e.shiftKey && this.last !== false){
19325             var last = this.last;
19326             this.selectRange(last, rowIndex, e.ctrlKey);
19327             this.last = last; // reset the last
19328             view.focusRow(rowIndex);
19329         }else{
19330             var isSelected = this.isSelected(rowIndex);
19331             if(e.button !== 0 && isSelected){
19332                 view.focusRow(rowIndex);
19333             }else if(e.ctrlKey && isSelected){
19334                 this.deselectRow(rowIndex);
19335             }else if(!isSelected){
19336                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
19337                 view.focusRow(rowIndex);
19338             }
19339         }
19340         this.fireEvent("afterselectionchange", this);
19341     },
19342     // private
19343     handleDragableRowClick :  function(grid, rowIndex, e) 
19344     {
19345         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
19346             this.selectRow(rowIndex, false);
19347             grid.view.focusRow(rowIndex);
19348              this.fireEvent("afterselectionchange", this);
19349         }
19350     },
19351     
19352     /**
19353      * Selects multiple rows.
19354      * @param {Array} rows Array of the indexes of the row to select
19355      * @param {Boolean} keepExisting (optional) True to keep existing selections
19356      */
19357     selectRows : function(rows, keepExisting){
19358         if(!keepExisting){
19359             this.clearSelections();
19360         }
19361         for(var i = 0, len = rows.length; i < len; i++){
19362             this.selectRow(rows[i], true);
19363         }
19364     },
19365
19366     /**
19367      * Selects a range of rows. All rows in between startRow and endRow are also selected.
19368      * @param {Number} startRow The index of the first row in the range
19369      * @param {Number} endRow The index of the last row in the range
19370      * @param {Boolean} keepExisting (optional) True to retain existing selections
19371      */
19372     selectRange : function(startRow, endRow, keepExisting){
19373         if(this.locked) return;
19374         if(!keepExisting){
19375             this.clearSelections();
19376         }
19377         if(startRow <= endRow){
19378             for(var i = startRow; i <= endRow; i++){
19379                 this.selectRow(i, true);
19380             }
19381         }else{
19382             for(var i = startRow; i >= endRow; i--){
19383                 this.selectRow(i, true);
19384             }
19385         }
19386     },
19387
19388     /**
19389      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
19390      * @param {Number} startRow The index of the first row in the range
19391      * @param {Number} endRow The index of the last row in the range
19392      */
19393     deselectRange : function(startRow, endRow, preventViewNotify){
19394         if(this.locked) return;
19395         for(var i = startRow; i <= endRow; i++){
19396             this.deselectRow(i, preventViewNotify);
19397         }
19398     },
19399
19400     /**
19401      * Selects a row.
19402      * @param {Number} row The index of the row to select
19403      * @param {Boolean} keepExisting (optional) True to keep existing selections
19404      */
19405     selectRow : function(index, keepExisting, preventViewNotify){
19406         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
19407         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
19408             if(!keepExisting || this.singleSelect){
19409                 this.clearSelections();
19410             }
19411             var r = this.grid.dataSource.getAt(index);
19412             this.selections.add(r);
19413             this.last = this.lastActive = index;
19414             if(!preventViewNotify){
19415                 this.grid.getView().onRowSelect(index);
19416             }
19417             this.fireEvent("rowselect", this, index, r);
19418             this.fireEvent("selectionchange", this);
19419         }
19420     },
19421
19422     /**
19423      * Deselects a row.
19424      * @param {Number} row The index of the row to deselect
19425      */
19426     deselectRow : function(index, preventViewNotify){
19427         if(this.locked) return;
19428         if(this.last == index){
19429             this.last = false;
19430         }
19431         if(this.lastActive == index){
19432             this.lastActive = false;
19433         }
19434         var r = this.grid.dataSource.getAt(index);
19435         this.selections.remove(r);
19436         if(!preventViewNotify){
19437             this.grid.getView().onRowDeselect(index);
19438         }
19439         this.fireEvent("rowdeselect", this, index);
19440         this.fireEvent("selectionchange", this);
19441     },
19442
19443     // private
19444     restoreLast : function(){
19445         if(this._last){
19446             this.last = this._last;
19447         }
19448     },
19449
19450     // private
19451     acceptsNav : function(row, col, cm){
19452         return !cm.isHidden(col) && cm.isCellEditable(col, row);
19453     },
19454
19455     // private
19456     onEditorKey : function(field, e){
19457         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
19458         if(k == e.TAB){
19459             e.stopEvent();
19460             ed.completeEdit();
19461             if(e.shiftKey){
19462                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
19463             }else{
19464                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
19465             }
19466         }else if(k == e.ENTER && !e.ctrlKey){
19467             e.stopEvent();
19468             ed.completeEdit();
19469             if(e.shiftKey){
19470                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
19471             }else{
19472                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
19473             }
19474         }else if(k == e.ESC){
19475             ed.cancelEdit();
19476         }
19477         if(newCell){
19478             g.startEditing(newCell[0], newCell[1]);
19479         }
19480     }
19481 });/*
19482  * Based on:
19483  * Ext JS Library 1.1.1
19484  * Copyright(c) 2006-2007, Ext JS, LLC.
19485  *
19486  * Originally Released Under LGPL - original licence link has changed is not relivant.
19487  *
19488  * Fork - LGPL
19489  * <script type="text/javascript">
19490  */
19491  
19492 /**
19493  * @class Roo.bootstrap.PagingToolbar
19494  * @extends Roo.Row
19495  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
19496  * @constructor
19497  * Create a new PagingToolbar
19498  * @param {Object} config The config object
19499  */
19500 Roo.bootstrap.PagingToolbar = function(config)
19501 {
19502     // old args format still supported... - xtype is prefered..
19503         // created from xtype...
19504     var ds = config.dataSource;
19505     this.toolbarItems = [];
19506     if (config.items) {
19507         this.toolbarItems = config.items;
19508 //        config.items = [];
19509     }
19510     
19511     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
19512     this.ds = ds;
19513     this.cursor = 0;
19514     if (ds) { 
19515         this.bind(ds);
19516     }
19517     
19518     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
19519     
19520 };
19521
19522 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
19523     /**
19524      * @cfg {Roo.data.Store} dataSource
19525      * The underlying data store providing the paged data
19526      */
19527     /**
19528      * @cfg {String/HTMLElement/Element} container
19529      * container The id or element that will contain the toolbar
19530      */
19531     /**
19532      * @cfg {Boolean} displayInfo
19533      * True to display the displayMsg (defaults to false)
19534      */
19535     /**
19536      * @cfg {Number} pageSize
19537      * The number of records to display per page (defaults to 20)
19538      */
19539     pageSize: 20,
19540     /**
19541      * @cfg {String} displayMsg
19542      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
19543      */
19544     displayMsg : 'Displaying {0} - {1} of {2}',
19545     /**
19546      * @cfg {String} emptyMsg
19547      * The message to display when no records are found (defaults to "No data to display")
19548      */
19549     emptyMsg : 'No data to display',
19550     /**
19551      * Customizable piece of the default paging text (defaults to "Page")
19552      * @type String
19553      */
19554     beforePageText : "Page",
19555     /**
19556      * Customizable piece of the default paging text (defaults to "of %0")
19557      * @type String
19558      */
19559     afterPageText : "of {0}",
19560     /**
19561      * Customizable piece of the default paging text (defaults to "First Page")
19562      * @type String
19563      */
19564     firstText : "First Page",
19565     /**
19566      * Customizable piece of the default paging text (defaults to "Previous Page")
19567      * @type String
19568      */
19569     prevText : "Previous Page",
19570     /**
19571      * Customizable piece of the default paging text (defaults to "Next Page")
19572      * @type String
19573      */
19574     nextText : "Next Page",
19575     /**
19576      * Customizable piece of the default paging text (defaults to "Last Page")
19577      * @type String
19578      */
19579     lastText : "Last Page",
19580     /**
19581      * Customizable piece of the default paging text (defaults to "Refresh")
19582      * @type String
19583      */
19584     refreshText : "Refresh",
19585
19586     buttons : false,
19587     // private
19588     onRender : function(ct, position) 
19589     {
19590         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
19591         this.navgroup.parentId = this.id;
19592         this.navgroup.onRender(this.el, null);
19593         // add the buttons to the navgroup
19594         
19595         if(this.displayInfo){
19596             Roo.log(this.el.select('ul.navbar-nav',true).first());
19597             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
19598             this.displayEl = this.el.select('.x-paging-info', true).first();
19599 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
19600 //            this.displayEl = navel.el.select('span',true).first();
19601         }
19602         
19603         var _this = this;
19604         
19605         if(this.buttons){
19606             Roo.each(_this.buttons, function(e){
19607                Roo.factory(e).onRender(_this.el, null);
19608             });
19609         }
19610             
19611         Roo.each(_this.toolbarItems, function(e) {
19612             _this.navgroup.addItem(e);
19613         });
19614         
19615         
19616         this.first = this.navgroup.addItem({
19617             tooltip: this.firstText,
19618             cls: "prev",
19619             icon : 'fa fa-backward',
19620             disabled: true,
19621             preventDefault: true,
19622             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
19623         });
19624         
19625         this.prev =  this.navgroup.addItem({
19626             tooltip: this.prevText,
19627             cls: "prev",
19628             icon : 'fa fa-step-backward',
19629             disabled: true,
19630             preventDefault: true,
19631             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
19632         });
19633     //this.addSeparator();
19634         
19635         
19636         var field = this.navgroup.addItem( {
19637             tagtype : 'span',
19638             cls : 'x-paging-position',
19639             
19640             html : this.beforePageText  +
19641                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
19642                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
19643          } ); //?? escaped?
19644         
19645         this.field = field.el.select('input', true).first();
19646         this.field.on("keydown", this.onPagingKeydown, this);
19647         this.field.on("focus", function(){this.dom.select();});
19648     
19649     
19650         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
19651         //this.field.setHeight(18);
19652         //this.addSeparator();
19653         this.next = this.navgroup.addItem({
19654             tooltip: this.nextText,
19655             cls: "next",
19656             html : ' <i class="fa fa-step-forward">',
19657             disabled: true,
19658             preventDefault: true,
19659             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
19660         });
19661         this.last = this.navgroup.addItem({
19662             tooltip: this.lastText,
19663             icon : 'fa fa-forward',
19664             cls: "next",
19665             disabled: true,
19666             preventDefault: true,
19667             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
19668         });
19669     //this.addSeparator();
19670         this.loading = this.navgroup.addItem({
19671             tooltip: this.refreshText,
19672             icon: 'fa fa-refresh',
19673             preventDefault: true,
19674             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
19675         });
19676
19677     },
19678
19679     // private
19680     updateInfo : function(){
19681         if(this.displayEl){
19682             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
19683             var msg = count == 0 ?
19684                 this.emptyMsg :
19685                 String.format(
19686                     this.displayMsg,
19687                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
19688                 );
19689             this.displayEl.update(msg);
19690         }
19691     },
19692
19693     // private
19694     onLoad : function(ds, r, o){
19695        this.cursor = o.params ? o.params.start : 0;
19696        var d = this.getPageData(),
19697             ap = d.activePage,
19698             ps = d.pages;
19699         
19700        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
19701        this.field.dom.value = ap;
19702        this.first.setDisabled(ap == 1);
19703        this.prev.setDisabled(ap == 1);
19704        this.next.setDisabled(ap == ps);
19705        this.last.setDisabled(ap == ps);
19706        this.loading.enable();
19707        this.updateInfo();
19708     },
19709
19710     // private
19711     getPageData : function(){
19712         var total = this.ds.getTotalCount();
19713         return {
19714             total : total,
19715             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
19716             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
19717         };
19718     },
19719
19720     // private
19721     onLoadError : function(){
19722         this.loading.enable();
19723     },
19724
19725     // private
19726     onPagingKeydown : function(e){
19727         var k = e.getKey();
19728         var d = this.getPageData();
19729         if(k == e.RETURN){
19730             var v = this.field.dom.value, pageNum;
19731             if(!v || isNaN(pageNum = parseInt(v, 10))){
19732                 this.field.dom.value = d.activePage;
19733                 return;
19734             }
19735             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
19736             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19737             e.stopEvent();
19738         }
19739         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))
19740         {
19741           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
19742           this.field.dom.value = pageNum;
19743           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
19744           e.stopEvent();
19745         }
19746         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19747         {
19748           var v = this.field.dom.value, pageNum; 
19749           var increment = (e.shiftKey) ? 10 : 1;
19750           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
19751             increment *= -1;
19752           if(!v || isNaN(pageNum = parseInt(v, 10))) {
19753             this.field.dom.value = d.activePage;
19754             return;
19755           }
19756           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
19757           {
19758             this.field.dom.value = parseInt(v, 10) + increment;
19759             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
19760             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
19761           }
19762           e.stopEvent();
19763         }
19764     },
19765
19766     // private
19767     beforeLoad : function(){
19768         if(this.loading){
19769             this.loading.disable();
19770         }
19771     },
19772
19773     // private
19774     onClick : function(which){
19775         
19776         var ds = this.ds;
19777         if (!ds) {
19778             return;
19779         }
19780         
19781         switch(which){
19782             case "first":
19783                 ds.load({params:{start: 0, limit: this.pageSize}});
19784             break;
19785             case "prev":
19786                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
19787             break;
19788             case "next":
19789                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
19790             break;
19791             case "last":
19792                 var total = ds.getTotalCount();
19793                 var extra = total % this.pageSize;
19794                 var lastStart = extra ? (total - extra) : total-this.pageSize;
19795                 ds.load({params:{start: lastStart, limit: this.pageSize}});
19796             break;
19797             case "refresh":
19798                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
19799             break;
19800         }
19801     },
19802
19803     /**
19804      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
19805      * @param {Roo.data.Store} store The data store to unbind
19806      */
19807     unbind : function(ds){
19808         ds.un("beforeload", this.beforeLoad, this);
19809         ds.un("load", this.onLoad, this);
19810         ds.un("loadexception", this.onLoadError, this);
19811         ds.un("remove", this.updateInfo, this);
19812         ds.un("add", this.updateInfo, this);
19813         this.ds = undefined;
19814     },
19815
19816     /**
19817      * Binds the paging toolbar to the specified {@link Roo.data.Store}
19818      * @param {Roo.data.Store} store The data store to bind
19819      */
19820     bind : function(ds){
19821         ds.on("beforeload", this.beforeLoad, this);
19822         ds.on("load", this.onLoad, this);
19823         ds.on("loadexception", this.onLoadError, this);
19824         ds.on("remove", this.updateInfo, this);
19825         ds.on("add", this.updateInfo, this);
19826         this.ds = ds;
19827     }
19828 });/*
19829  * - LGPL
19830  *
19831  * element
19832  * 
19833  */
19834
19835 /**
19836  * @class Roo.bootstrap.MessageBar
19837  * @extends Roo.bootstrap.Component
19838  * Bootstrap MessageBar class
19839  * @cfg {String} html contents of the MessageBar
19840  * @cfg {String} weight (info | success | warning | danger) default info
19841  * @cfg {String} beforeClass insert the bar before the given class
19842  * @cfg {Boolean} closable (true | false) default false
19843  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
19844  * 
19845  * @constructor
19846  * Create a new Element
19847  * @param {Object} config The config object
19848  */
19849
19850 Roo.bootstrap.MessageBar = function(config){
19851     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
19852 };
19853
19854 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
19855     
19856     html: '',
19857     weight: 'info',
19858     closable: false,
19859     fixed: false,
19860     beforeClass: 'bootstrap-sticky-wrap',
19861     
19862     getAutoCreate : function(){
19863         
19864         var cfg = {
19865             tag: 'div',
19866             cls: 'alert alert-dismissable alert-' + this.weight,
19867             cn: [
19868                 {
19869                     tag: 'span',
19870                     cls: 'message',
19871                     html: this.html || ''
19872                 }
19873             ]
19874         }
19875         
19876         if(this.fixed){
19877             cfg.cls += ' alert-messages-fixed';
19878         }
19879         
19880         if(this.closable){
19881             cfg.cn.push({
19882                 tag: 'button',
19883                 cls: 'close',
19884                 html: 'x'
19885             });
19886         }
19887         
19888         return cfg;
19889     },
19890     
19891     onRender : function(ct, position)
19892     {
19893         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19894         
19895         if(!this.el){
19896             var cfg = Roo.apply({},  this.getAutoCreate());
19897             cfg.id = Roo.id();
19898             
19899             if (this.cls) {
19900                 cfg.cls += ' ' + this.cls;
19901             }
19902             if (this.style) {
19903                 cfg.style = this.style;
19904             }
19905             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
19906             
19907             this.el.setVisibilityMode(Roo.Element.DISPLAY);
19908         }
19909         
19910         this.el.select('>button.close').on('click', this.hide, this);
19911         
19912     },
19913     
19914     show : function()
19915     {
19916         if (!this.rendered) {
19917             this.render();
19918         }
19919         
19920         this.el.show();
19921         
19922         this.fireEvent('show', this);
19923         
19924     },
19925     
19926     hide : function()
19927     {
19928         if (!this.rendered) {
19929             this.render();
19930         }
19931         
19932         this.el.hide();
19933         
19934         this.fireEvent('hide', this);
19935     },
19936     
19937     update : function()
19938     {
19939 //        var e = this.el.dom.firstChild;
19940 //        
19941 //        if(this.closable){
19942 //            e = e.nextSibling;
19943 //        }
19944 //        
19945 //        e.data = this.html || '';
19946
19947         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
19948     }
19949    
19950 });
19951
19952  
19953
19954      /*
19955  * - LGPL
19956  *
19957  * Graph
19958  * 
19959  */
19960
19961
19962 /**
19963  * @class Roo.bootstrap.Graph
19964  * @extends Roo.bootstrap.Component
19965  * Bootstrap Graph class
19966 > Prameters
19967  -sm {number} sm 4
19968  -md {number} md 5
19969  @cfg {String} graphtype  bar | vbar | pie
19970  @cfg {number} g_x coodinator | centre x (pie)
19971  @cfg {number} g_y coodinator | centre y (pie)
19972  @cfg {number} g_r radius (pie)
19973  @cfg {number} g_height height of the chart (respected by all elements in the set)
19974  @cfg {number} g_width width of the chart (respected by all elements in the set)
19975  @cfg {Object} title The title of the chart
19976     
19977  -{Array}  values
19978  -opts (object) options for the chart 
19979      o {
19980      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
19981      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
19982      o vgutter (number)
19983      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.
19984      o stacked (boolean) whether or not to tread values as in a stacked bar chart
19985      o to
19986      o stretch (boolean)
19987      o }
19988  -opts (object) options for the pie
19989      o{
19990      o cut
19991      o startAngle (number)
19992      o endAngle (number)
19993      } 
19994  *
19995  * @constructor
19996  * Create a new Input
19997  * @param {Object} config The config object
19998  */
19999
20000 Roo.bootstrap.Graph = function(config){
20001     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20002     
20003     this.addEvents({
20004         // img events
20005         /**
20006          * @event click
20007          * The img click event for the img.
20008          * @param {Roo.EventObject} e
20009          */
20010         "click" : true
20011     });
20012 };
20013
20014 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20015     
20016     sm: 4,
20017     md: 5,
20018     graphtype: 'bar',
20019     g_height: 250,
20020     g_width: 400,
20021     g_x: 50,
20022     g_y: 50,
20023     g_r: 30,
20024     opts:{
20025         //g_colors: this.colors,
20026         g_type: 'soft',
20027         g_gutter: '20%'
20028
20029     },
20030     title : false,
20031
20032     getAutoCreate : function(){
20033         
20034         var cfg = {
20035             tag: 'div',
20036             html : null
20037         }
20038         
20039         
20040         return  cfg;
20041     },
20042
20043     onRender : function(ct,position){
20044         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20045         this.raphael = Raphael(this.el.dom);
20046         
20047                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20048                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20049                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20050                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20051                 /*
20052                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20053                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20054                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20055                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20056                 
20057                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20058                 r.barchart(330, 10, 300, 220, data1);
20059                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20060                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20061                 */
20062                 
20063                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20064                 // r.barchart(30, 30, 560, 250,  xdata, {
20065                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20066                 //     axis : "0 0 1 1",
20067                 //     axisxlabels :  xdata
20068                 //     //yvalues : cols,
20069                    
20070                 // });
20071 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20072 //        
20073 //        this.load(null,xdata,{
20074 //                axis : "0 0 1 1",
20075 //                axisxlabels :  xdata
20076 //                });
20077
20078     },
20079
20080     load : function(graphtype,xdata,opts){
20081         this.raphael.clear();
20082         if(!graphtype) {
20083             graphtype = this.graphtype;
20084         }
20085         if(!opts){
20086             opts = this.opts;
20087         }
20088         var r = this.raphael,
20089             fin = function () {
20090                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20091             },
20092             fout = function () {
20093                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20094             },
20095             pfin = function() {
20096                 this.sector.stop();
20097                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20098
20099                 if (this.label) {
20100                     this.label[0].stop();
20101                     this.label[0].attr({ r: 7.5 });
20102                     this.label[1].attr({ "font-weight": 800 });
20103                 }
20104             },
20105             pfout = function() {
20106                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20107
20108                 if (this.label) {
20109                     this.label[0].animate({ r: 5 }, 500, "bounce");
20110                     this.label[1].attr({ "font-weight": 400 });
20111                 }
20112             };
20113
20114         switch(graphtype){
20115             case 'bar':
20116                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20117                 break;
20118             case 'hbar':
20119                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20120                 break;
20121             case 'pie':
20122 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20123 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20124 //            
20125                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20126                 
20127                 break;
20128
20129         }
20130         
20131         if(this.title){
20132             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20133         }
20134         
20135     },
20136     
20137     setTitle: function(o)
20138     {
20139         this.title = o;
20140     },
20141     
20142     initEvents: function() {
20143         
20144         if(!this.href){
20145             this.el.on('click', this.onClick, this);
20146         }
20147     },
20148     
20149     onClick : function(e)
20150     {
20151         Roo.log('img onclick');
20152         this.fireEvent('click', this, e);
20153     }
20154    
20155 });
20156
20157  
20158 /*
20159  * - LGPL
20160  *
20161  * numberBox
20162  * 
20163  */
20164 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20165
20166 /**
20167  * @class Roo.bootstrap.dash.NumberBox
20168  * @extends Roo.bootstrap.Component
20169  * Bootstrap NumberBox class
20170  * @cfg {String} headline Box headline
20171  * @cfg {String} content Box content
20172  * @cfg {String} icon Box icon
20173  * @cfg {String} footer Footer text
20174  * @cfg {String} fhref Footer href
20175  * 
20176  * @constructor
20177  * Create a new NumberBox
20178  * @param {Object} config The config object
20179  */
20180
20181
20182 Roo.bootstrap.dash.NumberBox = function(config){
20183     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
20184     
20185 };
20186
20187 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
20188     
20189     headline : '',
20190     content : '',
20191     icon : '',
20192     footer : '',
20193     fhref : '',
20194     ficon : '',
20195     
20196     getAutoCreate : function(){
20197         
20198         var cfg = {
20199             tag : 'div',
20200             cls : 'small-box ',
20201             cn : [
20202                 {
20203                     tag : 'div',
20204                     cls : 'inner',
20205                     cn :[
20206                         {
20207                             tag : 'h3',
20208                             cls : 'roo-headline',
20209                             html : this.headline
20210                         },
20211                         {
20212                             tag : 'p',
20213                             cls : 'roo-content',
20214                             html : this.content
20215                         }
20216                     ]
20217                 }
20218             ]
20219         }
20220         
20221         if(this.icon){
20222             cfg.cn.push({
20223                 tag : 'div',
20224                 cls : 'icon',
20225                 cn :[
20226                     {
20227                         tag : 'i',
20228                         cls : 'ion ' + this.icon
20229                     }
20230                 ]
20231             });
20232         }
20233         
20234         if(this.footer){
20235             var footer = {
20236                 tag : 'a',
20237                 cls : 'small-box-footer',
20238                 href : this.fhref || '#',
20239                 html : this.footer
20240             };
20241             
20242             cfg.cn.push(footer);
20243             
20244         }
20245         
20246         return  cfg;
20247     },
20248
20249     onRender : function(ct,position){
20250         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
20251
20252
20253        
20254                 
20255     },
20256
20257     setHeadline: function (value)
20258     {
20259         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
20260     },
20261     
20262     setFooter: function (value, href)
20263     {
20264         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
20265         
20266         if(href){
20267             this.el.select('a.small-box-footer',true).first().attr('href', href);
20268         }
20269         
20270     },
20271
20272     setContent: function (value)
20273     {
20274         this.el.select('.roo-content',true).first().dom.innerHTML = value;
20275     },
20276
20277     initEvents: function() 
20278     {   
20279         
20280     }
20281     
20282 });
20283
20284  
20285 /*
20286  * - LGPL
20287  *
20288  * TabBox
20289  * 
20290  */
20291 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20292
20293 /**
20294  * @class Roo.bootstrap.dash.TabBox
20295  * @extends Roo.bootstrap.Component
20296  * Bootstrap TabBox class
20297  * @cfg {String} title Title of the TabBox
20298  * @cfg {String} icon Icon of the TabBox
20299  * @cfg {Boolean} showtabs (true|false) show the tabs default true
20300  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
20301  * 
20302  * @constructor
20303  * Create a new TabBox
20304  * @param {Object} config The config object
20305  */
20306
20307
20308 Roo.bootstrap.dash.TabBox = function(config){
20309     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
20310     this.addEvents({
20311         // raw events
20312         /**
20313          * @event addpane
20314          * When a pane is added
20315          * @param {Roo.bootstrap.dash.TabPane} pane
20316          */
20317         "addpane" : true,
20318         /**
20319          * @event activatepane
20320          * When a pane is activated
20321          * @param {Roo.bootstrap.dash.TabPane} pane
20322          */
20323         "activatepane" : true
20324         
20325          
20326     });
20327     
20328     this.panes = [];
20329 };
20330
20331 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
20332
20333     title : '',
20334     icon : false,
20335     showtabs : true,
20336     tabScrollable : false,
20337     
20338     getChildContainer : function()
20339     {
20340         return this.el.select('.tab-content', true).first();
20341     },
20342     
20343     getAutoCreate : function(){
20344         
20345         var header = {
20346             tag: 'li',
20347             cls: 'pull-left header',
20348             html: this.title,
20349             cn : []
20350         };
20351         
20352         if(this.icon){
20353             header.cn.push({
20354                 tag: 'i',
20355                 cls: 'fa ' + this.icon
20356             });
20357         }
20358         
20359         var h = {
20360             tag: 'ul',
20361             cls: 'nav nav-tabs pull-right',
20362             cn: [
20363                 header
20364             ]
20365         };
20366         
20367         if(this.tabScrollable){
20368             h = {
20369                 tag: 'div',
20370                 cls: 'tab-header',
20371                 cn: [
20372                     {
20373                         tag: 'ul',
20374                         cls: 'nav nav-tabs pull-right',
20375                         cn: [
20376                             header
20377                         ]
20378                     }
20379                 ]
20380             }
20381         }
20382         
20383         var cfg = {
20384             tag: 'div',
20385             cls: 'nav-tabs-custom',
20386             cn: [
20387                 h,
20388                 {
20389                     tag: 'div',
20390                     cls: 'tab-content no-padding',
20391                     cn: []
20392                 }
20393             ]
20394         }
20395
20396         return  cfg;
20397     },
20398     initEvents : function()
20399     {
20400         //Roo.log('add add pane handler');
20401         this.on('addpane', this.onAddPane, this);
20402     },
20403      /**
20404      * Updates the box title
20405      * @param {String} html to set the title to.
20406      */
20407     setTitle : function(value)
20408     {
20409         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
20410     },
20411     onAddPane : function(pane)
20412     {
20413         this.panes.push(pane);
20414         //Roo.log('addpane');
20415         //Roo.log(pane);
20416         // tabs are rendere left to right..
20417         if(!this.showtabs){
20418             return;
20419         }
20420         
20421         var ctr = this.el.select('.nav-tabs', true).first();
20422          
20423          
20424         var existing = ctr.select('.nav-tab',true);
20425         var qty = existing.getCount();;
20426         
20427         
20428         var tab = ctr.createChild({
20429             tag : 'li',
20430             cls : 'nav-tab' + (qty ? '' : ' active'),
20431             cn : [
20432                 {
20433                     tag : 'a',
20434                     href:'#',
20435                     html : pane.title
20436                 }
20437             ]
20438         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
20439         pane.tab = tab;
20440         
20441         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
20442         if (!qty) {
20443             pane.el.addClass('active');
20444         }
20445         
20446                 
20447     },
20448     onTabClick : function(ev,un,ob,pane)
20449     {
20450         //Roo.log('tab - prev default');
20451         ev.preventDefault();
20452         
20453         
20454         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
20455         pane.tab.addClass('active');
20456         //Roo.log(pane.title);
20457         this.getChildContainer().select('.tab-pane',true).removeClass('active');
20458         // technically we should have a deactivate event.. but maybe add later.
20459         // and it should not de-activate the selected tab...
20460         this.fireEvent('activatepane', pane);
20461         pane.el.addClass('active');
20462         pane.fireEvent('activate');
20463         
20464         
20465     },
20466     
20467     getActivePane : function()
20468     {
20469         var r = false;
20470         Roo.each(this.panes, function(p) {
20471             if(p.el.hasClass('active')){
20472                 r = p;
20473                 return false;
20474             }
20475             
20476             return;
20477         });
20478         
20479         return r;
20480     }
20481     
20482     
20483 });
20484
20485  
20486 /*
20487  * - LGPL
20488  *
20489  * Tab pane
20490  * 
20491  */
20492 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
20493 /**
20494  * @class Roo.bootstrap.TabPane
20495  * @extends Roo.bootstrap.Component
20496  * Bootstrap TabPane class
20497  * @cfg {Boolean} active (false | true) Default false
20498  * @cfg {String} title title of panel
20499
20500  * 
20501  * @constructor
20502  * Create a new TabPane
20503  * @param {Object} config The config object
20504  */
20505
20506 Roo.bootstrap.dash.TabPane = function(config){
20507     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
20508     
20509     this.addEvents({
20510         // raw events
20511         /**
20512          * @event activate
20513          * When a pane is activated
20514          * @param {Roo.bootstrap.dash.TabPane} pane
20515          */
20516         "activate" : true
20517          
20518     });
20519 };
20520
20521 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
20522     
20523     active : false,
20524     title : '',
20525     
20526     // the tabBox that this is attached to.
20527     tab : false,
20528      
20529     getAutoCreate : function() 
20530     {
20531         var cfg = {
20532             tag: 'div',
20533             cls: 'tab-pane'
20534         }
20535         
20536         if(this.active){
20537             cfg.cls += ' active';
20538         }
20539         
20540         return cfg;
20541     },
20542     initEvents  : function()
20543     {
20544         //Roo.log('trigger add pane handler');
20545         this.parent().fireEvent('addpane', this)
20546     },
20547     
20548      /**
20549      * Updates the tab title 
20550      * @param {String} html to set the title to.
20551      */
20552     setTitle: function(str)
20553     {
20554         if (!this.tab) {
20555             return;
20556         }
20557         this.title = str;
20558         this.tab.select('a', true).first().dom.innerHTML = str;
20559         
20560     }
20561     
20562     
20563     
20564 });
20565
20566  
20567
20568
20569  /*
20570  * - LGPL
20571  *
20572  * menu
20573  * 
20574  */
20575 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20576
20577 /**
20578  * @class Roo.bootstrap.menu.Menu
20579  * @extends Roo.bootstrap.Component
20580  * Bootstrap Menu class - container for Menu
20581  * @cfg {String} html Text of the menu
20582  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
20583  * @cfg {String} icon Font awesome icon
20584  * @cfg {String} pos Menu align to (top | bottom) default bottom
20585  * 
20586  * 
20587  * @constructor
20588  * Create a new Menu
20589  * @param {Object} config The config object
20590  */
20591
20592
20593 Roo.bootstrap.menu.Menu = function(config){
20594     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
20595     
20596     this.addEvents({
20597         /**
20598          * @event beforeshow
20599          * Fires before this menu is displayed
20600          * @param {Roo.bootstrap.menu.Menu} this
20601          */
20602         beforeshow : true,
20603         /**
20604          * @event beforehide
20605          * Fires before this menu is hidden
20606          * @param {Roo.bootstrap.menu.Menu} this
20607          */
20608         beforehide : true,
20609         /**
20610          * @event show
20611          * Fires after this menu is displayed
20612          * @param {Roo.bootstrap.menu.Menu} this
20613          */
20614         show : true,
20615         /**
20616          * @event hide
20617          * Fires after this menu is hidden
20618          * @param {Roo.bootstrap.menu.Menu} this
20619          */
20620         hide : true,
20621         /**
20622          * @event click
20623          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
20624          * @param {Roo.bootstrap.menu.Menu} this
20625          * @param {Roo.EventObject} e
20626          */
20627         click : true
20628     });
20629     
20630 };
20631
20632 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
20633     
20634     submenu : false,
20635     html : '',
20636     weight : 'default',
20637     icon : false,
20638     pos : 'bottom',
20639     
20640     
20641     getChildContainer : function() {
20642         if(this.isSubMenu){
20643             return this.el;
20644         }
20645         
20646         return this.el.select('ul.dropdown-menu', true).first();  
20647     },
20648     
20649     getAutoCreate : function()
20650     {
20651         var text = [
20652             {
20653                 tag : 'span',
20654                 cls : 'roo-menu-text',
20655                 html : this.html
20656             }
20657         ];
20658         
20659         if(this.icon){
20660             text.unshift({
20661                 tag : 'i',
20662                 cls : 'fa ' + this.icon
20663             })
20664         }
20665         
20666         
20667         var cfg = {
20668             tag : 'div',
20669             cls : 'btn-group',
20670             cn : [
20671                 {
20672                     tag : 'button',
20673                     cls : 'dropdown-button btn btn-' + this.weight,
20674                     cn : text
20675                 },
20676                 {
20677                     tag : 'button',
20678                     cls : 'dropdown-toggle btn btn-' + this.weight,
20679                     cn : [
20680                         {
20681                             tag : 'span',
20682                             cls : 'caret'
20683                         }
20684                     ]
20685                 },
20686                 {
20687                     tag : 'ul',
20688                     cls : 'dropdown-menu'
20689                 }
20690             ]
20691             
20692         };
20693         
20694         if(this.pos == 'top'){
20695             cfg.cls += ' dropup';
20696         }
20697         
20698         if(this.isSubMenu){
20699             cfg = {
20700                 tag : 'ul',
20701                 cls : 'dropdown-menu'
20702             }
20703         }
20704         
20705         return cfg;
20706     },
20707     
20708     onRender : function(ct, position)
20709     {
20710         this.isSubMenu = ct.hasClass('dropdown-submenu');
20711         
20712         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
20713     },
20714     
20715     initEvents : function() 
20716     {
20717         if(this.isSubMenu){
20718             return;
20719         }
20720         
20721         this.hidden = true;
20722         
20723         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
20724         this.triggerEl.on('click', this.onTriggerPress, this);
20725         
20726         this.buttonEl = this.el.select('button.dropdown-button', true).first();
20727         this.buttonEl.on('click', this.onClick, this);
20728         
20729     },
20730     
20731     list : function()
20732     {
20733         if(this.isSubMenu){
20734             return this.el;
20735         }
20736         
20737         return this.el.select('ul.dropdown-menu', true).first();
20738     },
20739     
20740     onClick : function(e)
20741     {
20742         this.fireEvent("click", this, e);
20743     },
20744     
20745     onTriggerPress  : function(e)
20746     {   
20747         if (this.isVisible()) {
20748             this.hide();
20749         } else {
20750             this.show();
20751         }
20752     },
20753     
20754     isVisible : function(){
20755         return !this.hidden;
20756     },
20757     
20758     show : function()
20759     {
20760         this.fireEvent("beforeshow", this);
20761         
20762         this.hidden = false;
20763         this.el.addClass('open');
20764         
20765         Roo.get(document).on("mouseup", this.onMouseUp, this);
20766         
20767         this.fireEvent("show", this);
20768         
20769         
20770     },
20771     
20772     hide : function()
20773     {
20774         this.fireEvent("beforehide", this);
20775         
20776         this.hidden = true;
20777         this.el.removeClass('open');
20778         
20779         Roo.get(document).un("mouseup", this.onMouseUp);
20780         
20781         this.fireEvent("hide", this);
20782     },
20783     
20784     onMouseUp : function()
20785     {
20786         this.hide();
20787     }
20788     
20789 });
20790
20791  
20792  /*
20793  * - LGPL
20794  *
20795  * menu item
20796  * 
20797  */
20798 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20799
20800 /**
20801  * @class Roo.bootstrap.menu.Item
20802  * @extends Roo.bootstrap.Component
20803  * Bootstrap MenuItem class
20804  * @cfg {Boolean} submenu (true | false) default false
20805  * @cfg {String} html text of the item
20806  * @cfg {String} href the link
20807  * @cfg {Boolean} disable (true | false) default false
20808  * @cfg {Boolean} preventDefault (true | false) default true
20809  * @cfg {String} icon Font awesome icon
20810  * @cfg {String} pos Submenu align to (left | right) default right 
20811  * 
20812  * 
20813  * @constructor
20814  * Create a new Item
20815  * @param {Object} config The config object
20816  */
20817
20818
20819 Roo.bootstrap.menu.Item = function(config){
20820     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
20821     this.addEvents({
20822         /**
20823          * @event mouseover
20824          * Fires when the mouse is hovering over this menu
20825          * @param {Roo.bootstrap.menu.Item} this
20826          * @param {Roo.EventObject} e
20827          */
20828         mouseover : true,
20829         /**
20830          * @event mouseout
20831          * Fires when the mouse exits this menu
20832          * @param {Roo.bootstrap.menu.Item} this
20833          * @param {Roo.EventObject} e
20834          */
20835         mouseout : true,
20836         // raw events
20837         /**
20838          * @event click
20839          * The raw click event for the entire grid.
20840          * @param {Roo.EventObject} e
20841          */
20842         click : true
20843     });
20844 };
20845
20846 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
20847     
20848     submenu : false,
20849     href : '',
20850     html : '',
20851     preventDefault: true,
20852     disable : false,
20853     icon : false,
20854     pos : 'right',
20855     
20856     getAutoCreate : function()
20857     {
20858         var text = [
20859             {
20860                 tag : 'span',
20861                 cls : 'roo-menu-item-text',
20862                 html : this.html
20863             }
20864         ];
20865         
20866         if(this.icon){
20867             text.unshift({
20868                 tag : 'i',
20869                 cls : 'fa ' + this.icon
20870             })
20871         }
20872         
20873         var cfg = {
20874             tag : 'li',
20875             cn : [
20876                 {
20877                     tag : 'a',
20878                     href : this.href || '#',
20879                     cn : text
20880                 }
20881             ]
20882         };
20883         
20884         if(this.disable){
20885             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
20886         }
20887         
20888         if(this.submenu){
20889             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
20890             
20891             if(this.pos == 'left'){
20892                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
20893             }
20894         }
20895         
20896         return cfg;
20897     },
20898     
20899     initEvents : function() 
20900     {
20901         this.el.on('mouseover', this.onMouseOver, this);
20902         this.el.on('mouseout', this.onMouseOut, this);
20903         
20904         this.el.select('a', true).first().on('click', this.onClick, this);
20905         
20906     },
20907     
20908     onClick : function(e)
20909     {
20910         if(this.preventDefault){
20911             e.preventDefault();
20912         }
20913         
20914         this.fireEvent("click", this, e);
20915     },
20916     
20917     onMouseOver : function(e)
20918     {
20919         if(this.submenu && this.pos == 'left'){
20920             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
20921         }
20922         
20923         this.fireEvent("mouseover", this, e);
20924     },
20925     
20926     onMouseOut : function(e)
20927     {
20928         this.fireEvent("mouseout", this, e);
20929     }
20930 });
20931
20932  
20933
20934  /*
20935  * - LGPL
20936  *
20937  * menu separator
20938  * 
20939  */
20940 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
20941
20942 /**
20943  * @class Roo.bootstrap.menu.Separator
20944  * @extends Roo.bootstrap.Component
20945  * Bootstrap Separator class
20946  * 
20947  * @constructor
20948  * Create a new Separator
20949  * @param {Object} config The config object
20950  */
20951
20952
20953 Roo.bootstrap.menu.Separator = function(config){
20954     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
20955 };
20956
20957 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
20958     
20959     getAutoCreate : function(){
20960         var cfg = {
20961             tag : 'li',
20962             cls: 'divider'
20963         };
20964         
20965         return cfg;
20966     }
20967    
20968 });
20969
20970  
20971
20972  /*
20973  * - LGPL
20974  *
20975  * Tooltip
20976  * 
20977  */
20978
20979 /**
20980  * @class Roo.bootstrap.Tooltip
20981  * Bootstrap Tooltip class
20982  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
20983  * to determine which dom element triggers the tooltip.
20984  * 
20985  * It needs to add support for additional attributes like tooltip-position
20986  * 
20987  * @constructor
20988  * Create a new Toolti
20989  * @param {Object} config The config object
20990  */
20991
20992 Roo.bootstrap.Tooltip = function(config){
20993     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
20994 };
20995
20996 Roo.apply(Roo.bootstrap.Tooltip, {
20997     /**
20998      * @function init initialize tooltip monitoring.
20999      * @static
21000      */
21001     currentEl : false,
21002     currentTip : false,
21003     currentRegion : false,
21004     
21005     //  init : delay?
21006     
21007     init : function()
21008     {
21009         Roo.get(document).on('mouseover', this.enter ,this);
21010         Roo.get(document).on('mouseout', this.leave, this);
21011          
21012         
21013         this.currentTip = new Roo.bootstrap.Tooltip();
21014     },
21015     
21016     enter : function(ev)
21017     {
21018         var dom = ev.getTarget();
21019         //Roo.log(['enter',dom]);
21020         var el = Roo.fly(dom);
21021         if (this.currentEl) {
21022             //Roo.log(dom);
21023             //Roo.log(this.currentEl);
21024             //Roo.log(this.currentEl.contains(dom));
21025             if (this.currentEl == el) {
21026                 return;
21027             }
21028             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21029                 return;
21030             }
21031
21032         }
21033         
21034         
21035         
21036         if (this.currentTip.el) {
21037             this.currentTip.el.hide(); // force hiding...
21038         }    
21039         //Roo.log(el);
21040         if (!el.attr('tooltip')) { // parents who have tip?
21041             return;
21042         }
21043         this.currentEl = el;
21044         this.currentTip.bind(el);
21045         this.currentRegion = Roo.lib.Region.getRegion(dom);
21046         this.currentTip.enter();
21047         
21048     },
21049     leave : function(ev)
21050     {
21051         var dom = ev.getTarget();
21052         //Roo.log(['leave',dom]);
21053         if (!this.currentEl) {
21054             return;
21055         }
21056         
21057         
21058         if (dom != this.currentEl.dom) {
21059             return;
21060         }
21061         var xy = ev.getXY();
21062         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21063             return;
21064         }
21065         // only activate leave if mouse cursor is outside... bounding box..
21066         
21067         
21068         
21069         
21070         if (this.currentTip) {
21071             this.currentTip.leave();
21072         }
21073         //Roo.log('clear currentEl');
21074         this.currentEl = false;
21075         
21076         
21077     },
21078     alignment : {
21079         'left' : ['r-l', [-2,0], 'right'],
21080         'right' : ['l-r', [2,0], 'left'],
21081         'bottom' : ['t-b', [0,2], 'top'],
21082         'top' : [ 'b-t', [0,-2], 'bottom']
21083     }
21084     
21085 });
21086
21087
21088 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21089     
21090     
21091     bindEl : false,
21092     
21093     delay : null, // can be { show : 300 , hide: 500}
21094     
21095     timeout : null,
21096     
21097     hoverState : null, //???
21098     
21099     placement : 'bottom', 
21100     
21101     getAutoCreate : function(){
21102     
21103         var cfg = {
21104            cls : 'tooltip',
21105            role : 'tooltip',
21106            cn : [
21107                 {
21108                     cls : 'tooltip-arrow'
21109                 },
21110                 {
21111                     cls : 'tooltip-inner'
21112                 }
21113            ]
21114         };
21115         
21116         return cfg;
21117     },
21118     bind : function(el)
21119     {
21120         this.bindEl = el;
21121     },
21122       
21123     
21124     enter : function () {
21125        
21126         if (this.timeout != null) {
21127             clearTimeout(this.timeout);
21128         }
21129         
21130         this.hoverState = 'in'
21131          //Roo.log("enter - show");
21132         if (!this.delay || !this.delay.show) {
21133             this.show();
21134             return;
21135         }
21136         var _t = this;
21137         this.timeout = setTimeout(function () {
21138             if (_t.hoverState == 'in') {
21139                 _t.show();
21140             }
21141         }, this.delay.show);
21142     },
21143     leave : function()
21144     {
21145         clearTimeout(this.timeout);
21146     
21147         this.hoverState = 'out'
21148          if (!this.delay || !this.delay.hide) {
21149             this.hide();
21150             return 
21151         }
21152        
21153         var _t = this;
21154         this.timeout = setTimeout(function () {
21155             //Roo.log("leave - timeout");
21156             
21157             if (_t.hoverState == 'out') {
21158                 _t.hide();
21159                 Roo.bootstrap.Tooltip.currentEl = false;
21160             }
21161         }, delay)
21162     },
21163     
21164     show : function ()
21165     {
21166         if (!this.el) {
21167             this.render(document.body);
21168         }
21169         // set content.
21170         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
21171         this.el.select('.tooltip-inner',true).first().dom.innerHTML = this.bindEl.attr('tooltip');
21172         
21173         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
21174         
21175         var placement = typeof this.placement == 'function' ?
21176             this.placement.call(this, this.el, on_el) :
21177             this.placement;
21178             
21179         var autoToken = /\s?auto?\s?/i;
21180         var autoPlace = autoToken.test(placement);
21181         if (autoPlace) {
21182             placement = placement.replace(autoToken, '') || 'top';
21183         }
21184         
21185         //this.el.detach()
21186         //this.el.setXY([0,0]);
21187         this.el.show();
21188         //this.el.dom.style.display='block';
21189         this.el.addClass(placement);
21190         
21191         //this.el.appendTo(on_el);
21192         
21193         var p = this.getPosition();
21194         var box = this.el.getBox();
21195         
21196         if (autoPlace) {
21197             // fixme..
21198         }
21199         var align = Roo.bootstrap.Tooltip.alignment[placement]
21200         this.el.alignTo(this.bindEl, align[0],align[1]);
21201         //var arrow = this.el.select('.arrow',true).first();
21202         //arrow.set(align[2], 
21203         
21204         this.el.addClass('in fade');
21205         this.hoverState = null;
21206         
21207         if (this.el.hasClass('fade')) {
21208             // fade it?
21209         }
21210         
21211     },
21212     hide : function()
21213     {
21214          
21215         if (!this.el) {
21216             return;
21217         }
21218         //this.el.setXY([0,0]);
21219         this.el.removeClass('in');
21220         //this.el.hide();
21221         
21222     }
21223     
21224 });
21225  
21226
21227  /*
21228  * - LGPL
21229  *
21230  * Location Picker
21231  * 
21232  */
21233
21234 /**
21235  * @class Roo.bootstrap.LocationPicker
21236  * @extends Roo.bootstrap.Component
21237  * Bootstrap LocationPicker class
21238  * @cfg {Number} latitude Position when init default 0
21239  * @cfg {Number} longitude Position when init default 0
21240  * @cfg {Number} zoom default 15
21241  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
21242  * @cfg {Boolean} mapTypeControl default false
21243  * @cfg {Boolean} disableDoubleClickZoom default false
21244  * @cfg {Boolean} scrollwheel default true
21245  * @cfg {Boolean} streetViewControl default false
21246  * @cfg {Number} radius default 0
21247  * @cfg {String} locationName
21248  * @cfg {Boolean} draggable default true
21249  * @cfg {Boolean} enableAutocomplete default false
21250  * @cfg {Boolean} enableReverseGeocode default true
21251  * @cfg {String} markerTitle
21252  * 
21253  * @constructor
21254  * Create a new LocationPicker
21255  * @param {Object} config The config object
21256  */
21257
21258
21259 Roo.bootstrap.LocationPicker = function(config){
21260     
21261     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
21262     
21263     this.addEvents({
21264         /**
21265          * @event initial
21266          * Fires when the picker initialized.
21267          * @param {Roo.bootstrap.LocationPicker} this
21268          * @param {Google Location} location
21269          */
21270         initial : true,
21271         /**
21272          * @event positionchanged
21273          * Fires when the picker position changed.
21274          * @param {Roo.bootstrap.LocationPicker} this
21275          * @param {Google Location} location
21276          */
21277         positionchanged : true,
21278         /**
21279          * @event resize
21280          * Fires when the map resize.
21281          * @param {Roo.bootstrap.LocationPicker} this
21282          */
21283         resize : true,
21284         /**
21285          * @event show
21286          * Fires when the map show.
21287          * @param {Roo.bootstrap.LocationPicker} this
21288          */
21289         show : true,
21290         /**
21291          * @event hide
21292          * Fires when the map hide.
21293          * @param {Roo.bootstrap.LocationPicker} this
21294          */
21295         hide : true,
21296         /**
21297          * @event mapClick
21298          * Fires when click the map.
21299          * @param {Roo.bootstrap.LocationPicker} this
21300          * @param {Map event} e
21301          */
21302         mapClick : true,
21303         /**
21304          * @event mapRightClick
21305          * Fires when right click the map.
21306          * @param {Roo.bootstrap.LocationPicker} this
21307          * @param {Map event} e
21308          */
21309         mapRightClick : true,
21310         /**
21311          * @event markerClick
21312          * Fires when click the marker.
21313          * @param {Roo.bootstrap.LocationPicker} this
21314          * @param {Map event} e
21315          */
21316         markerClick : true,
21317         /**
21318          * @event markerRightClick
21319          * Fires when right click the marker.
21320          * @param {Roo.bootstrap.LocationPicker} this
21321          * @param {Map event} e
21322          */
21323         markerRightClick : true,
21324         /**
21325          * @event OverlayViewDraw
21326          * Fires when OverlayView Draw
21327          * @param {Roo.bootstrap.LocationPicker} this
21328          */
21329         OverlayViewDraw : true,
21330         /**
21331          * @event OverlayViewOnAdd
21332          * Fires when OverlayView Draw
21333          * @param {Roo.bootstrap.LocationPicker} this
21334          */
21335         OverlayViewOnAdd : true,
21336         /**
21337          * @event OverlayViewOnRemove
21338          * Fires when OverlayView Draw
21339          * @param {Roo.bootstrap.LocationPicker} this
21340          */
21341         OverlayViewOnRemove : true,
21342         /**
21343          * @event OverlayViewShow
21344          * Fires when OverlayView Draw
21345          * @param {Roo.bootstrap.LocationPicker} this
21346          * @param {Pixel} cpx
21347          */
21348         OverlayViewShow : true,
21349         /**
21350          * @event OverlayViewHide
21351          * Fires when OverlayView Draw
21352          * @param {Roo.bootstrap.LocationPicker} this
21353          */
21354         OverlayViewHide : true
21355     });
21356         
21357 };
21358
21359 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
21360     
21361     gMapContext: false,
21362     
21363     latitude: 0,
21364     longitude: 0,
21365     zoom: 15,
21366     mapTypeId: false,
21367     mapTypeControl: false,
21368     disableDoubleClickZoom: false,
21369     scrollwheel: true,
21370     streetViewControl: false,
21371     radius: 0,
21372     locationName: '',
21373     draggable: true,
21374     enableAutocomplete: false,
21375     enableReverseGeocode: true,
21376     markerTitle: '',
21377     
21378     getAutoCreate: function()
21379     {
21380
21381         var cfg = {
21382             tag: 'div',
21383             cls: 'roo-location-picker'
21384         };
21385         
21386         return cfg
21387     },
21388     
21389     initEvents: function(ct, position)
21390     {       
21391         if(!this.el.getWidth() || this.isApplied()){
21392             return;
21393         }
21394         
21395         this.el.setVisibilityMode(Roo.Element.DISPLAY);
21396         
21397         this.initial();
21398     },
21399     
21400     initial: function()
21401     {
21402         if(!this.mapTypeId){
21403             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
21404         }
21405         
21406         this.gMapContext = this.GMapContext();
21407         
21408         this.initOverlayView();
21409         
21410         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
21411         
21412         var _this = this;
21413                 
21414         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
21415             _this.setPosition(_this.gMapContext.marker.position);
21416         });
21417         
21418         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
21419             Roo.log('mapClick');
21420             _this.fireEvent('mapClick', this, event);
21421             
21422         });
21423
21424         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
21425             Roo.log('mapRightClick');
21426             _this.fireEvent('mapRightClick', this, event);
21427             
21428         });
21429         
21430         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
21431             Roo.log('markerClick');
21432             _this.fireEvent('markerClick', this, event);
21433             
21434         });
21435
21436         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
21437             Roo.log('markerRightClick');
21438             _this.fireEvent('markerRightClick', this, event);
21439             
21440         });
21441         
21442         this.setPosition(this.gMapContext.location);
21443         
21444         this.fireEvent('initial', this, this.gMapContext.location);
21445     },
21446     
21447     initOverlayView: function()
21448     {
21449         var _this = this;
21450         
21451         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
21452             
21453             draw: function()
21454             {
21455                 Roo.log('OverlayView draw');
21456                 _this.fireEvent('OverlayViewDraw', _this);
21457             },
21458             
21459             onAdd: function()
21460             {
21461                 Roo.log('OverlayView onAdd');
21462                 _this.fireEvent('OverlayViewOnAdd', _this);
21463             },
21464             
21465             onRemove: function()
21466             {
21467                 Roo.log('OverlayView onRemove');
21468                 _this.fireEvent('OverlayViewOnRemove', _this);
21469             },
21470             
21471             show: function(cpx)
21472             {
21473                 Roo.log('OverlayView show');
21474                 _this.fireEvent('OverlayViewShow', _this, cpx);
21475             },
21476             
21477             hide: function()
21478             {
21479                 Roo.log('OverlayView hide');
21480                 _this.fireEvent('OverlayViewHide', _this);
21481             }
21482             
21483         });
21484     },
21485     
21486     fromLatLngToContainerPixel: function(event)
21487     {
21488         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
21489     },
21490     
21491     isApplied: function() 
21492     {
21493         return this.getGmapContext() == false ? false : true;
21494     },
21495     
21496     getGmapContext: function() 
21497     {
21498         return this.gMapContext
21499     },
21500     
21501     GMapContext: function() 
21502     {
21503         var _map = new google.maps.Map(this.el.dom, this);
21504         var _marker = new google.maps.Marker({
21505             position: new google.maps.LatLng(this.latitude, this.longitude),
21506             map: _map,
21507             title: this.markerTitle,
21508             draggable: this.draggable
21509         });
21510         
21511         return {
21512             map: _map,
21513             marker: _marker,
21514             circle: null,
21515             location: _marker.position,
21516             radius: this.radius,
21517             locationName: this.locationName,
21518             addressComponents: {
21519                 formatted_address: null,
21520                 addressLine1: null,
21521                 addressLine2: null,
21522                 streetName: null,
21523                 streetNumber: null,
21524                 city: null,
21525                 district: null,
21526                 state: null,
21527                 stateOrProvince: null
21528             },
21529             settings: this,
21530             domContainer: this.el.dom,
21531             geodecoder: new google.maps.Geocoder()
21532         };
21533     },
21534     
21535     drawCircle: function(center, radius, options) 
21536     {
21537         if (this.gMapContext.circle != null) {
21538             this.gMapContext.circle.setMap(null);
21539         }
21540         if (radius > 0) {
21541             radius *= 1;
21542             options = Roo.apply({}, options, {
21543                 strokeColor: "#0000FF",
21544                 strokeOpacity: .35,
21545                 strokeWeight: 2,
21546                 fillColor: "#0000FF",
21547                 fillOpacity: .2
21548             });
21549             
21550             options.map = this.gMapContext.map;
21551             options.radius = radius;
21552             options.center = center;
21553             this.gMapContext.circle = new google.maps.Circle(options);
21554             return this.gMapContext.circle;
21555         }
21556         
21557         return null;
21558     },
21559     
21560     setPosition: function(location) 
21561     {
21562         this.gMapContext.location = location;
21563         this.gMapContext.marker.setPosition(location);
21564         this.gMapContext.map.panTo(location);
21565         this.drawCircle(location, this.gMapContext.radius, {});
21566         
21567         var _this = this;
21568         
21569         if (this.gMapContext.settings.enableReverseGeocode) {
21570             this.gMapContext.geodecoder.geocode({
21571                 latLng: this.gMapContext.location
21572             }, function(results, status) {
21573                 
21574                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
21575                     _this.gMapContext.locationName = results[0].formatted_address;
21576                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
21577                     
21578                     _this.fireEvent('positionchanged', this, location);
21579                 }
21580             });
21581             
21582             return;
21583         }
21584         
21585         this.fireEvent('positionchanged', this, location);
21586     },
21587     
21588     resize: function()
21589     {
21590         google.maps.event.trigger(this.gMapContext.map, "resize");
21591         
21592         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
21593         
21594         this.fireEvent('resize', this);
21595     },
21596     
21597     setPositionByLatLng: function(latitude, longitude)
21598     {
21599         this.setPosition(new google.maps.LatLng(latitude, longitude));
21600     },
21601     
21602     getCurrentPosition: function() 
21603     {
21604         return {
21605             latitude: this.gMapContext.location.lat(),
21606             longitude: this.gMapContext.location.lng()
21607         };
21608     },
21609     
21610     getAddressName: function() 
21611     {
21612         return this.gMapContext.locationName;
21613     },
21614     
21615     getAddressComponents: function() 
21616     {
21617         return this.gMapContext.addressComponents;
21618     },
21619     
21620     address_component_from_google_geocode: function(address_components) 
21621     {
21622         var result = {};
21623         
21624         for (var i = 0; i < address_components.length; i++) {
21625             var component = address_components[i];
21626             if (component.types.indexOf("postal_code") >= 0) {
21627                 result.postalCode = component.short_name;
21628             } else if (component.types.indexOf("street_number") >= 0) {
21629                 result.streetNumber = component.short_name;
21630             } else if (component.types.indexOf("route") >= 0) {
21631                 result.streetName = component.short_name;
21632             } else if (component.types.indexOf("neighborhood") >= 0) {
21633                 result.city = component.short_name;
21634             } else if (component.types.indexOf("locality") >= 0) {
21635                 result.city = component.short_name;
21636             } else if (component.types.indexOf("sublocality") >= 0) {
21637                 result.district = component.short_name;
21638             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
21639                 result.stateOrProvince = component.short_name;
21640             } else if (component.types.indexOf("country") >= 0) {
21641                 result.country = component.short_name;
21642             }
21643         }
21644         
21645         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
21646         result.addressLine2 = "";
21647         return result;
21648     },
21649     
21650     setZoomLevel: function(zoom)
21651     {
21652         this.gMapContext.map.setZoom(zoom);
21653     },
21654     
21655     show: function()
21656     {
21657         if(!this.el){
21658             return;
21659         }
21660         
21661         this.el.show();
21662         
21663         this.resize();
21664         
21665         this.fireEvent('show', this);
21666     },
21667     
21668     hide: function()
21669     {
21670         if(!this.el){
21671             return;
21672         }
21673         
21674         this.el.hide();
21675         
21676         this.fireEvent('hide', this);
21677     }
21678     
21679 });
21680
21681 Roo.apply(Roo.bootstrap.LocationPicker, {
21682     
21683     OverlayView : function(map, options)
21684     {
21685         options = options || {};
21686         
21687         this.setMap(map);
21688     }
21689     
21690     
21691 });/*
21692  * - LGPL
21693  *
21694  * Alert
21695  * 
21696  */
21697
21698 /**
21699  * @class Roo.bootstrap.Alert
21700  * @extends Roo.bootstrap.Component
21701  * Bootstrap Alert class
21702  * @cfg {String} title The title of alert
21703  * @cfg {String} html The content of alert
21704  * @cfg {String} weight (  success | info | warning | danger )
21705  * @cfg {String} faicon font-awesomeicon
21706  * 
21707  * @constructor
21708  * Create a new alert
21709  * @param {Object} config The config object
21710  */
21711
21712
21713 Roo.bootstrap.Alert = function(config){
21714     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
21715     
21716 };
21717
21718 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
21719     
21720     title: '',
21721     html: '',
21722     weight: false,
21723     faicon: false,
21724     
21725     getAutoCreate : function()
21726     {
21727         
21728         var cfg = {
21729             tag : 'div',
21730             cls : 'alert',
21731             cn : [
21732                 {
21733                     tag : 'i',
21734                     cls : 'roo-alert-icon'
21735                     
21736                 },
21737                 {
21738                     tag : 'b',
21739                     cls : 'roo-alert-title',
21740                     html : this.title
21741                 },
21742                 {
21743                     tag : 'span',
21744                     cls : 'roo-alert-text',
21745                     html : this.html
21746                 }
21747             ]
21748         };
21749         
21750         if(this.faicon){
21751             cfg.cn[0].cls += ' fa ' + this.faicon;
21752         }
21753         
21754         if(this.weight){
21755             cfg.cls += ' alert-' + this.weight;
21756         }
21757         
21758         return cfg;
21759     },
21760     
21761     initEvents: function() 
21762     {
21763         this.el.setVisibilityMode(Roo.Element.DISPLAY);
21764     },
21765     
21766     setTitle : function(str)
21767     {
21768         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
21769     },
21770     
21771     setText : function(str)
21772     {
21773         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
21774     },
21775     
21776     setWeight : function(weight)
21777     {
21778         if(this.weight){
21779             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
21780         }
21781         
21782         this.weight = weight;
21783         
21784         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
21785     },
21786     
21787     setIcon : function(icon)
21788     {
21789         if(this.faicon){
21790             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
21791         }
21792         
21793         this.faicon = icon
21794         
21795         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
21796     },
21797     
21798     hide: function() 
21799     {
21800         this.el.hide();   
21801     },
21802     
21803     show: function() 
21804     {  
21805         this.el.show();   
21806     }
21807     
21808 });
21809
21810