4c052a528542d81c2553ed196fd0d8f4be69aa10
[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     this.addEvents({
33         /**
34          * @event childrenrendered
35          * Fires when the children have been rendered..
36          * @param {Roo.bootstrap.Component} this
37          */
38         "childrenrendered" : true
39         
40         
41         
42     });
43     
44     
45 };
46
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
48     
49     
50     allowDomMove : false, // to stop relocations in parent onRender...
51     
52     cls : false,
53     
54     style : false,
55     
56     autoCreate : false,
57     
58     tooltip : null,
59     /**
60      * Initialize Events for the element
61      */
62     initEvents : function() { },
63     
64     xattr : false,
65     
66     parentId : false,
67     
68     can_build_overlaid : true,
69     
70     container_method : false,
71     
72     dataId : false,
73     
74     name : false,
75     
76     parent: function() {
77         // returns the parent component..
78         return Roo.ComponentMgr.get(this.parentId)
79         
80         
81     },
82     
83     // private
84     onRender : function(ct, position)
85     {
86        // Roo.log("Call onRender: " + this.xtype);
87         
88         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
89         
90         if(this.el){
91             if (this.el.attr('xtype')) {
92                 this.el.attr('xtypex', this.el.attr('xtype'));
93                 this.el.dom.removeAttribute('xtype');
94                 
95                 this.initEvents();
96             }
97             
98             return;
99         }
100         
101          
102         
103         var cfg = Roo.apply({},  this.getAutoCreate());
104         cfg.id = Roo.id();
105         
106         // fill in the extra attributes 
107         if (this.xattr && typeof(this.xattr) =='object') {
108             for (var i in this.xattr) {
109                 cfg[i] = this.xattr[i];
110             }
111         }
112         
113         if(this.dataId){
114             cfg.dataId = this.dataId;
115         }
116         
117         if (this.cls) {
118             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
119         }
120         
121         if (this.style) { // fixme needs to support more complex style data.
122             cfg.style = this.style;
123         }
124         
125         if(this.name){
126             cfg.name = this.name;
127         }
128         
129        
130         
131         this.el = ct.createChild(cfg, position);
132         
133         if (this.tooltip) {
134             this.tooltipEl().attr('tooltip', this.tooltip);
135         }
136         
137         if(this.tabIndex !== undefined){
138             this.el.dom.setAttribute('tabIndex', this.tabIndex);
139         }
140         this.initEvents();
141         
142         
143     },
144     /**
145      * Fetch the element to add children to
146      * @return {Roo.Element} defaults to this.el
147      */
148     getChildContainer : function()
149     {
150         return this.el;
151     },
152     /**
153      * Fetch the element to display the tooltip on.
154      * @return {Roo.Element} defaults to this.el
155      */
156     tooltipEl : function()
157     {
158         return this.el;
159     },
160         
161     addxtype  : function(tree,cntr)
162     {
163         var cn = this;
164         
165         cn = Roo.factory(tree);
166            
167         cn.parentType = this.xtype; //??
168         cn.parentId = this.id;
169         
170         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
171         if (typeof(cn.container_method) == 'string') {
172             cntr = cn.container_method;
173         }
174         
175         
176         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
177         
178         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
179         
180         var build_from_html =  Roo.XComponent.build_from_html;
181           
182         var is_body  = (tree.xtype == 'Body') ;
183           
184         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
185           
186         var self_cntr_el = Roo.get(this[cntr](false));
187         
188         // do not try and build conditional elements 
189         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
190             return false;
191         }
192         
193         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
194             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
195                 return this.addxtypeChild(tree,cntr);
196             }
197             
198             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199                 
200             if(echild){
201                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202             }
203             
204             Roo.log('skipping render');
205             return cn;
206             
207         }
208         
209         var ret = false;
210         if (!build_from_html) {
211             return false;
212         }
213         
214         // this i think handles overlaying multiple children of the same type
215         // with the sam eelement.. - which might be buggy..
216         while (true) {
217             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
218             
219             if (!echild) {
220                 break;
221             }
222             
223             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
224                 break;
225             }
226             
227             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
228         }
229         return ret;
230     },
231     
232     addxtypeChild : function (tree, cntr)
233     {
234         Roo.debug && Roo.log('addxtypeChild:' + cntr);
235         var cn = this;
236         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237         
238         
239         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
240                     (typeof(tree['flexy:foreach']) != 'undefined');
241           
242         
243         
244          skip_children = false;
245         // render the element if it's not BODY.
246         if (tree.xtype != 'Body') {
247            
248             cn = Roo.factory(tree);
249            
250             cn.parentType = this.xtype; //??
251             cn.parentId = this.id;
252             
253             var build_from_html =  Roo.XComponent.build_from_html;
254             
255             
256             // does the container contain child eleemnts with 'xtype' attributes.
257             // that match this xtype..
258             // note - when we render we create these as well..
259             // so we should check to see if body has xtype set.
260             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
261                
262                 var self_cntr_el = Roo.get(this[cntr](false));
263                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
264                 if (echild) { 
265                     Roo.log(Roo.XComponent.build_from_html);
266                     Roo.log("got echild:");
267                     Roo.log(echild);
268                 }
269                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
270                 // and are not displayed -this causes this to use up the wrong element when matching.
271                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272                 
273                 
274                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
275                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
276                   
277                   
278                   
279                     cn.el = echild;
280                   //  Roo.log("GOT");
281                     //echild.dom.removeAttribute('xtype');
282                 } else {
283                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
284                     Roo.debug && Roo.log(self_cntr_el);
285                     Roo.debug && Roo.log(echild);
286                     Roo.debug && Roo.log(cn);
287                 }
288             }
289            
290             
291            
292             // if object has flexy:if - then it may or may not be rendered.
293             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
294                 // skip a flexy if element.
295                 Roo.debug && Roo.log('skipping render');
296                 Roo.debug && Roo.log(tree);
297                 if (!cn.el) {
298                     Roo.debug && Roo.log('skipping all children');
299                     skip_children = true;
300                 }
301                 
302              } else {
303                  
304                 // actually if flexy:foreach is found, we really want to create 
305                 // multiple copies here...
306                 //Roo.log('render');
307                 //Roo.log(this[cntr]());
308                 cn.render(this[cntr](true));
309              }
310             // then add the element..
311         }
312         
313         
314         // handle the kids..
315         
316         var nitems = [];
317         /*
318         if (typeof (tree.menu) != 'undefined') {
319             tree.menu.parentType = cn.xtype;
320             tree.menu.triggerEl = cn.el;
321             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
322             
323         }
324         */
325         if (!tree.items || !tree.items.length) {
326             cn.items = nitems;
327             return cn;
328         }
329         var items = tree.items;
330         delete tree.items;
331         
332         //Roo.log(items.length);
333             // add the items..
334         if (!skip_children) {    
335             for(var i =0;i < items.length;i++) {
336                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
337             }
338         }
339         
340         cn.items = nitems;
341         
342         this.fireEvent('childrenrendered', this);
343         
344         return cn;
345     } 
346     
347     
348 });
349
350  /*
351  * - LGPL
352  *
353  * Body
354  * 
355  */
356
357 /**
358  * @class Roo.bootstrap.Body
359  * @extends Roo.bootstrap.Component
360  * Bootstrap Body class
361  * 
362  * @constructor
363  * Create a new body
364  * @param {Object} config The config object
365  */
366
367 Roo.bootstrap.Body = function(config){
368     Roo.bootstrap.Body.superclass.constructor.call(this, config);
369     this.el = Roo.get(document.body);
370     if (this.cls && this.cls.length) {
371         Roo.get(document.body).addClass(this.cls);
372     }
373 };
374
375 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
376       
377         autoCreate : {
378         cls: 'container'
379     },
380     onRender : function(ct, position)
381     {
382        /* Roo.log("Roo.bootstrap.Body - onRender");
383         if (this.cls && this.cls.length) {
384             Roo.get(document.body).addClass(this.cls);
385         }
386         // style??? xttr???
387         */
388     }
389     
390     
391  
392    
393 });
394
395  /*
396  * - LGPL
397  *
398  * button group
399  * 
400  */
401
402
403 /**
404  * @class Roo.bootstrap.ButtonGroup
405  * @extends Roo.bootstrap.Component
406  * Bootstrap ButtonGroup class
407  * @cfg {String} size lg | sm | xs (default empty normal)
408  * @cfg {String} align vertical | justified  (default none)
409  * @cfg {String} direction up | down (default down)
410  * @cfg {Boolean} toolbar false | true
411  * @cfg {Boolean} btn true | false
412  * 
413  * 
414  * @constructor
415  * Create a new Input
416  * @param {Object} config The config object
417  */
418
419 Roo.bootstrap.ButtonGroup = function(config){
420     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
421 };
422
423 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
424     
425     size: '',
426     align: '',
427     direction: '',
428     toolbar: false,
429     btn: true,
430
431     getAutoCreate : function(){
432         var cfg = {
433             cls: 'btn-group',
434             html : null
435         }
436         
437         cfg.html = this.html || cfg.html;
438         
439         if (this.toolbar) {
440             cfg = {
441                 cls: 'btn-toolbar',
442                 html: null
443             }
444             
445             return cfg;
446         }
447         
448         if (['vertical','justified'].indexOf(this.align)!==-1) {
449             cfg.cls = 'btn-group-' + this.align;
450             
451             if (this.align == 'justified') {
452                 console.log(this.items);
453             }
454         }
455         
456         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
457             cfg.cls += ' btn-group-' + this.size;
458         }
459         
460         if (this.direction == 'up') {
461             cfg.cls += ' dropup' ;
462         }
463         
464         return cfg;
465     }
466    
467 });
468
469  /*
470  * - LGPL
471  *
472  * button
473  * 
474  */
475
476 /**
477  * @class Roo.bootstrap.Button
478  * @extends Roo.bootstrap.Component
479  * Bootstrap Button class
480  * @cfg {String} html The button content
481  * @cfg {String} weight (  primary | success | info | warning | danger | link ) default 
482  * @cfg {String} size ( lg | sm | xs)
483  * @cfg {String} tag ( a | input | submit)
484  * @cfg {String} href empty or href
485  * @cfg {Boolean} disabled default false;
486  * @cfg {Boolean} isClose default false;
487  * @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)
488  * @cfg {String} badge text for badge
489  * @cfg {String} theme default 
490  * @cfg {Boolean} inverse 
491  * @cfg {Boolean} toggle 
492  * @cfg {String} ontext text for on toggle state
493  * @cfg {String} offtext text for off toggle state
494  * @cfg {Boolean} defaulton 
495  * @cfg {Boolean} preventDefault  default true
496  * @cfg {Boolean} removeClass remove the standard class..
497  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
498  * 
499  * @constructor
500  * Create a new button
501  * @param {Object} config The config object
502  */
503
504
505 Roo.bootstrap.Button = function(config){
506     Roo.bootstrap.Button.superclass.constructor.call(this, config);
507     this.addEvents({
508         // raw events
509         /**
510          * @event click
511          * When a butotn is pressed
512          * @param {Roo.bootstrap.Button} this
513          * @param {Roo.EventObject} e
514          */
515         "click" : true,
516          /**
517          * @event toggle
518          * After the button has been toggles
519          * @param {Roo.EventObject} e
520          * @param {boolean} pressed (also available as button.pressed)
521          */
522         "toggle" : true
523     });
524 };
525
526 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
527     html: false,
528     active: false,
529     weight: '',
530     size: '',
531     tag: 'button',
532     href: '',
533     disabled: false,
534     isClose: false,
535     glyphicon: '',
536     badge: '',
537     theme: 'default',
538     inverse: false,
539     
540     toggle: false,
541     ontext: 'ON',
542     offtext: 'OFF',
543     defaulton: true,
544     preventDefault: true,
545     removeClass: false,
546     name: false,
547     target: false,
548     
549     
550     pressed : null,
551      
552     
553     getAutoCreate : function(){
554         
555         var cfg = {
556             tag : 'button',
557             cls : 'roo-button',
558             html: ''
559         };
560         
561         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
562             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
563             this.tag = 'button';
564         } else {
565             cfg.tag = this.tag;
566         }
567         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
568         
569         if (this.toggle == true) {
570             cfg={
571                 tag: 'div',
572                 cls: 'slider-frame roo-button',
573                 cn: [
574                     {
575                         tag: 'span',
576                         'data-on-text':'ON',
577                         'data-off-text':'OFF',
578                         cls: 'slider-button',
579                         html: this.offtext
580                     }
581                 ]
582             };
583             
584             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
585                 cfg.cls += ' '+this.weight;
586             }
587             
588             return cfg;
589         }
590         
591         if (this.isClose) {
592             cfg.cls += ' close';
593             
594             cfg["aria-hidden"] = true;
595             
596             cfg.html = "&times;";
597             
598             return cfg;
599         }
600         
601          
602         if (this.theme==='default') {
603             cfg.cls = 'btn roo-button';
604             
605             //if (this.parentType != 'Navbar') {
606             this.weight = this.weight.length ?  this.weight : 'default';
607             //}
608             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
609                 
610                 cfg.cls += ' btn-' + this.weight;
611             }
612         } else if (this.theme==='glow') {
613             
614             cfg.tag = 'a';
615             cfg.cls = 'btn-glow roo-button';
616             
617             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
618                 
619                 cfg.cls += ' ' + this.weight;
620             }
621         }
622    
623         
624         if (this.inverse) {
625             this.cls += ' inverse';
626         }
627         
628         
629         if (this.active) {
630             cfg.cls += ' active';
631         }
632         
633         if (this.disabled) {
634             cfg.disabled = 'disabled';
635         }
636         
637         if (this.items) {
638             Roo.log('changing to ul' );
639             cfg.tag = 'ul';
640             this.glyphicon = 'caret';
641         }
642         
643         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
644          
645         //gsRoo.log(this.parentType);
646         if (this.parentType === 'Navbar' && !this.parent().bar) {
647             Roo.log('changing to li?');
648             
649             cfg.tag = 'li';
650             
651             cfg.cls = '';
652             cfg.cn =  [{
653                 tag : 'a',
654                 cls : 'roo-button',
655                 html : this.html,
656                 href : this.href || '#'
657             }];
658             if (this.menu) {
659                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
660                 cfg.cls += ' dropdown';
661             }   
662             
663             delete cfg.html;
664             
665         }
666         
667        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
668         
669         if (this.glyphicon) {
670             cfg.html = ' ' + cfg.html;
671             
672             cfg.cn = [
673                 {
674                     tag: 'span',
675                     cls: 'glyphicon glyphicon-' + this.glyphicon
676                 }
677             ];
678         }
679         
680         if (this.badge) {
681             cfg.html += ' ';
682             
683             cfg.tag = 'a';
684             
685 //            cfg.cls='btn roo-button';
686             
687             cfg.href=this.href;
688             
689             var value = cfg.html;
690             
691             if(this.glyphicon){
692                 value = {
693                             tag: 'span',
694                             cls: 'glyphicon glyphicon-' + this.glyphicon,
695                             html: this.html
696                         };
697                 
698             }
699             
700             cfg.cn = [
701                 value,
702                 {
703                     tag: 'span',
704                     cls: 'badge',
705                     html: this.badge
706                 }
707             ];
708             
709             cfg.html='';
710         }
711         
712         if (this.menu) {
713             cfg.cls += ' dropdown';
714             cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
715         }
716         
717         if (cfg.tag !== 'a' && this.href !== '') {
718             throw "Tag must be a to set href.";
719         } else if (this.href.length > 0) {
720             cfg.href = this.href;
721         }
722         
723         if(this.removeClass){
724             cfg.cls = '';
725         }
726         
727         if(this.target){
728             cfg.target = this.target;
729         }
730         
731         return cfg;
732     },
733     initEvents: function() {
734        // Roo.log('init events?');
735 //        Roo.log(this.el.dom);
736         // add the menu...
737         
738         if (typeof (this.menu) != 'undefined') {
739             this.menu.parentType = this.xtype;
740             this.menu.triggerEl = this.el;
741             this.addxtype(Roo.apply({}, this.menu));
742         }
743
744
745        if (this.el.hasClass('roo-button')) {
746             this.el.on('click', this.onClick, this);
747        } else {
748             this.el.select('.roo-button').on('click', this.onClick, this);
749        }
750        
751        if(this.removeClass){
752            this.el.on('click', this.onClick, this);
753        }
754        
755        this.el.enableDisplayMode();
756         
757     },
758     onClick : function(e)
759     {
760         if (this.disabled) {
761             return;
762         }
763         
764         
765         Roo.log('button on click ');
766         if(this.preventDefault){
767             e.preventDefault();
768         }
769         if (this.pressed === true || this.pressed === false) {
770             this.pressed = !this.pressed;
771             this.el[this.pressed ? 'addClass' : 'removeClass']('active');
772             this.fireEvent('toggle', this, e, this.pressed);
773         }
774         
775         
776         this.fireEvent('click', this, e);
777     },
778     
779     /**
780      * Enables this button
781      */
782     enable : function()
783     {
784         this.disabled = false;
785         this.el.removeClass('disabled');
786     },
787     
788     /**
789      * Disable this button
790      */
791     disable : function()
792     {
793         this.disabled = true;
794         this.el.addClass('disabled');
795     },
796      /**
797      * sets the active state on/off, 
798      * @param {Boolean} state (optional) Force a particular state
799      */
800     setActive : function(v) {
801         
802         this.el[v ? 'addClass' : 'removeClass']('active');
803     },
804      /**
805      * toggles the current active state 
806      */
807     toggleActive : function()
808     {
809        var active = this.el.hasClass('active');
810        this.setActive(!active);
811        
812         
813     },
814     setText : function(str)
815     {
816         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
817     },
818     getText : function()
819     {
820         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
821     },
822     hide: function() {
823        
824      
825         this.el.hide();   
826     },
827     show: function() {
828        
829         this.el.show();   
830     }
831     
832     
833 });
834
835  /*
836  * - LGPL
837  *
838  * column
839  * 
840  */
841
842 /**
843  * @class Roo.bootstrap.Column
844  * @extends Roo.bootstrap.Component
845  * Bootstrap Column class
846  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
847  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
848  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
849  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
850  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
851  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
852  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
853  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
854  *
855  * 
856  * @cfg {Boolean} hidden (true|false) hide the element
857  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
858  * @cfg {String} fa (ban|check|...) font awesome icon
859  * @cfg {Number} fasize (1|2|....) font awsome size
860
861  * @cfg {String} icon (info-sign|check|...) glyphicon name
862
863  * @cfg {String} html content of column.
864  * 
865  * @constructor
866  * Create a new Column
867  * @param {Object} config The config object
868  */
869
870 Roo.bootstrap.Column = function(config){
871     Roo.bootstrap.Column.superclass.constructor.call(this, config);
872 };
873
874 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
875     
876     xs: false,
877     sm: false,
878     md: false,
879     lg: false,
880     xsoff: false,
881     smoff: false,
882     mdoff: false,
883     lgoff: false,
884     html: '',
885     offset: 0,
886     alert: false,
887     fa: false,
888     icon : false,
889     hidden : false,
890     fasize : 1,
891     
892     getAutoCreate : function(){
893         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
894         
895         cfg = {
896             tag: 'div',
897             cls: 'column'
898         };
899         
900         var settings=this;
901         ['xs','sm','md','lg'].map(function(size){
902             //Roo.log( size + ':' + settings[size]);
903             
904             if (settings[size+'off'] !== false) {
905                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
906             }
907             
908             if (settings[size] === false) {
909                 return;
910             }
911             Roo.log(settings[size]);
912             if (!settings[size]) { // 0 = hidden
913                 cfg.cls += ' hidden-' + size;
914                 return;
915             }
916             cfg.cls += ' col-' + size + '-' + settings[size];
917             
918         });
919         
920         if (this.hidden) {
921             cfg.cls += ' hidden';
922         }
923         
924         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
925             cfg.cls +=' alert alert-' + this.alert;
926         }
927         
928         
929         if (this.html.length) {
930             cfg.html = this.html;
931         }
932         if (this.fa) {
933             var fasize = '';
934             if (this.fasize > 1) {
935                 fasize = ' fa-' + this.fasize + 'x';
936             }
937             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
938             
939             
940         }
941         if (this.icon) {
942             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
943         }
944         
945         return cfg;
946     }
947    
948 });
949
950  
951
952  /*
953  * - LGPL
954  *
955  * page container.
956  * 
957  */
958
959
960 /**
961  * @class Roo.bootstrap.Container
962  * @extends Roo.bootstrap.Component
963  * Bootstrap Container class
964  * @cfg {Boolean} jumbotron is it a jumbotron element
965  * @cfg {String} html content of element
966  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
967  * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
968  * @cfg {String} header content of header (for panel)
969  * @cfg {String} footer content of footer (for panel)
970  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
971  * @cfg {String} tag (header|aside|section) type of HTML tag.
972  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
973  * @cfg {String} fa (ban|check|...) font awesome icon
974  * @cfg {String} icon (info-sign|check|...) glyphicon name
975  * @cfg {Boolean} hidden (true|false) hide the element
976
977  *     
978  * @constructor
979  * Create a new Container
980  * @param {Object} config The config object
981  */
982
983 Roo.bootstrap.Container = function(config){
984     Roo.bootstrap.Container.superclass.constructor.call(this, config);
985 };
986
987 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
988     
989     jumbotron : false,
990     well: '',
991     panel : '',
992     header: '',
993     footer : '',
994     sticky: '',
995     tag : false,
996     alert : false,
997     fa: false,
998     icon : false,
999   
1000      
1001     getChildContainer : function() {
1002         
1003         if(!this.el){
1004             return false;
1005         }
1006         
1007         if (this.panel.length) {
1008             return this.el.select('.panel-body',true).first();
1009         }
1010         
1011         return this.el;
1012     },
1013     
1014     
1015     getAutoCreate : function(){
1016         
1017         var cfg = {
1018             tag : this.tag || 'div',
1019             html : '',
1020             cls : ''
1021         };
1022         if (this.jumbotron) {
1023             cfg.cls = 'jumbotron';
1024         }
1025         
1026         
1027         
1028         // - this is applied by the parent..
1029         //if (this.cls) {
1030         //    cfg.cls = this.cls + '';
1031         //}
1032         
1033         if (this.sticky.length) {
1034             
1035             var bd = Roo.get(document.body);
1036             if (!bd.hasClass('bootstrap-sticky')) {
1037                 bd.addClass('bootstrap-sticky');
1038                 Roo.select('html',true).setStyle('height', '100%');
1039             }
1040              
1041             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1042         }
1043         
1044         
1045         if (this.well.length) {
1046             switch (this.well) {
1047                 case 'lg':
1048                 case 'sm':
1049                     cfg.cls +=' well well-' +this.well;
1050                     break;
1051                 default:
1052                     cfg.cls +=' well';
1053                     break;
1054             }
1055         }
1056         
1057         if (this.hidden) {
1058             cfg.cls += ' hidden';
1059         }
1060         
1061         
1062         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1063             cfg.cls +=' alert alert-' + this.alert;
1064         }
1065         
1066         var body = cfg;
1067         
1068         if (this.panel.length) {
1069             cfg.cls += ' panel panel-' + this.panel;
1070             cfg.cn = [];
1071             if (this.header.length) {
1072                 cfg.cn.push({
1073                     
1074                     cls : 'panel-heading',
1075                     cn : [{
1076                         tag: 'h3',
1077                         cls : 'panel-title',
1078                         html : this.header
1079                     }]
1080                     
1081                 });
1082             }
1083             body = false;
1084             cfg.cn.push({
1085                 cls : 'panel-body',
1086                 html : this.html
1087             });
1088             
1089             
1090             if (this.footer.length) {
1091                 cfg.cn.push({
1092                     cls : 'panel-footer',
1093                     html : this.footer
1094                     
1095                 });
1096             }
1097             
1098         }
1099         
1100         if (body) {
1101             body.html = this.html || cfg.html;
1102             // prefix with the icons..
1103             if (this.fa) {
1104                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1105             }
1106             if (this.icon) {
1107                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1108             }
1109             
1110             
1111         }
1112         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1113             cfg.cls =  'container';
1114         }
1115         
1116         return cfg;
1117     },
1118     
1119     titleEl : function()
1120     {
1121         if(!this.el || !this.panel.length || !this.header.length){
1122             return;
1123         }
1124         
1125         return this.el.select('.panel-title',true).first();
1126     },
1127     
1128     setTitle : function(v)
1129     {
1130         var titleEl = this.titleEl();
1131         
1132         if(!titleEl){
1133             return;
1134         }
1135         
1136         titleEl.dom.innerHTML = v;
1137     },
1138     
1139     getTitle : function()
1140     {
1141         
1142         var titleEl = this.titleEl();
1143         
1144         if(!titleEl){
1145             return '';
1146         }
1147         
1148         return titleEl.dom.innerHTML;
1149     },
1150     
1151     show : function() {
1152         this.el.removeClass('hidden');
1153     },
1154     hide: function() {
1155         if (!this.el.hasClass('hidden')) {
1156             this.el.addClass('hidden');
1157         }
1158         
1159     }
1160    
1161 });
1162
1163  /*
1164  * - LGPL
1165  *
1166  * image
1167  * 
1168  */
1169
1170
1171 /**
1172  * @class Roo.bootstrap.Img
1173  * @extends Roo.bootstrap.Component
1174  * Bootstrap Img class
1175  * @cfg {Boolean} imgResponsive false | true
1176  * @cfg {String} border rounded | circle | thumbnail
1177  * @cfg {String} src image source
1178  * @cfg {String} alt image alternative text
1179  * @cfg {String} href a tag href
1180  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1181  * 
1182  * @constructor
1183  * Create a new Input
1184  * @param {Object} config The config object
1185  */
1186
1187 Roo.bootstrap.Img = function(config){
1188     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1189     
1190     this.addEvents({
1191         // img events
1192         /**
1193          * @event click
1194          * The img click event for the img.
1195          * @param {Roo.EventObject} e
1196          */
1197         "click" : true
1198     });
1199 };
1200
1201 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1202     
1203     imgResponsive: true,
1204     border: '',
1205     src: '',
1206     href: false,
1207     target: false,
1208
1209     getAutoCreate : function(){
1210         
1211         var cfg = {
1212             tag: 'img',
1213             cls: (this.imgResponsive) ? 'img-responsive' : '',
1214             html : null
1215         }
1216         
1217         cfg.html = this.html || cfg.html;
1218         
1219         cfg.src = this.src || cfg.src;
1220         
1221         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1222             cfg.cls += ' img-' + this.border;
1223         }
1224         
1225         if(this.alt){
1226             cfg.alt = this.alt;
1227         }
1228         
1229         if(this.href){
1230             var a = {
1231                 tag: 'a',
1232                 href: this.href,
1233                 cn: [
1234                     cfg
1235                 ]
1236             }
1237             
1238             if(this.target){
1239                 a.target = this.target;
1240             }
1241             
1242         }
1243         
1244         
1245         return (this.href) ? a : cfg;
1246     },
1247     
1248     initEvents: function() {
1249         
1250         if(!this.href){
1251             this.el.on('click', this.onClick, this);
1252         }
1253     },
1254     
1255     onClick : function(e)
1256     {
1257         Roo.log('img onclick');
1258         this.fireEvent('click', this, e);
1259     }
1260    
1261 });
1262
1263  /*
1264  * - LGPL
1265  *
1266  * image
1267  * 
1268  */
1269
1270
1271 /**
1272  * @class Roo.bootstrap.Link
1273  * @extends Roo.bootstrap.Component
1274  * Bootstrap Link Class
1275  * @cfg {String} alt image alternative text
1276  * @cfg {String} href a tag href
1277  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1278  * @cfg {String} html the content of the link.
1279  * @cfg {String} anchor name for the anchor link
1280
1281  * @cfg {Boolean} preventDefault (true | false) default false
1282
1283  * 
1284  * @constructor
1285  * Create a new Input
1286  * @param {Object} config The config object
1287  */
1288
1289 Roo.bootstrap.Link = function(config){
1290     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1291     
1292     this.addEvents({
1293         // img events
1294         /**
1295          * @event click
1296          * The img click event for the img.
1297          * @param {Roo.EventObject} e
1298          */
1299         "click" : true
1300     });
1301 };
1302
1303 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1304     
1305     href: false,
1306     target: false,
1307     preventDefault: false,
1308     anchor : false,
1309     alt : false,
1310
1311     getAutoCreate : function()
1312     {
1313         
1314         var cfg = {
1315             tag: 'a'
1316         };
1317         // anchor's do not require html/href...
1318         if (this.anchor === false) {
1319             cfg.html = this.html || 'html-missing';
1320             cfg.href = this.href || '#';
1321         } else {
1322             cfg.name = this.anchor;
1323             if (this.html !== false) {
1324                 cfg.html = this.html;
1325             }
1326             if (this.href !== false) {
1327                 cfg.href = this.href;
1328             }
1329         }
1330         
1331         if(this.alt !== false){
1332             cfg.alt = this.alt;
1333         }
1334         
1335         
1336         if(this.target !== false) {
1337             cfg.target = this.target;
1338         }
1339         
1340         return cfg;
1341     },
1342     
1343     initEvents: function() {
1344         
1345         if(!this.href || this.preventDefault){
1346             this.el.on('click', this.onClick, this);
1347         }
1348     },
1349     
1350     onClick : function(e)
1351     {
1352         if(this.preventDefault){
1353             e.preventDefault();
1354         }
1355         //Roo.log('img onclick');
1356         this.fireEvent('click', this, e);
1357     }
1358    
1359 });
1360
1361  /*
1362  * - LGPL
1363  *
1364  * header
1365  * 
1366  */
1367
1368 /**
1369  * @class Roo.bootstrap.Header
1370  * @extends Roo.bootstrap.Component
1371  * Bootstrap Header class
1372  * @cfg {String} html content of header
1373  * @cfg {Number} level (1|2|3|4|5|6) default 1
1374  * 
1375  * @constructor
1376  * Create a new Header
1377  * @param {Object} config The config object
1378  */
1379
1380
1381 Roo.bootstrap.Header  = function(config){
1382     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1383 };
1384
1385 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1386     
1387     //href : false,
1388     html : false,
1389     level : 1,
1390     
1391     
1392     
1393     getAutoCreate : function(){
1394         
1395         
1396         
1397         var cfg = {
1398             tag: 'h' + (1 *this.level),
1399             html: this.html || ''
1400         } ;
1401         
1402         return cfg;
1403     }
1404    
1405 });
1406
1407  
1408
1409  /*
1410  * Based on:
1411  * Ext JS Library 1.1.1
1412  * Copyright(c) 2006-2007, Ext JS, LLC.
1413  *
1414  * Originally Released Under LGPL - original licence link has changed is not relivant.
1415  *
1416  * Fork - LGPL
1417  * <script type="text/javascript">
1418  */
1419  
1420 /**
1421  * @class Roo.bootstrap.MenuMgr
1422  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1423  * @singleton
1424  */
1425 Roo.bootstrap.MenuMgr = function(){
1426    var menus, active, groups = {}, attached = false, lastShow = new Date();
1427
1428    // private - called when first menu is created
1429    function init(){
1430        menus = {};
1431        active = new Roo.util.MixedCollection();
1432        Roo.get(document).addKeyListener(27, function(){
1433            if(active.length > 0){
1434                hideAll();
1435            }
1436        });
1437    }
1438
1439    // private
1440    function hideAll(){
1441        if(active && active.length > 0){
1442            var c = active.clone();
1443            c.each(function(m){
1444                m.hide();
1445            });
1446        }
1447    }
1448
1449    // private
1450    function onHide(m){
1451        active.remove(m);
1452        if(active.length < 1){
1453            Roo.get(document).un("mouseup", onMouseDown);
1454             
1455            attached = false;
1456        }
1457    }
1458
1459    // private
1460    function onShow(m){
1461        var last = active.last();
1462        lastShow = new Date();
1463        active.add(m);
1464        if(!attached){
1465           Roo.get(document).on("mouseup", onMouseDown);
1466            
1467            attached = true;
1468        }
1469        if(m.parentMenu){
1470           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1471           m.parentMenu.activeChild = m;
1472        }else if(last && last.isVisible()){
1473           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1474        }
1475    }
1476
1477    // private
1478    function onBeforeHide(m){
1479        if(m.activeChild){
1480            m.activeChild.hide();
1481        }
1482        if(m.autoHideTimer){
1483            clearTimeout(m.autoHideTimer);
1484            delete m.autoHideTimer;
1485        }
1486    }
1487
1488    // private
1489    function onBeforeShow(m){
1490        var pm = m.parentMenu;
1491        if(!pm && !m.allowOtherMenus){
1492            hideAll();
1493        }else if(pm && pm.activeChild && active != m){
1494            pm.activeChild.hide();
1495        }
1496    }
1497
1498    // private
1499    function onMouseDown(e){
1500         Roo.log("on MouseDown");
1501         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1502            hideAll();
1503         }
1504         
1505         
1506    }
1507
1508    // private
1509    function onBeforeCheck(mi, state){
1510        if(state){
1511            var g = groups[mi.group];
1512            for(var i = 0, l = g.length; i < l; i++){
1513                if(g[i] != mi){
1514                    g[i].setChecked(false);
1515                }
1516            }
1517        }
1518    }
1519
1520    return {
1521
1522        /**
1523         * Hides all menus that are currently visible
1524         */
1525        hideAll : function(){
1526             hideAll();  
1527        },
1528
1529        // private
1530        register : function(menu){
1531            if(!menus){
1532                init();
1533            }
1534            menus[menu.id] = menu;
1535            menu.on("beforehide", onBeforeHide);
1536            menu.on("hide", onHide);
1537            menu.on("beforeshow", onBeforeShow);
1538            menu.on("show", onShow);
1539            var g = menu.group;
1540            if(g && menu.events["checkchange"]){
1541                if(!groups[g]){
1542                    groups[g] = [];
1543                }
1544                groups[g].push(menu);
1545                menu.on("checkchange", onCheck);
1546            }
1547        },
1548
1549         /**
1550          * Returns a {@link Roo.menu.Menu} object
1551          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1552          * be used to generate and return a new Menu instance.
1553          */
1554        get : function(menu){
1555            if(typeof menu == "string"){ // menu id
1556                return menus[menu];
1557            }else if(menu.events){  // menu instance
1558                return menu;
1559            }
1560            /*else if(typeof menu.length == 'number'){ // array of menu items?
1561                return new Roo.bootstrap.Menu({items:menu});
1562            }else{ // otherwise, must be a config
1563                return new Roo.bootstrap.Menu(menu);
1564            }
1565            */
1566            return false;
1567        },
1568
1569        // private
1570        unregister : function(menu){
1571            delete menus[menu.id];
1572            menu.un("beforehide", onBeforeHide);
1573            menu.un("hide", onHide);
1574            menu.un("beforeshow", onBeforeShow);
1575            menu.un("show", onShow);
1576            var g = menu.group;
1577            if(g && menu.events["checkchange"]){
1578                groups[g].remove(menu);
1579                menu.un("checkchange", onCheck);
1580            }
1581        },
1582
1583        // private
1584        registerCheckable : function(menuItem){
1585            var g = menuItem.group;
1586            if(g){
1587                if(!groups[g]){
1588                    groups[g] = [];
1589                }
1590                groups[g].push(menuItem);
1591                menuItem.on("beforecheckchange", onBeforeCheck);
1592            }
1593        },
1594
1595        // private
1596        unregisterCheckable : function(menuItem){
1597            var g = menuItem.group;
1598            if(g){
1599                groups[g].remove(menuItem);
1600                menuItem.un("beforecheckchange", onBeforeCheck);
1601            }
1602        }
1603    };
1604 }();/*
1605  * - LGPL
1606  *
1607  * menu
1608  * 
1609  */
1610
1611 /**
1612  * @class Roo.bootstrap.Menu
1613  * @extends Roo.bootstrap.Component
1614  * Bootstrap Menu class - container for MenuItems
1615  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1616  * 
1617  * @constructor
1618  * Create a new Menu
1619  * @param {Object} config The config object
1620  */
1621
1622
1623 Roo.bootstrap.Menu = function(config){
1624     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1625     if (this.registerMenu) {
1626         Roo.bootstrap.MenuMgr.register(this);
1627     }
1628     this.addEvents({
1629         /**
1630          * @event beforeshow
1631          * Fires before this menu is displayed
1632          * @param {Roo.menu.Menu} this
1633          */
1634         beforeshow : true,
1635         /**
1636          * @event beforehide
1637          * Fires before this menu is hidden
1638          * @param {Roo.menu.Menu} this
1639          */
1640         beforehide : true,
1641         /**
1642          * @event show
1643          * Fires after this menu is displayed
1644          * @param {Roo.menu.Menu} this
1645          */
1646         show : true,
1647         /**
1648          * @event hide
1649          * Fires after this menu is hidden
1650          * @param {Roo.menu.Menu} this
1651          */
1652         hide : true,
1653         /**
1654          * @event click
1655          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1656          * @param {Roo.menu.Menu} this
1657          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1658          * @param {Roo.EventObject} e
1659          */
1660         click : true,
1661         /**
1662          * @event mouseover
1663          * Fires when the mouse is hovering over this menu
1664          * @param {Roo.menu.Menu} this
1665          * @param {Roo.EventObject} e
1666          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1667          */
1668         mouseover : true,
1669         /**
1670          * @event mouseout
1671          * Fires when the mouse exits this menu
1672          * @param {Roo.menu.Menu} this
1673          * @param {Roo.EventObject} e
1674          * @param {Roo.menu.Item} menuItem The menu item that was clicked
1675          */
1676         mouseout : true,
1677         /**
1678          * @event itemclick
1679          * Fires when a menu item contained in this menu is clicked
1680          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1681          * @param {Roo.EventObject} e
1682          */
1683         itemclick: true
1684     });
1685     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1686 };
1687
1688 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
1689     
1690    /// html : false,
1691     //align : '',
1692     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
1693     type: false,
1694     /**
1695      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1696      */
1697     registerMenu : true,
1698     
1699     menuItems :false, // stores the menu items..
1700     
1701     hidden:true,
1702     
1703     parentMenu : false,
1704     
1705     getChildContainer : function() {
1706         return this.el;  
1707     },
1708     
1709     getAutoCreate : function(){
1710          
1711         //if (['right'].indexOf(this.align)!==-1) {
1712         //    cfg.cn[1].cls += ' pull-right'
1713         //}
1714         
1715         
1716         var cfg = {
1717             tag : 'ul',
1718             cls : 'dropdown-menu' ,
1719             style : 'z-index:1000'
1720             
1721         }
1722         
1723         if (this.type === 'submenu') {
1724             cfg.cls = 'submenu active';
1725         }
1726         if (this.type === 'treeview') {
1727             cfg.cls = 'treeview-menu';
1728         }
1729         
1730         return cfg;
1731     },
1732     initEvents : function() {
1733         
1734        // Roo.log("ADD event");
1735        // Roo.log(this.triggerEl.dom);
1736         this.triggerEl.on('click', this.onTriggerPress, this);
1737         this.triggerEl.addClass('dropdown-toggle');
1738         this.el.on(Roo.isTouch ? 'touchstart' : 'click'   , this.onClick, this);
1739
1740         this.el.on("mouseover", this.onMouseOver, this);
1741         this.el.on("mouseout", this.onMouseOut, this);
1742         
1743         
1744     },
1745     findTargetItem : function(e){
1746         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
1747         if(!t){
1748             return false;
1749         }
1750         //Roo.log(t);         Roo.log(t.id);
1751         if(t && t.id){
1752             //Roo.log(this.menuitems);
1753             return this.menuitems.get(t.id);
1754             
1755             //return this.items.get(t.menuItemId);
1756         }
1757         
1758         return false;
1759     },
1760     onClick : function(e){
1761         Roo.log("menu.onClick");
1762         var t = this.findTargetItem(e);
1763         if(!t || t.isContainer){
1764             return;
1765         }
1766         Roo.log(e);
1767         /*
1768         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
1769             if(t == this.activeItem && t.shouldDeactivate(e)){
1770                 this.activeItem.deactivate();
1771                 delete this.activeItem;
1772                 return;
1773             }
1774             if(t.canActivate){
1775                 this.setActiveItem(t, true);
1776             }
1777             return;
1778             
1779             
1780         }
1781         */
1782        
1783         Roo.log('pass click event');
1784         
1785         t.onClick(e);
1786         
1787         this.fireEvent("click", this, t, e);
1788         
1789         this.hide();
1790     },
1791      onMouseOver : function(e){
1792         var t  = this.findTargetItem(e);
1793         //Roo.log(t);
1794         //if(t){
1795         //    if(t.canActivate && !t.disabled){
1796         //        this.setActiveItem(t, true);
1797         //    }
1798         //}
1799         
1800         this.fireEvent("mouseover", this, e, t);
1801     },
1802     isVisible : function(){
1803         return !this.hidden;
1804     },
1805      onMouseOut : function(e){
1806         var t  = this.findTargetItem(e);
1807         
1808         //if(t ){
1809         //    if(t == this.activeItem && t.shouldDeactivate(e)){
1810         //        this.activeItem.deactivate();
1811         //        delete this.activeItem;
1812         //    }
1813         //}
1814         this.fireEvent("mouseout", this, e, t);
1815     },
1816     
1817     
1818     /**
1819      * Displays this menu relative to another element
1820      * @param {String/HTMLElement/Roo.Element} element The element to align to
1821      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1822      * the element (defaults to this.defaultAlign)
1823      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1824      */
1825     show : function(el, pos, parentMenu){
1826         this.parentMenu = parentMenu;
1827         if(!this.el){
1828             this.render();
1829         }
1830         this.fireEvent("beforeshow", this);
1831         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1832     },
1833      /**
1834      * Displays this menu at a specific xy position
1835      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1836      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1837      */
1838     showAt : function(xy, parentMenu, /* private: */_e){
1839         this.parentMenu = parentMenu;
1840         if(!this.el){
1841             this.render();
1842         }
1843         if(_e !== false){
1844             this.fireEvent("beforeshow", this);
1845             
1846             //xy = this.el.adjustForConstraints(xy);
1847         }
1848         //this.el.setXY(xy);
1849         //this.el.show();
1850         this.hideMenuItems();
1851         this.hidden = false;
1852         this.triggerEl.addClass('open');
1853         this.focus();
1854         this.fireEvent("show", this);
1855     },
1856     
1857     focus : function(){
1858         return;
1859         if(!this.hidden){
1860             this.doFocus.defer(50, this);
1861         }
1862     },
1863
1864     doFocus : function(){
1865         if(!this.hidden){
1866             this.focusEl.focus();
1867         }
1868     },
1869
1870     /**
1871      * Hides this menu and optionally all parent menus
1872      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1873      */
1874     hide : function(deep){
1875         
1876         this.hideMenuItems();
1877         if(this.el && this.isVisible()){
1878             this.fireEvent("beforehide", this);
1879             if(this.activeItem){
1880                 this.activeItem.deactivate();
1881                 this.activeItem = null;
1882             }
1883             this.triggerEl.removeClass('open');;
1884             this.hidden = true;
1885             this.fireEvent("hide", this);
1886         }
1887         if(deep === true && this.parentMenu){
1888             this.parentMenu.hide(true);
1889         }
1890     },
1891     
1892     onTriggerPress  : function(e)
1893     {
1894         
1895         Roo.log('trigger press');
1896         //Roo.log(e.getTarget());
1897        // Roo.log(this.triggerEl.dom);
1898         if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1899             return;
1900         }
1901         if (this.isVisible()) {
1902             Roo.log('hide');
1903             this.hide();
1904         } else {
1905             this.show(this.triggerEl, false, false);
1906         }
1907         
1908         
1909     },
1910     
1911          
1912        
1913     
1914     hideMenuItems : function()
1915     {
1916         //$(backdrop).remove()
1917         Roo.select('.open',true).each(function(aa) {
1918             
1919             aa.removeClass('open');
1920           //var parent = getParent($(this))
1921           //var relatedTarget = { relatedTarget: this }
1922           
1923            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1924           //if (e.isDefaultPrevented()) return
1925            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1926         })
1927     },
1928     addxtypeChild : function (tree, cntr) {
1929         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1930           
1931         this.menuitems.add(comp);
1932         return comp;
1933
1934     },
1935     getEl : function()
1936     {
1937         Roo.log(this.el);
1938         return this.el;
1939     }
1940 });
1941
1942  
1943  /*
1944  * - LGPL
1945  *
1946  * menu item
1947  * 
1948  */
1949
1950
1951 /**
1952  * @class Roo.bootstrap.MenuItem
1953  * @extends Roo.bootstrap.Component
1954  * Bootstrap MenuItem class
1955  * @cfg {String} html the menu label
1956  * @cfg {String} href the link
1957  * @cfg {Boolean} preventDefault (true | false) default true
1958  * @cfg {Boolean} isContainer (true | false) default false
1959  * 
1960  * 
1961  * @constructor
1962  * Create a new MenuItem
1963  * @param {Object} config The config object
1964  */
1965
1966
1967 Roo.bootstrap.MenuItem = function(config){
1968     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1969     this.addEvents({
1970         // raw events
1971         /**
1972          * @event click
1973          * The raw click event for the entire grid.
1974          * @param {Roo.EventObject} e
1975          */
1976         "click" : true
1977     });
1978 };
1979
1980 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1981     
1982     href : false,
1983     html : false,
1984     preventDefault: true,
1985     isContainer : false,
1986     
1987     getAutoCreate : function(){
1988         
1989         if(this.isContainer){
1990             return {
1991                 tag: 'li',
1992                 cls: 'dropdown-menu-item'
1993             };
1994         }
1995         
1996         var cfg= {
1997             tag: 'li',
1998             cls: 'dropdown-menu-item',
1999             cn: [
2000                     {
2001                         tag : 'a',
2002                         href : '#',
2003                         html : 'Link'
2004                     }
2005                 ]
2006         };
2007         if (this.parent().type == 'treeview') {
2008             cfg.cls = 'treeview-menu';
2009         }
2010         
2011         cfg.cn[0].href = this.href || cfg.cn[0].href ;
2012         cfg.cn[0].html = this.html || cfg.cn[0].html ;
2013         return cfg;
2014     },
2015     
2016     initEvents: function() {
2017         
2018         //this.el.select('a').on('click', this.onClick, this);
2019         
2020     },
2021     onClick : function(e)
2022     {
2023         Roo.log('item on click ');
2024         //if(this.preventDefault){
2025         //    e.preventDefault();
2026         //}
2027         //this.parent().hideMenuItems();
2028         
2029         this.fireEvent('click', this, e);
2030     },
2031     getEl : function()
2032     {
2033         return this.el;
2034     }
2035 });
2036
2037  
2038
2039  /*
2040  * - LGPL
2041  *
2042  * menu separator
2043  * 
2044  */
2045
2046
2047 /**
2048  * @class Roo.bootstrap.MenuSeparator
2049  * @extends Roo.bootstrap.Component
2050  * Bootstrap MenuSeparator class
2051  * 
2052  * @constructor
2053  * Create a new MenuItem
2054  * @param {Object} config The config object
2055  */
2056
2057
2058 Roo.bootstrap.MenuSeparator = function(config){
2059     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2060 };
2061
2062 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2063     
2064     getAutoCreate : function(){
2065         var cfg = {
2066             cls: 'divider',
2067             tag : 'li'
2068         };
2069         
2070         return cfg;
2071     }
2072    
2073 });
2074
2075  
2076
2077  
2078 /*
2079 * Licence: LGPL
2080 */
2081
2082 /**
2083  * @class Roo.bootstrap.Modal
2084  * @extends Roo.bootstrap.Component
2085  * Bootstrap Modal class
2086  * @cfg {String} title Title of dialog
2087  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2088  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn 
2089  * @cfg {Boolean} specificTitle default false
2090  * @cfg {Array} buttons Array of buttons or standard button set..
2091  * @cfg {String} buttonPosition (left|right|center) default right
2092  * @cfg {Boolean} animate default true
2093  * @cfg {Boolean} allow_close default true
2094  * 
2095  * @constructor
2096  * Create a new Modal Dialog
2097  * @param {Object} config The config object
2098  */
2099
2100 Roo.bootstrap.Modal = function(config){
2101     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2102     this.addEvents({
2103         // raw events
2104         /**
2105          * @event btnclick
2106          * The raw btnclick event for the button
2107          * @param {Roo.EventObject} e
2108          */
2109         "btnclick" : true
2110     });
2111     this.buttons = this.buttons || [];
2112      
2113     if (this.tmpl) {
2114         this.tmpl = Roo.factory(this.tmpl);
2115     }
2116     
2117 };
2118
2119 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2120     
2121     title : 'test dialog',
2122    
2123     buttons : false,
2124     
2125     // set on load...
2126      
2127     html: false,
2128     
2129     tmp: false,
2130     
2131     specificTitle: false,
2132     
2133     buttonPosition: 'right',
2134     
2135     allow_close : true,
2136     
2137     animate : true,
2138     
2139     
2140      // private
2141     bodyEl:  false,
2142     footerEl:  false,
2143     titleEl:  false,
2144     closeEl:  false,
2145     
2146     
2147     onRender : function(ct, position)
2148     {
2149         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2150      
2151         if(!this.el){
2152             var cfg = Roo.apply({},  this.getAutoCreate());
2153             cfg.id = Roo.id();
2154             //if(!cfg.name){
2155             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2156             //}
2157             //if (!cfg.name.length) {
2158             //    delete cfg.name;
2159            // }
2160             if (this.cls) {
2161                 cfg.cls += ' ' + this.cls;
2162             }
2163             if (this.style) {
2164                 cfg.style = this.style;
2165             }
2166             this.el = Roo.get(document.body).createChild(cfg, position);
2167         }
2168         //var type = this.el.dom.type;
2169         
2170         
2171         
2172         
2173         if(this.tabIndex !== undefined){
2174             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2175         }
2176         
2177         
2178         this.bodyEl = this.el.select('.modal-body',true).first();
2179         this.closeEl = this.el.select('.modal-header .close', true).first();
2180         this.footerEl = this.el.select('.modal-footer',true).first();
2181         this.titleEl = this.el.select('.modal-title',true).first();
2182         
2183         
2184          
2185         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2186         this.maskEl.enableDisplayMode("block");
2187         this.maskEl.hide();
2188         //this.el.addClass("x-dlg-modal");
2189     
2190         if (this.buttons.length) {
2191             Roo.each(this.buttons, function(bb) {
2192                 b = Roo.apply({}, bb);
2193                 b.xns = b.xns || Roo.bootstrap;
2194                 b.xtype = b.xtype || 'Button';
2195                 if (typeof(b.listeners) == 'undefined') {
2196                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2197                 }
2198                 
2199                 var btn = Roo.factory(b);
2200                 
2201                 btn.onRender(this.el.select('.modal-footer div').first());
2202                 
2203             },this);
2204         }
2205         // render the children.
2206         var nitems = [];
2207         
2208         if(typeof(this.items) != 'undefined'){
2209             var items = this.items;
2210             delete this.items;
2211
2212             for(var i =0;i < items.length;i++) {
2213                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2214             }
2215         }
2216         
2217         this.items = nitems;
2218         
2219         // where are these used - they used to be body/close/footer
2220         
2221        
2222         this.initEvents();
2223         //this.el.addClass([this.fieldClass, this.cls]);
2224         
2225     },
2226     getAutoCreate : function(){
2227         
2228         
2229         var bdy = {
2230                 cls : 'modal-body',
2231                 html : this.html || ''
2232         };
2233         
2234         var title = {
2235             tag: 'h4',
2236             cls : 'modal-title',
2237             html : this.title
2238         };
2239         
2240         if(this.specificTitle){
2241             title = this.title;
2242             
2243         };
2244         
2245         var header = [];
2246         if (this.allow_close) {
2247             header.push({
2248                 tag: 'button',
2249                 cls : 'close',
2250                 html : '&times'
2251             });
2252         }
2253         header.push(title);
2254         
2255         var modal = {
2256             cls: "modal",
2257             style : 'display: none',
2258             cn : [
2259                 {
2260                     cls: "modal-dialog",
2261                     cn : [
2262                         {
2263                             cls : "modal-content",
2264                             cn : [
2265                                 {
2266                                     cls : 'modal-header',
2267                                     cn : header
2268                                 },
2269                                 bdy,
2270                                 {
2271                                     cls : 'modal-footer',
2272                                     cn : [
2273                                         {
2274                                             tag: 'div',
2275                                             cls: 'btn-' + this.buttonPosition
2276                                         }
2277                                     ]
2278                                     
2279                                 }
2280                                 
2281                                 
2282                             ]
2283                             
2284                         }
2285                     ]
2286                         
2287                 }
2288             ]
2289         };
2290         
2291         if(this.animate){
2292             modal.cls += ' fade';
2293         }
2294         
2295         return modal;
2296           
2297     },
2298     getChildContainer : function() {
2299          
2300          return this.bodyEl;
2301         
2302     },
2303     getButtonContainer : function() {
2304          return this.el.select('.modal-footer div',true).first();
2305         
2306     },
2307     initEvents : function()
2308     {
2309         if (this.allow_close) {
2310             this.closeEl.on('click', this.hide, this);
2311         }
2312
2313     },
2314     show : function() {
2315         
2316         if (!this.rendered) {
2317             this.render();
2318         }
2319         
2320         this.el.setStyle('display', 'block');
2321         
2322         if(this.animate){
2323             var _this = this;
2324             (function(){ _this.el.addClass('in'); }).defer(50);
2325         }else{
2326             this.el.addClass('in');
2327         }
2328         
2329         // not sure how we can show data in here.. 
2330         //if (this.tmpl) {
2331         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2332         //}
2333         
2334         Roo.get(document.body).addClass("x-body-masked");
2335         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2336         this.maskEl.show();
2337         this.el.setStyle('zIndex', '10001');
2338        
2339         this.fireEvent('show', this);
2340         
2341         
2342     },
2343     hide : function()
2344     {
2345         this.maskEl.hide();
2346         Roo.get(document.body).removeClass("x-body-masked");
2347         this.el.removeClass('in');
2348         
2349         if(this.animate){
2350             var _this = this;
2351             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2352         }else{
2353             this.el.setStyle('display', 'none');
2354         }
2355         
2356         this.fireEvent('hide', this);
2357     },
2358     
2359     addButton : function(str, cb)
2360     {
2361          
2362         
2363         var b = Roo.apply({}, { html : str } );
2364         b.xns = b.xns || Roo.bootstrap;
2365         b.xtype = b.xtype || 'Button';
2366         if (typeof(b.listeners) == 'undefined') {
2367             b.listeners = { click : cb.createDelegate(this)  };
2368         }
2369         
2370         var btn = Roo.factory(b);
2371            
2372         btn.onRender(this.el.select('.modal-footer div').first());
2373         
2374         return btn;   
2375        
2376     },
2377     
2378     setDefaultButton : function(btn)
2379     {
2380         //this.el.select('.modal-footer').()
2381     },
2382     resizeTo: function(w,h)
2383     {
2384         // skip..
2385     },
2386     setContentSize  : function(w, h)
2387     {
2388         
2389     },
2390     onButtonClick: function(btn,e)
2391     {
2392         //Roo.log([a,b,c]);
2393         this.fireEvent('btnclick', btn.name, e);
2394     },
2395      /**
2396      * Set the title of the Dialog
2397      * @param {String} str new Title
2398      */
2399     setTitle: function(str) {
2400         this.titleEl.dom.innerHTML = str;    
2401     },
2402     /**
2403      * Set the body of the Dialog
2404      * @param {String} str new Title
2405      */
2406     setBody: function(str) {
2407         this.bodyEl.dom.innerHTML = str;    
2408     },
2409     /**
2410      * Set the body of the Dialog using the template
2411      * @param {Obj} data - apply this data to the template and replace the body contents.
2412      */
2413     applyBody: function(obj)
2414     {
2415         if (!this.tmpl) {
2416             Roo.log("Error - using apply Body without a template");
2417             //code
2418         }
2419         this.tmpl.overwrite(this.bodyEl, obj);
2420     }
2421     
2422 });
2423
2424
2425 Roo.apply(Roo.bootstrap.Modal,  {
2426     /**
2427          * Button config that displays a single OK button
2428          * @type Object
2429          */
2430         OK :  [{
2431             name : 'ok',
2432             weight : 'primary',
2433             html : 'OK'
2434         }], 
2435         /**
2436          * Button config that displays Yes and No buttons
2437          * @type Object
2438          */
2439         YESNO : [
2440             {
2441                 name  : 'no',
2442                 html : 'No'
2443             },
2444             {
2445                 name  :'yes',
2446                 weight : 'primary',
2447                 html : 'Yes'
2448             }
2449         ],
2450         
2451         /**
2452          * Button config that displays OK and Cancel buttons
2453          * @type Object
2454          */
2455         OKCANCEL : [
2456             {
2457                name : 'cancel',
2458                 html : 'Cancel'
2459             },
2460             {
2461                 name : 'ok',
2462                 weight : 'primary',
2463                 html : 'OK'
2464             }
2465         ],
2466         /**
2467          * Button config that displays Yes, No and Cancel buttons
2468          * @type Object
2469          */
2470         YESNOCANCEL : [
2471             {
2472                 name : 'yes',
2473                 weight : 'primary',
2474                 html : 'Yes'
2475             },
2476             {
2477                 name : 'no',
2478                 html : 'No'
2479             },
2480             {
2481                 name : 'cancel',
2482                 html : 'Cancel'
2483             }
2484         ]
2485 });
2486  
2487  /*
2488  * - LGPL
2489  *
2490  * messagebox - can be used as a replace
2491  * 
2492  */
2493 /**
2494  * @class Roo.MessageBox
2495  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2496  * Example usage:
2497  *<pre><code>
2498 // Basic alert:
2499 Roo.Msg.alert('Status', 'Changes saved successfully.');
2500
2501 // Prompt for user data:
2502 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2503     if (btn == 'ok'){
2504         // process text value...
2505     }
2506 });
2507
2508 // Show a dialog using config options:
2509 Roo.Msg.show({
2510    title:'Save Changes?',
2511    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2512    buttons: Roo.Msg.YESNOCANCEL,
2513    fn: processResult,
2514    animEl: 'elId'
2515 });
2516 </code></pre>
2517  * @singleton
2518  */
2519 Roo.bootstrap.MessageBox = function(){
2520     var dlg, opt, mask, waitTimer;
2521     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2522     var buttons, activeTextEl, bwidth;
2523
2524     
2525     // private
2526     var handleButton = function(button){
2527         dlg.hide();
2528         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2529     };
2530
2531     // private
2532     var handleHide = function(){
2533         if(opt && opt.cls){
2534             dlg.el.removeClass(opt.cls);
2535         }
2536         //if(waitTimer){
2537         //    Roo.TaskMgr.stop(waitTimer);
2538         //    waitTimer = null;
2539         //}
2540     };
2541
2542     // private
2543     var updateButtons = function(b){
2544         var width = 0;
2545         if(!b){
2546             buttons["ok"].hide();
2547             buttons["cancel"].hide();
2548             buttons["yes"].hide();
2549             buttons["no"].hide();
2550             //dlg.footer.dom.style.display = 'none';
2551             return width;
2552         }
2553         dlg.footerEl.dom.style.display = '';
2554         for(var k in buttons){
2555             if(typeof buttons[k] != "function"){
2556                 if(b[k]){
2557                     buttons[k].show();
2558                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2559                     width += buttons[k].el.getWidth()+15;
2560                 }else{
2561                     buttons[k].hide();
2562                 }
2563             }
2564         }
2565         return width;
2566     };
2567
2568     // private
2569     var handleEsc = function(d, k, e){
2570         if(opt && opt.closable !== false){
2571             dlg.hide();
2572         }
2573         if(e){
2574             e.stopEvent();
2575         }
2576     };
2577
2578     return {
2579         /**
2580          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2581          * @return {Roo.BasicDialog} The BasicDialog element
2582          */
2583         getDialog : function(){
2584            if(!dlg){
2585                 dlg = new Roo.bootstrap.Modal( {
2586                     //draggable: true,
2587                     //resizable:false,
2588                     //constraintoviewport:false,
2589                     //fixedcenter:true,
2590                     //collapsible : false,
2591                     //shim:true,
2592                     //modal: true,
2593                   //  width:400,
2594                   //  height:100,
2595                     //buttonAlign:"center",
2596                     closeClick : function(){
2597                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2598                             handleButton("no");
2599                         }else{
2600                             handleButton("cancel");
2601                         }
2602                     }
2603                 });
2604                 dlg.render();
2605                 dlg.on("hide", handleHide);
2606                 mask = dlg.mask;
2607                 //dlg.addKeyListener(27, handleEsc);
2608                 buttons = {};
2609                 this.buttons = buttons;
2610                 var bt = this.buttonText;
2611                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2612                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2613                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2614                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2615                 Roo.log(buttons)
2616                 bodyEl = dlg.bodyEl.createChild({
2617
2618                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2619                         '<textarea class="roo-mb-textarea"></textarea>' +
2620                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2621                 });
2622                 msgEl = bodyEl.dom.firstChild;
2623                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2624                 textboxEl.enableDisplayMode();
2625                 textboxEl.addKeyListener([10,13], function(){
2626                     if(dlg.isVisible() && opt && opt.buttons){
2627                         if(opt.buttons.ok){
2628                             handleButton("ok");
2629                         }else if(opt.buttons.yes){
2630                             handleButton("yes");
2631                         }
2632                     }
2633                 });
2634                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2635                 textareaEl.enableDisplayMode();
2636                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2637                 progressEl.enableDisplayMode();
2638                 var pf = progressEl.dom.firstChild;
2639                 if (pf) {
2640                     pp = Roo.get(pf.firstChild);
2641                     pp.setHeight(pf.offsetHeight);
2642                 }
2643                 
2644             }
2645             return dlg;
2646         },
2647
2648         /**
2649          * Updates the message box body text
2650          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2651          * the XHTML-compliant non-breaking space character '&amp;#160;')
2652          * @return {Roo.MessageBox} This message box
2653          */
2654         updateText : function(text){
2655             if(!dlg.isVisible() && !opt.width){
2656                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2657             }
2658             msgEl.innerHTML = text || '&#160;';
2659       
2660             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2661             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2662             var w = Math.max(
2663                     Math.min(opt.width || cw , this.maxWidth), 
2664                     Math.max(opt.minWidth || this.minWidth, bwidth)
2665             );
2666             if(opt.prompt){
2667                 activeTextEl.setWidth(w);
2668             }
2669             if(dlg.isVisible()){
2670                 dlg.fixedcenter = false;
2671             }
2672             // to big, make it scroll. = But as usual stupid IE does not support
2673             // !important..
2674             
2675             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2676                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2677                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2678             } else {
2679                 bodyEl.dom.style.height = '';
2680                 bodyEl.dom.style.overflowY = '';
2681             }
2682             if (cw > w) {
2683                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2684             } else {
2685                 bodyEl.dom.style.overflowX = '';
2686             }
2687             
2688             dlg.setContentSize(w, bodyEl.getHeight());
2689             if(dlg.isVisible()){
2690                 dlg.fixedcenter = true;
2691             }
2692             return this;
2693         },
2694
2695         /**
2696          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2697          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2698          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2699          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2700          * @return {Roo.MessageBox} This message box
2701          */
2702         updateProgress : function(value, text){
2703             if(text){
2704                 this.updateText(text);
2705             }
2706             if (pp) { // weird bug on my firefox - for some reason this is not defined
2707                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2708             }
2709             return this;
2710         },        
2711
2712         /**
2713          * Returns true if the message box is currently displayed
2714          * @return {Boolean} True if the message box is visible, else false
2715          */
2716         isVisible : function(){
2717             return dlg && dlg.isVisible();  
2718         },
2719
2720         /**
2721          * Hides the message box if it is displayed
2722          */
2723         hide : function(){
2724             if(this.isVisible()){
2725                 dlg.hide();
2726             }  
2727         },
2728
2729         /**
2730          * Displays a new message box, or reinitializes an existing message box, based on the config options
2731          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2732          * The following config object properties are supported:
2733          * <pre>
2734 Property    Type             Description
2735 ----------  ---------------  ------------------------------------------------------------------------------------
2736 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2737                                    closes (defaults to undefined)
2738 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2739                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2740 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2741                                    progress and wait dialogs will ignore this property and always hide the
2742                                    close button as they can only be closed programmatically.
2743 cls               String           A custom CSS class to apply to the message box element
2744 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2745                                    displayed (defaults to 75)
2746 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2747                                    function will be btn (the name of the button that was clicked, if applicable,
2748                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2749                                    Progress and wait dialogs will ignore this option since they do not respond to
2750                                    user actions and can only be closed programmatically, so any required function
2751                                    should be called by the same code after it closes the dialog.
2752 icon              String           A CSS class that provides a background image to be used as an icon for
2753                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2754 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2755 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2756 modal             Boolean          False to allow user interaction with the page while the message box is
2757                                    displayed (defaults to true)
2758 msg               String           A string that will replace the existing message box body text (defaults
2759                                    to the XHTML-compliant non-breaking space character '&#160;')
2760 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2761 progress          Boolean          True to display a progress bar (defaults to false)
2762 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2763 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2764 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2765 title             String           The title text
2766 value             String           The string value to set into the active textbox element if displayed
2767 wait              Boolean          True to display a progress bar (defaults to false)
2768 width             Number           The width of the dialog in pixels
2769 </pre>
2770          *
2771          * Example usage:
2772          * <pre><code>
2773 Roo.Msg.show({
2774    title: 'Address',
2775    msg: 'Please enter your address:',
2776    width: 300,
2777    buttons: Roo.MessageBox.OKCANCEL,
2778    multiline: true,
2779    fn: saveAddress,
2780    animEl: 'addAddressBtn'
2781 });
2782 </code></pre>
2783          * @param {Object} config Configuration options
2784          * @return {Roo.MessageBox} This message box
2785          */
2786         show : function(options)
2787         {
2788             
2789             // this causes nightmares if you show one dialog after another
2790             // especially on callbacks..
2791              
2792             if(this.isVisible()){
2793                 
2794                 this.hide();
2795                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2796                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2797                 Roo.log("New Dialog Message:" +  options.msg )
2798                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2799                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2800                 
2801             }
2802             var d = this.getDialog();
2803             opt = options;
2804             d.setTitle(opt.title || "&#160;");
2805             d.closeEl.setDisplayed(opt.closable !== false);
2806             activeTextEl = textboxEl;
2807             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2808             if(opt.prompt){
2809                 if(opt.multiline){
2810                     textboxEl.hide();
2811                     textareaEl.show();
2812                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2813                         opt.multiline : this.defaultTextHeight);
2814                     activeTextEl = textareaEl;
2815                 }else{
2816                     textboxEl.show();
2817                     textareaEl.hide();
2818                 }
2819             }else{
2820                 textboxEl.hide();
2821                 textareaEl.hide();
2822             }
2823             progressEl.setDisplayed(opt.progress === true);
2824             this.updateProgress(0);
2825             activeTextEl.dom.value = opt.value || "";
2826             if(opt.prompt){
2827                 dlg.setDefaultButton(activeTextEl);
2828             }else{
2829                 var bs = opt.buttons;
2830                 var db = null;
2831                 if(bs && bs.ok){
2832                     db = buttons["ok"];
2833                 }else if(bs && bs.yes){
2834                     db = buttons["yes"];
2835                 }
2836                 dlg.setDefaultButton(db);
2837             }
2838             bwidth = updateButtons(opt.buttons);
2839             this.updateText(opt.msg);
2840             if(opt.cls){
2841                 d.el.addClass(opt.cls);
2842             }
2843             d.proxyDrag = opt.proxyDrag === true;
2844             d.modal = opt.modal !== false;
2845             d.mask = opt.modal !== false ? mask : false;
2846             if(!d.isVisible()){
2847                 // force it to the end of the z-index stack so it gets a cursor in FF
2848                 document.body.appendChild(dlg.el.dom);
2849                 d.animateTarget = null;
2850                 d.show(options.animEl);
2851             }
2852             return this;
2853         },
2854
2855         /**
2856          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2857          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2858          * and closing the message box when the process is complete.
2859          * @param {String} title The title bar text
2860          * @param {String} msg The message box body text
2861          * @return {Roo.MessageBox} This message box
2862          */
2863         progress : function(title, msg){
2864             this.show({
2865                 title : title,
2866                 msg : msg,
2867                 buttons: false,
2868                 progress:true,
2869                 closable:false,
2870                 minWidth: this.minProgressWidth,
2871                 modal : true
2872             });
2873             return this;
2874         },
2875
2876         /**
2877          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2878          * If a callback function is passed it will be called after the user clicks the button, and the
2879          * id of the button that was clicked will be passed as the only parameter to the callback
2880          * (could also be the top-right close button).
2881          * @param {String} title The title bar text
2882          * @param {String} msg The message box body text
2883          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2884          * @param {Object} scope (optional) The scope of the callback function
2885          * @return {Roo.MessageBox} This message box
2886          */
2887         alert : function(title, msg, fn, scope){
2888             this.show({
2889                 title : title,
2890                 msg : msg,
2891                 buttons: this.OK,
2892                 fn: fn,
2893                 scope : scope,
2894                 modal : true
2895             });
2896             return this;
2897         },
2898
2899         /**
2900          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2901          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2902          * You are responsible for closing the message box when the process is complete.
2903          * @param {String} msg The message box body text
2904          * @param {String} title (optional) The title bar text
2905          * @return {Roo.MessageBox} This message box
2906          */
2907         wait : function(msg, title){
2908             this.show({
2909                 title : title,
2910                 msg : msg,
2911                 buttons: false,
2912                 closable:false,
2913                 progress:true,
2914                 modal:true,
2915                 width:300,
2916                 wait:true
2917             });
2918             waitTimer = Roo.TaskMgr.start({
2919                 run: function(i){
2920                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2921                 },
2922                 interval: 1000
2923             });
2924             return this;
2925         },
2926
2927         /**
2928          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2929          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2930          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2931          * @param {String} title The title bar text
2932          * @param {String} msg The message box body text
2933          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2934          * @param {Object} scope (optional) The scope of the callback function
2935          * @return {Roo.MessageBox} This message box
2936          */
2937         confirm : function(title, msg, fn, scope){
2938             this.show({
2939                 title : title,
2940                 msg : msg,
2941                 buttons: this.YESNO,
2942                 fn: fn,
2943                 scope : scope,
2944                 modal : true
2945             });
2946             return this;
2947         },
2948
2949         /**
2950          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2951          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2952          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2953          * (could also be the top-right close button) and the text that was entered will be passed as the two
2954          * parameters to the callback.
2955          * @param {String} title The title bar text
2956          * @param {String} msg The message box body text
2957          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2958          * @param {Object} scope (optional) The scope of the callback function
2959          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2960          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2961          * @return {Roo.MessageBox} This message box
2962          */
2963         prompt : function(title, msg, fn, scope, multiline){
2964             this.show({
2965                 title : title,
2966                 msg : msg,
2967                 buttons: this.OKCANCEL,
2968                 fn: fn,
2969                 minWidth:250,
2970                 scope : scope,
2971                 prompt:true,
2972                 multiline: multiline,
2973                 modal : true
2974             });
2975             return this;
2976         },
2977
2978         /**
2979          * Button config that displays a single OK button
2980          * @type Object
2981          */
2982         OK : {ok:true},
2983         /**
2984          * Button config that displays Yes and No buttons
2985          * @type Object
2986          */
2987         YESNO : {yes:true, no:true},
2988         /**
2989          * Button config that displays OK and Cancel buttons
2990          * @type Object
2991          */
2992         OKCANCEL : {ok:true, cancel:true},
2993         /**
2994          * Button config that displays Yes, No and Cancel buttons
2995          * @type Object
2996          */
2997         YESNOCANCEL : {yes:true, no:true, cancel:true},
2998
2999         /**
3000          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3001          * @type Number
3002          */
3003         defaultTextHeight : 75,
3004         /**
3005          * The maximum width in pixels of the message box (defaults to 600)
3006          * @type Number
3007          */
3008         maxWidth : 600,
3009         /**
3010          * The minimum width in pixels of the message box (defaults to 100)
3011          * @type Number
3012          */
3013         minWidth : 100,
3014         /**
3015          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3016          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3017          * @type Number
3018          */
3019         minProgressWidth : 250,
3020         /**
3021          * An object containing the default button text strings that can be overriden for localized language support.
3022          * Supported properties are: ok, cancel, yes and no.
3023          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3024          * @type Object
3025          */
3026         buttonText : {
3027             ok : "OK",
3028             cancel : "Cancel",
3029             yes : "Yes",
3030             no : "No"
3031         }
3032     };
3033 }();
3034
3035 /**
3036  * Shorthand for {@link Roo.MessageBox}
3037  */
3038 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3039 Roo.Msg = Roo.Msg || Roo.MessageBox;
3040 /*
3041  * - LGPL
3042  *
3043  * navbar
3044  * 
3045  */
3046
3047 /**
3048  * @class Roo.bootstrap.Navbar
3049  * @extends Roo.bootstrap.Component
3050  * Bootstrap Navbar class
3051
3052  * @constructor
3053  * Create a new Navbar
3054  * @param {Object} config The config object
3055  */
3056
3057
3058 Roo.bootstrap.Navbar = function(config){
3059     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3060     
3061 };
3062
3063 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3064     
3065     
3066    
3067     // private
3068     navItems : false,
3069     loadMask : false,
3070     
3071     
3072     getAutoCreate : function(){
3073         
3074         
3075         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3076         
3077     },
3078     
3079     initEvents :function ()
3080     {
3081         //Roo.log(this.el.select('.navbar-toggle',true));
3082         this.el.select('.navbar-toggle',true).on('click', function() {
3083            // Roo.log('click');
3084             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3085         }, this);
3086         
3087         var mark = {
3088             tag: "div",
3089             cls:"x-dlg-mask"
3090         }
3091         
3092         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3093         
3094         var size = this.el.getSize();
3095         this.maskEl.setSize(size.width, size.height);
3096         this.maskEl.enableDisplayMode("block");
3097         this.maskEl.hide();
3098         
3099         if(this.loadMask){
3100             this.maskEl.show();
3101         }
3102     },
3103     
3104     
3105     getChildContainer : function()
3106     {
3107         if (this.el.select('.collapse').getCount()) {
3108             return this.el.select('.collapse',true).first();
3109         }
3110         
3111         return this.el;
3112     },
3113     
3114     mask : function()
3115     {
3116         this.maskEl.show();
3117     },
3118     
3119     unmask : function()
3120     {
3121         this.maskEl.hide();
3122     } 
3123     
3124     
3125     
3126     
3127 });
3128
3129
3130
3131  
3132
3133  /*
3134  * - LGPL
3135  *
3136  * navbar
3137  * 
3138  */
3139
3140 /**
3141  * @class Roo.bootstrap.NavSimplebar
3142  * @extends Roo.bootstrap.Navbar
3143  * Bootstrap Sidebar class
3144  *
3145  * @cfg {Boolean} inverse is inverted color
3146  * 
3147  * @cfg {String} type (nav | pills | tabs)
3148  * @cfg {Boolean} arrangement stacked | justified
3149  * @cfg {String} align (left | right) alignment
3150  * 
3151  * @cfg {Boolean} main (true|false) main nav bar? default false
3152  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3153  * 
3154  * @cfg {String} tag (header|footer|nav|div) default is nav 
3155
3156  * 
3157  * 
3158  * 
3159  * @constructor
3160  * Create a new Sidebar
3161  * @param {Object} config The config object
3162  */
3163
3164
3165 Roo.bootstrap.NavSimplebar = function(config){
3166     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3167 };
3168
3169 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3170     
3171     inverse: false,
3172     
3173     type: false,
3174     arrangement: '',
3175     align : false,
3176     
3177     
3178     
3179     main : false,
3180     
3181     
3182     tag : false,
3183     
3184     
3185     getAutoCreate : function(){
3186         
3187         
3188         var cfg = {
3189             tag : this.tag || 'div',
3190             cls : 'navbar'
3191         };
3192           
3193         
3194         cfg.cn = [
3195             {
3196                 cls: 'nav',
3197                 tag : 'ul'
3198             }
3199         ];
3200         
3201          
3202         this.type = this.type || 'nav';
3203         if (['tabs','pills'].indexOf(this.type)!==-1) {
3204             cfg.cn[0].cls += ' nav-' + this.type
3205         
3206         
3207         } else {
3208             if (this.type!=='nav') {
3209                 Roo.log('nav type must be nav/tabs/pills')
3210             }
3211             cfg.cn[0].cls += ' navbar-nav'
3212         }
3213         
3214         
3215         
3216         
3217         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3218             cfg.cn[0].cls += ' nav-' + this.arrangement;
3219         }
3220         
3221         
3222         if (this.align === 'right') {
3223             cfg.cn[0].cls += ' navbar-right';
3224         }
3225         
3226         if (this.inverse) {
3227             cfg.cls += ' navbar-inverse';
3228             
3229         }
3230         
3231         
3232         return cfg;
3233     
3234         
3235     }
3236     
3237     
3238     
3239 });
3240
3241
3242
3243  
3244
3245  
3246        /*
3247  * - LGPL
3248  *
3249  * navbar
3250  * 
3251  */
3252
3253 /**
3254  * @class Roo.bootstrap.NavHeaderbar
3255  * @extends Roo.bootstrap.NavSimplebar
3256  * Bootstrap Sidebar class
3257  *
3258  * @cfg {String} brand what is brand
3259  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3260  * @cfg {String} brand_href href of the brand
3261  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3262  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3263  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3264  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3265  * 
3266  * @constructor
3267  * Create a new Sidebar
3268  * @param {Object} config The config object
3269  */
3270
3271
3272 Roo.bootstrap.NavHeaderbar = function(config){
3273     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3274       
3275 };
3276
3277 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3278     
3279     position: '',
3280     brand: '',
3281     brand_href: false,
3282     srButton : true,
3283     autohide : false,
3284     desktopCenter : false,
3285    
3286     
3287     getAutoCreate : function(){
3288         
3289         var   cfg = {
3290             tag: this.nav || 'nav',
3291             cls: 'navbar',
3292             role: 'navigation',
3293             cn: []
3294         };
3295         
3296         var cn = cfg.cn;
3297         if (this.desktopCenter) {
3298             cn.push({cls : 'container', cn : []});
3299             cn = cn[0].cn;
3300         }
3301         
3302         if(this.srButton){
3303             cn.push({
3304                 tag: 'div',
3305                 cls: 'navbar-header',
3306                 cn: [
3307                     {
3308                         tag: 'button',
3309                         type: 'button',
3310                         cls: 'navbar-toggle',
3311                         'data-toggle': 'collapse',
3312                         cn: [
3313                             {
3314                                 tag: 'span',
3315                                 cls: 'sr-only',
3316                                 html: 'Toggle navigation'
3317                             },
3318                             {
3319                                 tag: 'span',
3320                                 cls: 'icon-bar'
3321                             },
3322                             {
3323                                 tag: 'span',
3324                                 cls: 'icon-bar'
3325                             },
3326                             {
3327                                 tag: 'span',
3328                                 cls: 'icon-bar'
3329                             }
3330                         ]
3331                     }
3332                 ]
3333             });
3334         }
3335         
3336         cn.push({
3337             tag: 'div',
3338             cls: 'collapse navbar-collapse',
3339             cn : []
3340         });
3341         
3342         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3343         
3344         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3345             cfg.cls += ' navbar-' + this.position;
3346             
3347             // tag can override this..
3348             
3349             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3350         }
3351         
3352         if (this.brand !== '') {
3353             cn[0].cn.push({
3354                 tag: 'a',
3355                 href: this.brand_href ? this.brand_href : '#',
3356                 cls: 'navbar-brand',
3357                 cn: [
3358                 this.brand
3359                 ]
3360             });
3361         }
3362         
3363         if(this.main){
3364             cfg.cls += ' main-nav';
3365         }
3366         
3367         
3368         return cfg;
3369
3370         
3371     },
3372     getHeaderChildContainer : function()
3373     {
3374         if (this.el.select('.navbar-header').getCount()) {
3375             return this.el.select('.navbar-header',true).first();
3376         }
3377         
3378         return this.getChildContainer();
3379     },
3380     
3381     
3382     initEvents : function()
3383     {
3384         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3385         
3386         if (this.autohide) {
3387             
3388             var prevScroll = 0;
3389             var ft = this.el;
3390             
3391             Roo.get(document).on('scroll',function(e) {
3392                 var ns = Roo.get(document).getScroll().top;
3393                 var os = prevScroll;
3394                 prevScroll = ns;
3395                 
3396                 if(ns > os){
3397                     ft.removeClass('slideDown');
3398                     ft.addClass('slideUp');
3399                     return;
3400                 }
3401                 ft.removeClass('slideUp');
3402                 ft.addClass('slideDown');
3403                  
3404               
3405           },this);
3406         }
3407     }    
3408           
3409       
3410     
3411     
3412 });
3413
3414
3415
3416  
3417
3418  /*
3419  * - LGPL
3420  *
3421  * navbar
3422  * 
3423  */
3424
3425 /**
3426  * @class Roo.bootstrap.NavSidebar
3427  * @extends Roo.bootstrap.Navbar
3428  * Bootstrap Sidebar class
3429  * 
3430  * @constructor
3431  * Create a new Sidebar
3432  * @param {Object} config The config object
3433  */
3434
3435
3436 Roo.bootstrap.NavSidebar = function(config){
3437     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3438 };
3439
3440 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3441     
3442     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3443     
3444     getAutoCreate : function(){
3445         
3446         
3447         return  {
3448             tag: 'div',
3449             cls: 'sidebar sidebar-nav'
3450         };
3451     
3452         
3453     }
3454     
3455     
3456     
3457 });
3458
3459
3460
3461  
3462
3463  /*
3464  * - LGPL
3465  *
3466  * nav group
3467  * 
3468  */
3469
3470 /**
3471  * @class Roo.bootstrap.NavGroup
3472  * @extends Roo.bootstrap.Component
3473  * Bootstrap NavGroup class
3474  * @cfg {String} align left | right
3475  * @cfg {Boolean} inverse false | true
3476  * @cfg {String} type (nav|pills|tab) default nav
3477  * @cfg {String} navId - reference Id for navbar.
3478
3479  * 
3480  * @constructor
3481  * Create a new nav group
3482  * @param {Object} config The config object
3483  */
3484
3485 Roo.bootstrap.NavGroup = function(config){
3486     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3487     this.navItems = [];
3488    
3489     Roo.bootstrap.NavGroup.register(this);
3490      this.addEvents({
3491         /**
3492              * @event changed
3493              * Fires when the active item changes
3494              * @param {Roo.bootstrap.NavGroup} this
3495              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3496              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3497          */
3498         'changed': true
3499      });
3500     
3501 };
3502
3503 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3504     
3505     align: '',
3506     inverse: false,
3507     form: false,
3508     type: 'nav',
3509     navId : '',
3510     // private
3511     
3512     navItems : false, 
3513     
3514     getAutoCreate : function()
3515     {
3516         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3517         
3518         cfg = {
3519             tag : 'ul',
3520             cls: 'nav' 
3521         }
3522         
3523         if (['tabs','pills'].indexOf(this.type)!==-1) {
3524             cfg.cls += ' nav-' + this.type
3525         } else {
3526             if (this.type!=='nav') {
3527                 Roo.log('nav type must be nav/tabs/pills')
3528             }
3529             cfg.cls += ' navbar-nav'
3530         }
3531         
3532         if (this.parent().sidebar) {
3533             cfg = {
3534                 tag: 'ul',
3535                 cls: 'dashboard-menu sidebar-menu'
3536             }
3537             
3538             return cfg;
3539         }
3540         
3541         if (this.form === true) {
3542             cfg = {
3543                 tag: 'form',
3544                 cls: 'navbar-form'
3545             }
3546             
3547             if (this.align === 'right') {
3548                 cfg.cls += ' navbar-right';
3549             } else {
3550                 cfg.cls += ' navbar-left';
3551             }
3552         }
3553         
3554         if (this.align === 'right') {
3555             cfg.cls += ' navbar-right';
3556         }
3557         
3558         if (this.inverse) {
3559             cfg.cls += ' navbar-inverse';
3560             
3561         }
3562         
3563         
3564         return cfg;
3565     },
3566     /**
3567     * sets the active Navigation item
3568     * @param {Roo.bootstrap.NavItem} the new current navitem
3569     */
3570     setActiveItem : function(item)
3571     {
3572         var prev = false;
3573         Roo.each(this.navItems, function(v){
3574             if (v == item) {
3575                 return ;
3576             }
3577             if (v.isActive()) {
3578                 v.setActive(false, true);
3579                 prev = v;
3580                 
3581             }
3582             
3583         });
3584
3585         item.setActive(true, true);
3586         this.fireEvent('changed', this, item, prev);
3587         
3588         
3589     },
3590     /**
3591     * gets the active Navigation item
3592     * @return {Roo.bootstrap.NavItem} the current navitem
3593     */
3594     getActive : function()
3595     {
3596         
3597         var prev = false;
3598         Roo.each(this.navItems, function(v){
3599             
3600             if (v.isActive()) {
3601                 prev = v;
3602                 
3603             }
3604             
3605         });
3606         return prev;
3607     },
3608     
3609     indexOfNav : function()
3610     {
3611         
3612         var prev = false;
3613         Roo.each(this.navItems, function(v,i){
3614             
3615             if (v.isActive()) {
3616                 prev = i;
3617                 
3618             }
3619             
3620         });
3621         return prev;
3622     },
3623     /**
3624     * adds a Navigation item
3625     * @param {Roo.bootstrap.NavItem} the navitem to add
3626     */
3627     addItem : function(cfg)
3628     {
3629         var cn = new Roo.bootstrap.NavItem(cfg);
3630         this.register(cn);
3631         cn.parentId = this.id;
3632         cn.onRender(this.el, null);
3633         return cn;
3634     },
3635     /**
3636     * register a Navigation item
3637     * @param {Roo.bootstrap.NavItem} the navitem to add
3638     */
3639     register : function(item)
3640     {
3641         this.navItems.push( item);
3642         item.navId = this.navId;
3643     
3644     },
3645     
3646     /**
3647     * clear all the Navigation item
3648     */
3649    
3650     clearAll : function()
3651     {
3652         this.navItems = [];
3653         this.el.dom.innerHTML = '';
3654     },
3655     
3656     getNavItem: function(tabId)
3657     {
3658         var ret = false;
3659         Roo.each(this.navItems, function(e) {
3660             if (e.tabId == tabId) {
3661                ret =  e;
3662                return false;
3663             }
3664             return true;
3665             
3666         });
3667         return ret;
3668     },
3669     
3670     setActiveNext : function()
3671     {
3672         var i = this.indexOfNav(this.getActive());
3673         if (i > this.navItems.length) {
3674             return;
3675         }
3676         this.setActiveItem(this.navItems[i+1]);
3677     },
3678     setActivePrev : function()
3679     {
3680         var i = this.indexOfNav(this.getActive());
3681         if (i  < 1) {
3682             return;
3683         }
3684         this.setActiveItem(this.navItems[i-1]);
3685     },
3686     clearWasActive : function(except) {
3687         Roo.each(this.navItems, function(e) {
3688             if (e.tabId != except.tabId && e.was_active) {
3689                e.was_active = false;
3690                return false;
3691             }
3692             return true;
3693             
3694         });
3695     },
3696     getWasActive : function ()
3697     {
3698         var r = false;
3699         Roo.each(this.navItems, function(e) {
3700             if (e.was_active) {
3701                r = e;
3702                return false;
3703             }
3704             return true;
3705             
3706         });
3707         return r;
3708     }
3709     
3710     
3711 });
3712
3713  
3714 Roo.apply(Roo.bootstrap.NavGroup, {
3715     
3716     groups: {},
3717      /**
3718     * register a Navigation Group
3719     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3720     */
3721     register : function(navgrp)
3722     {
3723         this.groups[navgrp.navId] = navgrp;
3724         
3725     },
3726     /**
3727     * fetch a Navigation Group based on the navigation ID
3728     * @param {string} the navgroup to add
3729     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3730     */
3731     get: function(navId) {
3732         if (typeof(this.groups[navId]) == 'undefined') {
3733             return false;
3734             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3735         }
3736         return this.groups[navId] ;
3737     }
3738     
3739     
3740     
3741 });
3742
3743  /*
3744  * - LGPL
3745  *
3746  * row
3747  * 
3748  */
3749
3750 /**
3751  * @class Roo.bootstrap.NavItem
3752  * @extends Roo.bootstrap.Component
3753  * Bootstrap Navbar.NavItem class
3754  * @cfg {String} href  link to
3755  * @cfg {String} html content of button
3756  * @cfg {String} badge text inside badge
3757  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3758  * @cfg {String} glyphicon name of glyphicon
3759  * @cfg {String} icon name of font awesome icon
3760  * @cfg {Boolean} active Is item active
3761  * @cfg {Boolean} disabled Is item disabled
3762  
3763  * @cfg {Boolean} preventDefault (true | false) default false
3764  * @cfg {String} tabId the tab that this item activates.
3765  * @cfg {String} tagtype (a|span) render as a href or span?
3766  * @cfg {Boolean} animateRef (true|false) link to element default false
3767   
3768  * @constructor
3769  * Create a new Navbar Item
3770  * @param {Object} config The config object
3771  */
3772 Roo.bootstrap.NavItem = function(config){
3773     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3774     this.addEvents({
3775         // raw events
3776         /**
3777          * @event click
3778          * The raw click event for the entire grid.
3779          * @param {Roo.EventObject} e
3780          */
3781         "click" : true,
3782          /**
3783             * @event changed
3784             * Fires when the active item active state changes
3785             * @param {Roo.bootstrap.NavItem} this
3786             * @param {boolean} state the new state
3787              
3788          */
3789         'changed': true,
3790         /**
3791             * @event scrollto
3792             * Fires when scroll to element
3793             * @param {Roo.bootstrap.NavItem} this
3794             * @param {Object} options
3795             * @param {Roo.EventObject} e
3796              
3797          */
3798         'scrollto': true
3799     });
3800    
3801 };
3802
3803 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3804     
3805     href: false,
3806     html: '',
3807     badge: '',
3808     icon: false,
3809     glyphicon: false,
3810     active: false,
3811     preventDefault : false,
3812     tabId : false,
3813     tagtype : 'a',
3814     disabled : false,
3815     animateRef : false,
3816     was_active : false,
3817     
3818     getAutoCreate : function(){
3819          
3820         var cfg = {
3821             tag: 'li',
3822             cls: 'nav-item'
3823             
3824         }
3825         if (this.active) {
3826             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3827         }
3828         if (this.disabled) {
3829             cfg.cls += ' disabled';
3830         }
3831         
3832         if (this.href || this.html || this.glyphicon || this.icon) {
3833             cfg.cn = [
3834                 {
3835                     tag: this.tagtype,
3836                     href : this.href || "#",
3837                     html: this.html || ''
3838                 }
3839             ];
3840             
3841             if (this.icon) {
3842                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3843             }
3844
3845             if(this.glyphicon) {
3846                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3847             }
3848             
3849             if (this.menu) {
3850                 
3851                 cfg.cn[0].html += " <span class='caret'></span>";
3852              
3853             }
3854             
3855             if (this.badge !== '') {
3856                  
3857                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3858             }
3859         }
3860         
3861         
3862         
3863         return cfg;
3864     },
3865     initEvents: function() 
3866     {
3867         if (typeof (this.menu) != 'undefined') {
3868             this.menu.parentType = this.xtype;
3869             this.menu.triggerEl = this.el;
3870             this.menu = this.addxtype(Roo.apply({}, this.menu));
3871         }
3872         
3873         this.el.select('a',true).on('click', this.onClick, this);
3874         
3875         if(this.tagtype == 'span'){
3876             this.el.select('span',true).on('click', this.onClick, this);
3877         }
3878        
3879         // at this point parent should be available..
3880         this.parent().register(this);
3881     },
3882     
3883     onClick : function(e)
3884     {
3885         if(
3886                 this.preventDefault || 
3887                 this.href == '#' ||
3888                 (this.animateRef && this.href.charAt(0) == '#')
3889         ){
3890             e.preventDefault();
3891         }
3892         
3893         if (this.disabled) {
3894             return;
3895         }
3896         
3897         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3898         if (tg && tg.transition) {
3899             Roo.log("waiting for the transitionend");
3900             return;
3901         }
3902         
3903         Roo.log("fire event clicked");
3904         if(this.fireEvent('click', this, e) === false){
3905             return;
3906         };
3907         
3908         if(this.tagtype == 'span'){
3909             return;
3910         }
3911         
3912         if(this.animateRef && this.href.charAt(0) == '#'){
3913             this.scrollToElement(e);
3914             return;
3915         }
3916         
3917         var p = this.parent();
3918         if (['tabs','pills'].indexOf(p.type)!==-1) {
3919             if (typeof(p.setActiveItem) !== 'undefined') {
3920                 p.setActiveItem(this);
3921             }
3922         }
3923         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3924         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3925             // remove the collapsed menu expand...
3926             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3927         }
3928         
3929     },
3930     
3931     isActive: function () {
3932         return this.active
3933     },
3934     setActive : function(state, fire, is_was_active)
3935     {
3936         if (this.active && !state & this.navId) {
3937             this.was_active = true;
3938             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3939             if (nv) {
3940                 nv.clearWasActive(this);
3941             }
3942             
3943         }
3944         this.active = state;
3945         
3946         if (!state ) {
3947             this.el.removeClass('active');
3948         } else if (!this.el.hasClass('active')) {
3949             this.el.addClass('active');
3950         }
3951         if (fire) {
3952             this.fireEvent('changed', this, state);
3953         }
3954         
3955         // show a panel if it's registered and related..
3956         
3957         if (!this.navId || !this.tabId || !state || is_was_active) {
3958             return;
3959         }
3960         
3961         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3962         if (!tg) {
3963             return;
3964         }
3965         var pan = tg.getPanelByName(this.tabId);
3966         if (!pan) {
3967             return;
3968         }
3969         // if we can not flip to new panel - go back to old nav highlight..
3970         if (false == tg.showPanel(pan)) {
3971             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3972             if (nv) {
3973                 var onav = nv.getWasActive();
3974                 if (onav) {
3975                     onav.setActive(true, false, true);
3976                 }
3977             }
3978             
3979         }
3980         
3981         
3982         
3983     },
3984      // this should not be here...
3985     setDisabled : function(state)
3986     {
3987         this.disabled = state;
3988         if (!state ) {
3989             this.el.removeClass('disabled');
3990         } else if (!this.el.hasClass('disabled')) {
3991             this.el.addClass('disabled');
3992         }
3993         
3994     },
3995     
3996     /**
3997      * Fetch the element to display the tooltip on.
3998      * @return {Roo.Element} defaults to this.el
3999      */
4000     tooltipEl : function()
4001     {
4002         return this.el.select('' + this.tagtype + '', true).first();
4003     },
4004     
4005     scrollToElement : function(e)
4006     {
4007         var c = document.body;
4008         
4009         var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4010         
4011         if(!target){
4012             return;
4013         }
4014
4015         var o = target.calcOffsetsTo(c);
4016         
4017         var options = {
4018             target : target,
4019             value : o[1]
4020         }
4021         
4022         this.fireEvent('scrollto', this, options, e);
4023         
4024         Roo.get(c).scrollTo('top', options.value, true);
4025         
4026         return;
4027     }
4028 });
4029  
4030
4031  /*
4032  * - LGPL
4033  *
4034  * sidebar item
4035  *
4036  *  li
4037  *    <span> icon </span>
4038  *    <span> text </span>
4039  *    <span>badge </span>
4040  */
4041
4042 /**
4043  * @class Roo.bootstrap.NavSidebarItem
4044  * @extends Roo.bootstrap.NavItem
4045  * Bootstrap Navbar.NavSidebarItem class
4046  * @constructor
4047  * Create a new Navbar Button
4048  * @param {Object} config The config object
4049  */
4050 Roo.bootstrap.NavSidebarItem = function(config){
4051     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4052     this.addEvents({
4053         // raw events
4054         /**
4055          * @event click
4056          * The raw click event for the entire grid.
4057          * @param {Roo.EventObject} e
4058          */
4059         "click" : true,
4060          /**
4061             * @event changed
4062             * Fires when the active item active state changes
4063             * @param {Roo.bootstrap.NavSidebarItem} this
4064             * @param {boolean} state the new state
4065              
4066          */
4067         'changed': true
4068     });
4069    
4070 };
4071
4072 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4073     
4074     
4075     getAutoCreate : function(){
4076         
4077         
4078         var a = {
4079                 tag: 'a',
4080                 href : this.href || '#',
4081                 cls: '',
4082                 html : '',
4083                 cn : []
4084         };
4085         var cfg = {
4086             tag: 'li',
4087             cls: '',
4088             cn: [ a ]
4089         }
4090         var span = {
4091             tag: 'span',
4092             html : this.html || ''
4093         }
4094         
4095         
4096         if (this.active) {
4097             cfg.cls += ' active';
4098         }
4099         
4100         // left icon..
4101         if (this.glyphicon || this.icon) {
4102             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4103             a.cn.push({ tag : 'i', cls : c }) ;
4104         }
4105         // html..
4106         a.cn.push(span);
4107         // then badge..
4108         if (this.badge !== '') {
4109             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4110         }
4111         // fi
4112         if (this.menu) {
4113             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4114             a.cls += 'dropdown-toggle treeview' ;
4115             
4116         }
4117         
4118         
4119         
4120         return cfg;
4121          
4122            
4123     }
4124    
4125      
4126  
4127 });
4128  
4129
4130  /*
4131  * - LGPL
4132  *
4133  * row
4134  * 
4135  */
4136
4137 /**
4138  * @class Roo.bootstrap.Row
4139  * @extends Roo.bootstrap.Component
4140  * Bootstrap Row class (contains columns...)
4141  * 
4142  * @constructor
4143  * Create a new Row
4144  * @param {Object} config The config object
4145  */
4146
4147 Roo.bootstrap.Row = function(config){
4148     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4149 };
4150
4151 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4152     
4153     getAutoCreate : function(){
4154        return {
4155             cls: 'row clearfix'
4156        };
4157     }
4158     
4159     
4160 });
4161
4162  
4163
4164  /*
4165  * - LGPL
4166  *
4167  * element
4168  * 
4169  */
4170
4171 /**
4172  * @class Roo.bootstrap.Element
4173  * @extends Roo.bootstrap.Component
4174  * Bootstrap Element class
4175  * @cfg {String} html contents of the element
4176  * @cfg {String} tag tag of the element
4177  * @cfg {String} cls class of the element
4178  * 
4179  * @constructor
4180  * Create a new Element
4181  * @param {Object} config The config object
4182  */
4183
4184 Roo.bootstrap.Element = function(config){
4185     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4186 };
4187
4188 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4189     
4190     tag: 'div',
4191     cls: '',
4192     html: '',
4193      
4194     
4195     getAutoCreate : function(){
4196         
4197         var cfg = {
4198             tag: this.tag,
4199             cls: this.cls,
4200             html: this.html
4201         }
4202         
4203         
4204         
4205         return cfg;
4206     }
4207    
4208 });
4209
4210  
4211
4212  /*
4213  * - LGPL
4214  *
4215  * pagination
4216  * 
4217  */
4218
4219 /**
4220  * @class Roo.bootstrap.Pagination
4221  * @extends Roo.bootstrap.Component
4222  * Bootstrap Pagination class
4223  * @cfg {String} size xs | sm | md | lg
4224  * @cfg {Boolean} inverse false | true
4225  * 
4226  * @constructor
4227  * Create a new Pagination
4228  * @param {Object} config The config object
4229  */
4230
4231 Roo.bootstrap.Pagination = function(config){
4232     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4233 };
4234
4235 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4236     
4237     cls: false,
4238     size: false,
4239     inverse: false,
4240     
4241     getAutoCreate : function(){
4242         var cfg = {
4243             tag: 'ul',
4244                 cls: 'pagination'
4245         };
4246         if (this.inverse) {
4247             cfg.cls += ' inverse';
4248         }
4249         if (this.html) {
4250             cfg.html=this.html;
4251         }
4252         if (this.cls) {
4253             cfg.cls += " " + this.cls;
4254         }
4255         return cfg;
4256     }
4257    
4258 });
4259
4260  
4261
4262  /*
4263  * - LGPL
4264  *
4265  * Pagination item
4266  * 
4267  */
4268
4269
4270 /**
4271  * @class Roo.bootstrap.PaginationItem
4272  * @extends Roo.bootstrap.Component
4273  * Bootstrap PaginationItem class
4274  * @cfg {String} html text
4275  * @cfg {String} href the link
4276  * @cfg {Boolean} preventDefault (true | false) default true
4277  * @cfg {Boolean} active (true | false) default false
4278  * @cfg {Boolean} disabled default false
4279  * 
4280  * 
4281  * @constructor
4282  * Create a new PaginationItem
4283  * @param {Object} config The config object
4284  */
4285
4286
4287 Roo.bootstrap.PaginationItem = function(config){
4288     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4289     this.addEvents({
4290         // raw events
4291         /**
4292          * @event click
4293          * The raw click event for the entire grid.
4294          * @param {Roo.EventObject} e
4295          */
4296         "click" : true
4297     });
4298 };
4299
4300 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4301     
4302     href : false,
4303     html : false,
4304     preventDefault: true,
4305     active : false,
4306     cls : false,
4307     disabled: false,
4308     
4309     getAutoCreate : function(){
4310         var cfg= {
4311             tag: 'li',
4312             cn: [
4313                 {
4314                     tag : 'a',
4315                     href : this.href ? this.href : '#',
4316                     html : this.html ? this.html : ''
4317                 }
4318             ]
4319         };
4320         
4321         if(this.cls){
4322             cfg.cls = this.cls;
4323         }
4324         
4325         if(this.disabled){
4326             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4327         }
4328         
4329         if(this.active){
4330             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4331         }
4332         
4333         return cfg;
4334     },
4335     
4336     initEvents: function() {
4337         
4338         this.el.on('click', this.onClick, this);
4339         
4340     },
4341     onClick : function(e)
4342     {
4343         Roo.log('PaginationItem on click ');
4344         if(this.preventDefault){
4345             e.preventDefault();
4346         }
4347         
4348         if(this.disabled){
4349             return;
4350         }
4351         
4352         this.fireEvent('click', this, e);
4353     }
4354    
4355 });
4356
4357  
4358
4359  /*
4360  * - LGPL
4361  *
4362  * slider
4363  * 
4364  */
4365
4366
4367 /**
4368  * @class Roo.bootstrap.Slider
4369  * @extends Roo.bootstrap.Component
4370  * Bootstrap Slider class
4371  *    
4372  * @constructor
4373  * Create a new Slider
4374  * @param {Object} config The config object
4375  */
4376
4377 Roo.bootstrap.Slider = function(config){
4378     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4379 };
4380
4381 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4382     
4383     getAutoCreate : function(){
4384         
4385         var cfg = {
4386             tag: 'div',
4387             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4388             cn: [
4389                 {
4390                     tag: 'a',
4391                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4392                 }
4393             ]
4394         }
4395         
4396         return cfg;
4397     }
4398    
4399 });
4400
4401  /*
4402  * Based on:
4403  * Ext JS Library 1.1.1
4404  * Copyright(c) 2006-2007, Ext JS, LLC.
4405  *
4406  * Originally Released Under LGPL - original licence link has changed is not relivant.
4407  *
4408  * Fork - LGPL
4409  * <script type="text/javascript">
4410  */
4411  
4412
4413 /**
4414  * @class Roo.grid.ColumnModel
4415  * @extends Roo.util.Observable
4416  * This is the default implementation of a ColumnModel used by the Grid. It defines
4417  * the columns in the grid.
4418  * <br>Usage:<br>
4419  <pre><code>
4420  var colModel = new Roo.grid.ColumnModel([
4421         {header: "Ticker", width: 60, sortable: true, locked: true},
4422         {header: "Company Name", width: 150, sortable: true},
4423         {header: "Market Cap.", width: 100, sortable: true},
4424         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4425         {header: "Employees", width: 100, sortable: true, resizable: false}
4426  ]);
4427  </code></pre>
4428  * <p>
4429  
4430  * The config options listed for this class are options which may appear in each
4431  * individual column definition.
4432  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4433  * @constructor
4434  * @param {Object} config An Array of column config objects. See this class's
4435  * config objects for details.
4436 */
4437 Roo.grid.ColumnModel = function(config){
4438         /**
4439      * The config passed into the constructor
4440      */
4441     this.config = config;
4442     this.lookup = {};
4443
4444     // if no id, create one
4445     // if the column does not have a dataIndex mapping,
4446     // map it to the order it is in the config
4447     for(var i = 0, len = config.length; i < len; i++){
4448         var c = config[i];
4449         if(typeof c.dataIndex == "undefined"){
4450             c.dataIndex = i;
4451         }
4452         if(typeof c.renderer == "string"){
4453             c.renderer = Roo.util.Format[c.renderer];
4454         }
4455         if(typeof c.id == "undefined"){
4456             c.id = Roo.id();
4457         }
4458         if(c.editor && c.editor.xtype){
4459             c.editor  = Roo.factory(c.editor, Roo.grid);
4460         }
4461         if(c.editor && c.editor.isFormField){
4462             c.editor = new Roo.grid.GridEditor(c.editor);
4463         }
4464         this.lookup[c.id] = c;
4465     }
4466
4467     /**
4468      * The width of columns which have no width specified (defaults to 100)
4469      * @type Number
4470      */
4471     this.defaultWidth = 100;
4472
4473     /**
4474      * Default sortable of columns which have no sortable specified (defaults to false)
4475      * @type Boolean
4476      */
4477     this.defaultSortable = false;
4478
4479     this.addEvents({
4480         /**
4481              * @event widthchange
4482              * Fires when the width of a column changes.
4483              * @param {ColumnModel} this
4484              * @param {Number} columnIndex The column index
4485              * @param {Number} newWidth The new width
4486              */
4487             "widthchange": true,
4488         /**
4489              * @event headerchange
4490              * Fires when the text of a header changes.
4491              * @param {ColumnModel} this
4492              * @param {Number} columnIndex The column index
4493              * @param {Number} newText The new header text
4494              */
4495             "headerchange": true,
4496         /**
4497              * @event hiddenchange
4498              * Fires when a column is hidden or "unhidden".
4499              * @param {ColumnModel} this
4500              * @param {Number} columnIndex The column index
4501              * @param {Boolean} hidden true if hidden, false otherwise
4502              */
4503             "hiddenchange": true,
4504             /**
4505          * @event columnmoved
4506          * Fires when a column is moved.
4507          * @param {ColumnModel} this
4508          * @param {Number} oldIndex
4509          * @param {Number} newIndex
4510          */
4511         "columnmoved" : true,
4512         /**
4513          * @event columlockchange
4514          * Fires when a column's locked state is changed
4515          * @param {ColumnModel} this
4516          * @param {Number} colIndex
4517          * @param {Boolean} locked true if locked
4518          */
4519         "columnlockchange" : true
4520     });
4521     Roo.grid.ColumnModel.superclass.constructor.call(this);
4522 };
4523 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4524     /**
4525      * @cfg {String} header The header text to display in the Grid view.
4526      */
4527     /**
4528      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4529      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4530      * specified, the column's index is used as an index into the Record's data Array.
4531      */
4532     /**
4533      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4534      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4535      */
4536     /**
4537      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4538      * Defaults to the value of the {@link #defaultSortable} property.
4539      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4540      */
4541     /**
4542      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4543      */
4544     /**
4545      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4546      */
4547     /**
4548      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4549      */
4550     /**
4551      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4552      */
4553     /**
4554      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4555      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4556      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4557      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4558      */
4559        /**
4560      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4561      */
4562     /**
4563      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4564      */
4565     /**
4566      * @cfg {String} cursor (Optional)
4567      */
4568     /**
4569      * @cfg {String} tooltip (Optional)
4570      */
4571     /**
4572      * Returns the id of the column at the specified index.
4573      * @param {Number} index The column index
4574      * @return {String} the id
4575      */
4576     getColumnId : function(index){
4577         return this.config[index].id;
4578     },
4579
4580     /**
4581      * Returns the column for a specified id.
4582      * @param {String} id The column id
4583      * @return {Object} the column
4584      */
4585     getColumnById : function(id){
4586         return this.lookup[id];
4587     },
4588
4589     
4590     /**
4591      * Returns the column for a specified dataIndex.
4592      * @param {String} dataIndex The column dataIndex
4593      * @return {Object|Boolean} the column or false if not found
4594      */
4595     getColumnByDataIndex: function(dataIndex){
4596         var index = this.findColumnIndex(dataIndex);
4597         return index > -1 ? this.config[index] : false;
4598     },
4599     
4600     /**
4601      * Returns the index for a specified column id.
4602      * @param {String} id The column id
4603      * @return {Number} the index, or -1 if not found
4604      */
4605     getIndexById : function(id){
4606         for(var i = 0, len = this.config.length; i < len; i++){
4607             if(this.config[i].id == id){
4608                 return i;
4609             }
4610         }
4611         return -1;
4612     },
4613     
4614     /**
4615      * Returns the index for a specified column dataIndex.
4616      * @param {String} dataIndex The column dataIndex
4617      * @return {Number} the index, or -1 if not found
4618      */
4619     
4620     findColumnIndex : function(dataIndex){
4621         for(var i = 0, len = this.config.length; i < len; i++){
4622             if(this.config[i].dataIndex == dataIndex){
4623                 return i;
4624             }
4625         }
4626         return -1;
4627     },
4628     
4629     
4630     moveColumn : function(oldIndex, newIndex){
4631         var c = this.config[oldIndex];
4632         this.config.splice(oldIndex, 1);
4633         this.config.splice(newIndex, 0, c);
4634         this.dataMap = null;
4635         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4636     },
4637
4638     isLocked : function(colIndex){
4639         return this.config[colIndex].locked === true;
4640     },
4641
4642     setLocked : function(colIndex, value, suppressEvent){
4643         if(this.isLocked(colIndex) == value){
4644             return;
4645         }
4646         this.config[colIndex].locked = value;
4647         if(!suppressEvent){
4648             this.fireEvent("columnlockchange", this, colIndex, value);
4649         }
4650     },
4651
4652     getTotalLockedWidth : function(){
4653         var totalWidth = 0;
4654         for(var i = 0; i < this.config.length; i++){
4655             if(this.isLocked(i) && !this.isHidden(i)){
4656                 this.totalWidth += this.getColumnWidth(i);
4657             }
4658         }
4659         return totalWidth;
4660     },
4661
4662     getLockedCount : function(){
4663         for(var i = 0, len = this.config.length; i < len; i++){
4664             if(!this.isLocked(i)){
4665                 return i;
4666             }
4667         }
4668     },
4669
4670     /**
4671      * Returns the number of columns.
4672      * @return {Number}
4673      */
4674     getColumnCount : function(visibleOnly){
4675         if(visibleOnly === true){
4676             var c = 0;
4677             for(var i = 0, len = this.config.length; i < len; i++){
4678                 if(!this.isHidden(i)){
4679                     c++;
4680                 }
4681             }
4682             return c;
4683         }
4684         return this.config.length;
4685     },
4686
4687     /**
4688      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4689      * @param {Function} fn
4690      * @param {Object} scope (optional)
4691      * @return {Array} result
4692      */
4693     getColumnsBy : function(fn, scope){
4694         var r = [];
4695         for(var i = 0, len = this.config.length; i < len; i++){
4696             var c = this.config[i];
4697             if(fn.call(scope||this, c, i) === true){
4698                 r[r.length] = c;
4699             }
4700         }
4701         return r;
4702     },
4703
4704     /**
4705      * Returns true if the specified column is sortable.
4706      * @param {Number} col The column index
4707      * @return {Boolean}
4708      */
4709     isSortable : function(col){
4710         if(typeof this.config[col].sortable == "undefined"){
4711             return this.defaultSortable;
4712         }
4713         return this.config[col].sortable;
4714     },
4715
4716     /**
4717      * Returns the rendering (formatting) function defined for the column.
4718      * @param {Number} col The column index.
4719      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4720      */
4721     getRenderer : function(col){
4722         if(!this.config[col].renderer){
4723             return Roo.grid.ColumnModel.defaultRenderer;
4724         }
4725         return this.config[col].renderer;
4726     },
4727
4728     /**
4729      * Sets the rendering (formatting) function for a column.
4730      * @param {Number} col The column index
4731      * @param {Function} fn The function to use to process the cell's raw data
4732      * to return HTML markup for the grid view. The render function is called with
4733      * the following parameters:<ul>
4734      * <li>Data value.</li>
4735      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4736      * <li>css A CSS style string to apply to the table cell.</li>
4737      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4738      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4739      * <li>Row index</li>
4740      * <li>Column index</li>
4741      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4742      */
4743     setRenderer : function(col, fn){
4744         this.config[col].renderer = fn;
4745     },
4746
4747     /**
4748      * Returns the width for the specified column.
4749      * @param {Number} col The column index
4750      * @return {Number}
4751      */
4752     getColumnWidth : function(col){
4753         return this.config[col].width * 1 || this.defaultWidth;
4754     },
4755
4756     /**
4757      * Sets the width for a column.
4758      * @param {Number} col The column index
4759      * @param {Number} width The new width
4760      */
4761     setColumnWidth : function(col, width, suppressEvent){
4762         this.config[col].width = width;
4763         this.totalWidth = null;
4764         if(!suppressEvent){
4765              this.fireEvent("widthchange", this, col, width);
4766         }
4767     },
4768
4769     /**
4770      * Returns the total width of all columns.
4771      * @param {Boolean} includeHidden True to include hidden column widths
4772      * @return {Number}
4773      */
4774     getTotalWidth : function(includeHidden){
4775         if(!this.totalWidth){
4776             this.totalWidth = 0;
4777             for(var i = 0, len = this.config.length; i < len; i++){
4778                 if(includeHidden || !this.isHidden(i)){
4779                     this.totalWidth += this.getColumnWidth(i);
4780                 }
4781             }
4782         }
4783         return this.totalWidth;
4784     },
4785
4786     /**
4787      * Returns the header for the specified column.
4788      * @param {Number} col The column index
4789      * @return {String}
4790      */
4791     getColumnHeader : function(col){
4792         return this.config[col].header;
4793     },
4794
4795     /**
4796      * Sets the header for a column.
4797      * @param {Number} col The column index
4798      * @param {String} header The new header
4799      */
4800     setColumnHeader : function(col, header){
4801         this.config[col].header = header;
4802         this.fireEvent("headerchange", this, col, header);
4803     },
4804
4805     /**
4806      * Returns the tooltip for the specified column.
4807      * @param {Number} col The column index
4808      * @return {String}
4809      */
4810     getColumnTooltip : function(col){
4811             return this.config[col].tooltip;
4812     },
4813     /**
4814      * Sets the tooltip for a column.
4815      * @param {Number} col The column index
4816      * @param {String} tooltip The new tooltip
4817      */
4818     setColumnTooltip : function(col, tooltip){
4819             this.config[col].tooltip = tooltip;
4820     },
4821
4822     /**
4823      * Returns the dataIndex for the specified column.
4824      * @param {Number} col The column index
4825      * @return {Number}
4826      */
4827     getDataIndex : function(col){
4828         return this.config[col].dataIndex;
4829     },
4830
4831     /**
4832      * Sets the dataIndex for a column.
4833      * @param {Number} col The column index
4834      * @param {Number} dataIndex The new dataIndex
4835      */
4836     setDataIndex : function(col, dataIndex){
4837         this.config[col].dataIndex = dataIndex;
4838     },
4839
4840     
4841     
4842     /**
4843      * Returns true if the cell is editable.
4844      * @param {Number} colIndex The column index
4845      * @param {Number} rowIndex The row index
4846      * @return {Boolean}
4847      */
4848     isCellEditable : function(colIndex, rowIndex){
4849         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4850     },
4851
4852     /**
4853      * Returns the editor defined for the cell/column.
4854      * return false or null to disable editing.
4855      * @param {Number} colIndex The column index
4856      * @param {Number} rowIndex The row index
4857      * @return {Object}
4858      */
4859     getCellEditor : function(colIndex, rowIndex){
4860         return this.config[colIndex].editor;
4861     },
4862
4863     /**
4864      * Sets if a column is editable.
4865      * @param {Number} col The column index
4866      * @param {Boolean} editable True if the column is editable
4867      */
4868     setEditable : function(col, editable){
4869         this.config[col].editable = editable;
4870     },
4871
4872
4873     /**
4874      * Returns true if the column is hidden.
4875      * @param {Number} colIndex The column index
4876      * @return {Boolean}
4877      */
4878     isHidden : function(colIndex){
4879         return this.config[colIndex].hidden;
4880     },
4881
4882
4883     /**
4884      * Returns true if the column width cannot be changed
4885      */
4886     isFixed : function(colIndex){
4887         return this.config[colIndex].fixed;
4888     },
4889
4890     /**
4891      * Returns true if the column can be resized
4892      * @return {Boolean}
4893      */
4894     isResizable : function(colIndex){
4895         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4896     },
4897     /**
4898      * Sets if a column is hidden.
4899      * @param {Number} colIndex The column index
4900      * @param {Boolean} hidden True if the column is hidden
4901      */
4902     setHidden : function(colIndex, hidden){
4903         this.config[colIndex].hidden = hidden;
4904         this.totalWidth = null;
4905         this.fireEvent("hiddenchange", this, colIndex, hidden);
4906     },
4907
4908     /**
4909      * Sets the editor for a column.
4910      * @param {Number} col The column index
4911      * @param {Object} editor The editor object
4912      */
4913     setEditor : function(col, editor){
4914         this.config[col].editor = editor;
4915     }
4916 });
4917
4918 Roo.grid.ColumnModel.defaultRenderer = function(value){
4919         if(typeof value == "string" && value.length < 1){
4920             return "&#160;";
4921         }
4922         return value;
4923 };
4924
4925 // Alias for backwards compatibility
4926 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4927 /*
4928  * Based on:
4929  * Ext JS Library 1.1.1
4930  * Copyright(c) 2006-2007, Ext JS, LLC.
4931  *
4932  * Originally Released Under LGPL - original licence link has changed is not relivant.
4933  *
4934  * Fork - LGPL
4935  * <script type="text/javascript">
4936  */
4937  
4938 /**
4939  * @class Roo.LoadMask
4940  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4941  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4942  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4943  * element's UpdateManager load indicator and will be destroyed after the initial load.
4944  * @constructor
4945  * Create a new LoadMask
4946  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4947  * @param {Object} config The config object
4948  */
4949 Roo.LoadMask = function(el, config){
4950     this.el = Roo.get(el);
4951     Roo.apply(this, config);
4952     if(this.store){
4953         this.store.on('beforeload', this.onBeforeLoad, this);
4954         this.store.on('load', this.onLoad, this);
4955         this.store.on('loadexception', this.onLoadException, this);
4956         this.removeMask = false;
4957     }else{
4958         var um = this.el.getUpdateManager();
4959         um.showLoadIndicator = false; // disable the default indicator
4960         um.on('beforeupdate', this.onBeforeLoad, this);
4961         um.on('update', this.onLoad, this);
4962         um.on('failure', this.onLoad, this);
4963         this.removeMask = true;
4964     }
4965 };
4966
4967 Roo.LoadMask.prototype = {
4968     /**
4969      * @cfg {Boolean} removeMask
4970      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4971      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4972      */
4973     /**
4974      * @cfg {String} msg
4975      * The text to display in a centered loading message box (defaults to 'Loading...')
4976      */
4977     msg : 'Loading...',
4978     /**
4979      * @cfg {String} msgCls
4980      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4981      */
4982     msgCls : 'x-mask-loading',
4983
4984     /**
4985      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4986      * @type Boolean
4987      */
4988     disabled: false,
4989
4990     /**
4991      * Disables the mask to prevent it from being displayed
4992      */
4993     disable : function(){
4994        this.disabled = true;
4995     },
4996
4997     /**
4998      * Enables the mask so that it can be displayed
4999      */
5000     enable : function(){
5001         this.disabled = false;
5002     },
5003     
5004     onLoadException : function()
5005     {
5006         Roo.log(arguments);
5007         
5008         if (typeof(arguments[3]) != 'undefined') {
5009             Roo.MessageBox.alert("Error loading",arguments[3]);
5010         } 
5011         /*
5012         try {
5013             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5014                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5015             }   
5016         } catch(e) {
5017             
5018         }
5019         */
5020     
5021         
5022         
5023         this.el.unmask(this.removeMask);
5024     },
5025     // private
5026     onLoad : function()
5027     {
5028         this.el.unmask(this.removeMask);
5029     },
5030
5031     // private
5032     onBeforeLoad : function(){
5033         if(!this.disabled){
5034             this.el.mask(this.msg, this.msgCls);
5035         }
5036     },
5037
5038     // private
5039     destroy : function(){
5040         if(this.store){
5041             this.store.un('beforeload', this.onBeforeLoad, this);
5042             this.store.un('load', this.onLoad, this);
5043             this.store.un('loadexception', this.onLoadException, this);
5044         }else{
5045             var um = this.el.getUpdateManager();
5046             um.un('beforeupdate', this.onBeforeLoad, this);
5047             um.un('update', this.onLoad, this);
5048             um.un('failure', this.onLoad, this);
5049         }
5050     }
5051 };/*
5052  * - LGPL
5053  *
5054  * table
5055  * 
5056  */
5057
5058 /**
5059  * @class Roo.bootstrap.Table
5060  * @extends Roo.bootstrap.Component
5061  * Bootstrap Table class
5062  * @cfg {String} cls table class
5063  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5064  * @cfg {String} bgcolor Specifies the background color for a table
5065  * @cfg {Number} border Specifies whether the table cells should have borders or not
5066  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5067  * @cfg {Number} cellspacing Specifies the space between cells
5068  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5069  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5070  * @cfg {String} sortable Specifies that the table should be sortable
5071  * @cfg {String} summary Specifies a summary of the content of a table
5072  * @cfg {Number} width Specifies the width of a table
5073  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5074  * 
5075  * @cfg {boolean} striped Should the rows be alternative striped
5076  * @cfg {boolean} bordered Add borders to the table
5077  * @cfg {boolean} hover Add hover highlighting
5078  * @cfg {boolean} condensed Format condensed
5079  * @cfg {boolean} responsive Format condensed
5080  * @cfg {Boolean} loadMask (true|false) default false
5081  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5082  * @cfg {Boolean} thead (true|false) generate thead, default true
5083  * @cfg {Boolean} RowSelection (true|false) default false
5084  * @cfg {Boolean} CellSelection (true|false) default false
5085  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5086  
5087  * 
5088  * @constructor
5089  * Create a new Table
5090  * @param {Object} config The config object
5091  */
5092
5093 Roo.bootstrap.Table = function(config){
5094     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5095     
5096     if (this.sm) {
5097         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5098         this.sm = this.selModel;
5099         this.sm.xmodule = this.xmodule || false;
5100     }
5101     if (this.cm && typeof(this.cm.config) == 'undefined') {
5102         this.colModel = new Roo.grid.ColumnModel(this.cm);
5103         this.cm = this.colModel;
5104         this.cm.xmodule = this.xmodule || false;
5105     }
5106     if (this.store) {
5107         this.store= Roo.factory(this.store, Roo.data);
5108         this.ds = this.store;
5109         this.ds.xmodule = this.xmodule || false;
5110          
5111     }
5112     if (this.footer && this.store) {
5113         this.footer.dataSource = this.ds;
5114         this.footer = Roo.factory(this.footer);
5115     }
5116     
5117     /** @private */
5118     this.addEvents({
5119         /**
5120          * @event cellclick
5121          * Fires when a cell is clicked
5122          * @param {Roo.bootstrap.Table} this
5123          * @param {Roo.Element} el
5124          * @param {Number} rowIndex
5125          * @param {Number} columnIndex
5126          * @param {Roo.EventObject} e
5127          */
5128         "cellclick" : true,
5129         /**
5130          * @event celldblclick
5131          * Fires when a cell is double clicked
5132          * @param {Roo.bootstrap.Table} this
5133          * @param {Roo.Element} el
5134          * @param {Number} rowIndex
5135          * @param {Number} columnIndex
5136          * @param {Roo.EventObject} e
5137          */
5138         "celldblclick" : true,
5139         /**
5140          * @event rowclick
5141          * Fires when a row is clicked
5142          * @param {Roo.bootstrap.Table} this
5143          * @param {Roo.Element} el
5144          * @param {Number} rowIndex
5145          * @param {Roo.EventObject} e
5146          */
5147         "rowclick" : true,
5148         /**
5149          * @event rowdblclick
5150          * Fires when a row is double clicked
5151          * @param {Roo.bootstrap.Table} this
5152          * @param {Roo.Element} el
5153          * @param {Number} rowIndex
5154          * @param {Roo.EventObject} e
5155          */
5156         "rowdblclick" : true,
5157         /**
5158          * @event mouseover
5159          * Fires when a mouseover occur
5160          * @param {Roo.bootstrap.Table} this
5161          * @param {Roo.Element} el
5162          * @param {Number} rowIndex
5163          * @param {Number} columnIndex
5164          * @param {Roo.EventObject} e
5165          */
5166         "mouseover" : true,
5167         /**
5168          * @event mouseout
5169          * Fires when a mouseout occur
5170          * @param {Roo.bootstrap.Table} this
5171          * @param {Roo.Element} el
5172          * @param {Number} rowIndex
5173          * @param {Number} columnIndex
5174          * @param {Roo.EventObject} e
5175          */
5176         "mouseout" : true,
5177         /**
5178          * @event rowclass
5179          * Fires when a row is rendered, so you can change add a style to it.
5180          * @param {Roo.bootstrap.Table} this
5181          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5182          */
5183         'rowclass' : true,
5184           /**
5185          * @event rowsrendered
5186          * Fires when all the  rows have been rendered
5187          * @param {Roo.bootstrap.Table} this
5188          */
5189         'rowsrendered' : true
5190         
5191     });
5192 };
5193
5194 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5195     
5196     cls: false,
5197     align: false,
5198     bgcolor: false,
5199     border: false,
5200     cellpadding: false,
5201     cellspacing: false,
5202     frame: false,
5203     rules: false,
5204     sortable: false,
5205     summary: false,
5206     width: false,
5207     striped : false,
5208     bordered: false,
5209     hover:  false,
5210     condensed : false,
5211     responsive : false,
5212     sm : false,
5213     cm : false,
5214     store : false,
5215     loadMask : false,
5216     tfoot : true,
5217     thead : true,
5218     RowSelection : false,
5219     CellSelection : false,
5220     layout : false,
5221     
5222     // Roo.Element - the tbody
5223     mainBody: false, 
5224     
5225     getAutoCreate : function(){
5226         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5227         
5228         cfg = {
5229             tag: 'table',
5230             cls : 'table',
5231             cn : []
5232         }
5233             
5234         if (this.striped) {
5235             cfg.cls += ' table-striped';
5236         }
5237         
5238         if (this.hover) {
5239             cfg.cls += ' table-hover';
5240         }
5241         if (this.bordered) {
5242             cfg.cls += ' table-bordered';
5243         }
5244         if (this.condensed) {
5245             cfg.cls += ' table-condensed';
5246         }
5247         if (this.responsive) {
5248             cfg.cls += ' table-responsive';
5249         }
5250         
5251         if (this.cls) {
5252             cfg.cls+=  ' ' +this.cls;
5253         }
5254         
5255         // this lot should be simplifed...
5256         
5257         if (this.align) {
5258             cfg.align=this.align;
5259         }
5260         if (this.bgcolor) {
5261             cfg.bgcolor=this.bgcolor;
5262         }
5263         if (this.border) {
5264             cfg.border=this.border;
5265         }
5266         if (this.cellpadding) {
5267             cfg.cellpadding=this.cellpadding;
5268         }
5269         if (this.cellspacing) {
5270             cfg.cellspacing=this.cellspacing;
5271         }
5272         if (this.frame) {
5273             cfg.frame=this.frame;
5274         }
5275         if (this.rules) {
5276             cfg.rules=this.rules;
5277         }
5278         if (this.sortable) {
5279             cfg.sortable=this.sortable;
5280         }
5281         if (this.summary) {
5282             cfg.summary=this.summary;
5283         }
5284         if (this.width) {
5285             cfg.width=this.width;
5286         }
5287         if (this.layout) {
5288             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5289         }
5290         
5291         if(this.store || this.cm){
5292             if(this.thead){
5293                 cfg.cn.push(this.renderHeader());
5294             }
5295             
5296             cfg.cn.push(this.renderBody());
5297             
5298             if(this.tfoot){
5299                 cfg.cn.push(this.renderFooter());
5300             }
5301             
5302             cfg.cls+=  ' TableGrid';
5303         }
5304         
5305         return { cn : [ cfg ] };
5306     },
5307     
5308     initEvents : function()
5309     {   
5310         if(!this.store || !this.cm){
5311             return;
5312         }
5313         
5314         //Roo.log('initEvents with ds!!!!');
5315         
5316         this.mainBody = this.el.select('tbody', true).first();
5317         
5318         
5319         var _this = this;
5320         
5321         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5322             e.on('click', _this.sort, _this);
5323         });
5324         
5325         this.el.on("click", this.onClick, this);
5326         this.el.on("dblclick", this.onDblClick, this);
5327         
5328         // why is this done????? = it breaks dialogs??
5329         //this.parent().el.setStyle('position', 'relative');
5330         
5331         
5332         if (this.footer) {
5333             this.footer.parentId = this.id;
5334             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5335         }
5336         
5337         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5338         
5339         this.store.on('load', this.onLoad, this);
5340         this.store.on('beforeload', this.onBeforeLoad, this);
5341         this.store.on('update', this.onUpdate, this);
5342         this.store.on('add', this.onAdd, this);
5343         
5344     },
5345     
5346     onMouseover : function(e, el)
5347     {
5348         var cell = Roo.get(el);
5349         
5350         if(!cell){
5351             return;
5352         }
5353         
5354         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5355             cell = cell.findParent('td', false, true);
5356         }
5357         
5358         var row = cell.findParent('tr', false, true);
5359         var cellIndex = cell.dom.cellIndex;
5360         var rowIndex = row.dom.rowIndex - 1; // start from 0
5361         
5362         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5363         
5364     },
5365     
5366     onMouseout : function(e, el)
5367     {
5368         var cell = Roo.get(el);
5369         
5370         if(!cell){
5371             return;
5372         }
5373         
5374         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5375             cell = cell.findParent('td', false, true);
5376         }
5377         
5378         var row = cell.findParent('tr', false, true);
5379         var cellIndex = cell.dom.cellIndex;
5380         var rowIndex = row.dom.rowIndex - 1; // start from 0
5381         
5382         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5383         
5384     },
5385     
5386     onClick : function(e, el)
5387     {
5388         var cell = Roo.get(el);
5389         
5390         if(!cell || (!this.CellSelection && !this.RowSelection)){
5391             return;
5392         }
5393         
5394         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5395             cell = cell.findParent('td', false, true);
5396         }
5397         
5398         if(!cell || typeof(cell) == 'undefined'){
5399             return;
5400         }
5401         
5402         var row = cell.findParent('tr', false, true);
5403         
5404         if(!row || typeof(row) == 'undefined'){
5405             return;
5406         }
5407         
5408         var cellIndex = cell.dom.cellIndex;
5409         var rowIndex = this.getRowIndex(row);
5410         
5411         if(this.CellSelection){
5412             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5413         }
5414         
5415         if(this.RowSelection){
5416             this.fireEvent('rowclick', this, row, rowIndex, e);
5417         }
5418         
5419         
5420     },
5421     
5422     onDblClick : function(e,el)
5423     {
5424         var cell = Roo.get(el);
5425         
5426         if(!cell || (!this.CellSelection && !this.RowSelection)){
5427             return;
5428         }
5429         
5430         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5431             cell = cell.findParent('td', false, true);
5432         }
5433         
5434         if(!cell || typeof(cell) == 'undefined'){
5435             return;
5436         }
5437         
5438         var row = cell.findParent('tr', false, true);
5439         
5440         if(!row || typeof(row) == 'undefined'){
5441             return;
5442         }
5443         
5444         var cellIndex = cell.dom.cellIndex;
5445         var rowIndex = this.getRowIndex(row);
5446         
5447         if(this.CellSelection){
5448             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5449         }
5450         
5451         if(this.RowSelection){
5452             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5453         }
5454     },
5455     
5456     sort : function(e,el)
5457     {
5458         var col = Roo.get(el);
5459         
5460         if(!col.hasClass('sortable')){
5461             return;
5462         }
5463         
5464         var sort = col.attr('sort');
5465         var dir = 'ASC';
5466         
5467         if(col.hasClass('glyphicon-arrow-up')){
5468             dir = 'DESC';
5469         }
5470         
5471         this.store.sortInfo = {field : sort, direction : dir};
5472         
5473         if (this.footer) {
5474             Roo.log("calling footer first");
5475             this.footer.onClick('first');
5476         } else {
5477         
5478             this.store.load({ params : { start : 0 } });
5479         }
5480     },
5481     
5482     renderHeader : function()
5483     {
5484         var header = {
5485             tag: 'thead',
5486             cn : []
5487         };
5488         
5489         var cm = this.cm;
5490         
5491         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5492             
5493             var config = cm.config[i];
5494                     
5495             var c = {
5496                 tag: 'th',
5497                 style : '',
5498                 html: cm.getColumnHeader(i)
5499             };
5500             
5501             if(typeof(config.tooltip) != 'undefined'){
5502                 c.tooltip = config.tooltip;
5503             }
5504             
5505             if(typeof(config.colspan) != 'undefined'){
5506                 c.colspan = config.colspan;
5507             }
5508             
5509             if(typeof(config.hidden) != 'undefined' && config.hidden){
5510                 c.style += ' display:none;';
5511             }
5512             
5513             if(typeof(config.dataIndex) != 'undefined'){
5514                 c.sort = config.dataIndex;
5515             }
5516             
5517             if(typeof(config.sortable) != 'undefined' && config.sortable){
5518                 c.cls = 'sortable';
5519             }
5520             
5521             if(typeof(config.align) != 'undefined' && config.align.length){
5522                 c.style += ' text-align:' + config.align + ';';
5523             }
5524             
5525             if(typeof(config.width) != 'undefined'){
5526                 c.style += ' width:' + config.width + 'px;';
5527             }
5528             
5529             header.cn.push(c)
5530         }
5531         
5532         return header;
5533     },
5534     
5535     renderBody : function()
5536     {
5537         var body = {
5538             tag: 'tbody',
5539             cn : [
5540                 {
5541                     tag: 'tr',
5542                     cn : [
5543                         {
5544                             tag : 'td',
5545                             colspan :  this.cm.getColumnCount()
5546                         }
5547                     ]
5548                 }
5549             ]
5550         };
5551         
5552         return body;
5553     },
5554     
5555     renderFooter : function()
5556     {
5557         var footer = {
5558             tag: 'tfoot',
5559             cn : [
5560                 {
5561                     tag: 'tr',
5562                     cn : [
5563                         {
5564                             tag : 'td',
5565                             colspan :  this.cm.getColumnCount()
5566                         }
5567                     ]
5568                 }
5569             ]
5570         };
5571         
5572         return footer;
5573     },
5574     
5575     
5576     
5577     onLoad : function()
5578     {
5579         Roo.log('ds onload');
5580         this.clear();
5581         
5582         var _this = this;
5583         var cm = this.cm;
5584         var ds = this.store;
5585         
5586         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5587             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5588             
5589             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5590                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5591             }
5592             
5593             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5594                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5595             }
5596         });
5597         
5598         var tbody =  this.mainBody;
5599               
5600         if(ds.getCount() > 0){
5601             ds.data.each(function(d,rowIndex){
5602                 var row =  this.renderRow(cm, ds, rowIndex);
5603                 
5604                 tbody.createChild(row);
5605                 
5606                 var _this = this;
5607                 
5608                 if(row.cellObjects.length){
5609                     Roo.each(row.cellObjects, function(r){
5610                         _this.renderCellObject(r);
5611                     })
5612                 }
5613                 
5614             }, this);
5615         }
5616         
5617         Roo.each(this.el.select('tbody td', true).elements, function(e){
5618             e.on('mouseover', _this.onMouseover, _this);
5619         });
5620         
5621         Roo.each(this.el.select('tbody td', true).elements, function(e){
5622             e.on('mouseout', _this.onMouseout, _this);
5623         });
5624         this.fireEvent('rowsrendered', this);
5625         //if(this.loadMask){
5626         //    this.maskEl.hide();
5627         //}
5628     },
5629     
5630     
5631     onUpdate : function(ds,record)
5632     {
5633         this.refreshRow(record);
5634     },
5635     
5636     onRemove : function(ds, record, index, isUpdate){
5637         if(isUpdate !== true){
5638             this.fireEvent("beforerowremoved", this, index, record);
5639         }
5640         var bt = this.mainBody.dom;
5641         
5642         var rows = this.el.select('tbody > tr', true).elements;
5643         
5644         if(typeof(rows[index]) != 'undefined'){
5645             bt.removeChild(rows[index].dom);
5646         }
5647         
5648 //        if(bt.rows[index]){
5649 //            bt.removeChild(bt.rows[index]);
5650 //        }
5651         
5652         if(isUpdate !== true){
5653             //this.stripeRows(index);
5654             //this.syncRowHeights(index, index);
5655             //this.layout();
5656             this.fireEvent("rowremoved", this, index, record);
5657         }
5658     },
5659     
5660     onAdd : function(ds, records, rowIndex)
5661     {
5662         //Roo.log('on Add called');
5663         // - note this does not handle multiple adding very well..
5664         var bt = this.mainBody.dom;
5665         for (var i =0 ; i < records.length;i++) {
5666             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5667             //Roo.log(records[i]);
5668             //Roo.log(this.store.getAt(rowIndex+i));
5669             this.insertRow(this.store, rowIndex + i, false);
5670             return;
5671         }
5672         
5673     },
5674     
5675     
5676     refreshRow : function(record){
5677         var ds = this.store, index;
5678         if(typeof record == 'number'){
5679             index = record;
5680             record = ds.getAt(index);
5681         }else{
5682             index = ds.indexOf(record);
5683         }
5684         this.insertRow(ds, index, true);
5685         this.onRemove(ds, record, index+1, true);
5686         //this.syncRowHeights(index, index);
5687         //this.layout();
5688         this.fireEvent("rowupdated", this, index, record);
5689     },
5690     
5691     insertRow : function(dm, rowIndex, isUpdate){
5692         
5693         if(!isUpdate){
5694             this.fireEvent("beforerowsinserted", this, rowIndex);
5695         }
5696             //var s = this.getScrollState();
5697         var row = this.renderRow(this.cm, this.store, rowIndex);
5698         // insert before rowIndex..
5699         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5700         
5701         var _this = this;
5702                 
5703         if(row.cellObjects.length){
5704             Roo.each(row.cellObjects, function(r){
5705                 _this.renderCellObject(r);
5706             })
5707         }
5708             
5709         if(!isUpdate){
5710             this.fireEvent("rowsinserted", this, rowIndex);
5711             //this.syncRowHeights(firstRow, lastRow);
5712             //this.stripeRows(firstRow);
5713             //this.layout();
5714         }
5715         
5716     },
5717     
5718     
5719     getRowDom : function(rowIndex)
5720     {
5721         var rows = this.el.select('tbody > tr', true).elements;
5722         
5723         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5724         
5725     },
5726     // returns the object tree for a tr..
5727   
5728     
5729     renderRow : function(cm, ds, rowIndex) 
5730     {
5731         
5732         var d = ds.getAt(rowIndex);
5733         
5734         var row = {
5735             tag : 'tr',
5736             cn : []
5737         };
5738             
5739         var cellObjects = [];
5740         
5741         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5742             var config = cm.config[i];
5743             
5744             var renderer = cm.getRenderer(i);
5745             var value = '';
5746             var id = false;
5747             
5748             if(typeof(renderer) !== 'undefined'){
5749                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5750             }
5751             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5752             // and are rendered into the cells after the row is rendered - using the id for the element.
5753             
5754             if(typeof(value) === 'object'){
5755                 id = Roo.id();
5756                 cellObjects.push({
5757                     container : id,
5758                     cfg : value 
5759                 })
5760             }
5761             
5762             var rowcfg = {
5763                 record: d,
5764                 rowIndex : rowIndex,
5765                 colIndex : i,
5766                 rowClass : ''
5767             }
5768
5769             this.fireEvent('rowclass', this, rowcfg);
5770             
5771             var td = {
5772                 tag: 'td',
5773                 cls : rowcfg.rowClass,
5774                 style: '',
5775                 html: (typeof(value) === 'object') ? '' : value
5776             };
5777             
5778             if (id) {
5779                 td.id = id;
5780             }
5781             
5782             if(typeof(config.colspan) != 'undefined'){
5783                 td.colspan = config.colspan;
5784             }
5785             
5786             if(typeof(config.hidden) != 'undefined' && config.hidden){
5787                 td.style += ' display:none;';
5788             }
5789             
5790             if(typeof(config.align) != 'undefined' && config.align.length){
5791                 td.style += ' text-align:' + config.align + ';';
5792             }
5793             
5794             if(typeof(config.width) != 'undefined'){
5795                 td.style += ' width:' +  config.width + 'px;';
5796             }
5797             
5798             if(typeof(config.cursor) != 'undefined'){
5799                 td.style += ' cursor:' +  config.cursor + ';';
5800             }
5801              
5802             row.cn.push(td);
5803            
5804         }
5805         
5806         row.cellObjects = cellObjects;
5807         
5808         return row;
5809           
5810     },
5811     
5812     
5813     
5814     onBeforeLoad : function()
5815     {
5816         //Roo.log('ds onBeforeLoad');
5817         
5818         //this.clear();
5819         
5820         //if(this.loadMask){
5821         //    this.maskEl.show();
5822         //}
5823     },
5824      /**
5825      * Remove all rows
5826      */
5827     clear : function()
5828     {
5829         this.el.select('tbody', true).first().dom.innerHTML = '';
5830     },
5831     /**
5832      * Show or hide a row.
5833      * @param {Number} rowIndex to show or hide
5834      * @param {Boolean} state hide
5835      */
5836     setRowVisibility : function(rowIndex, state)
5837     {
5838         var bt = this.mainBody.dom;
5839         
5840         var rows = this.el.select('tbody > tr', true).elements;
5841         
5842         if(typeof(rows[rowIndex]) == 'undefined'){
5843             return;
5844         }
5845         rows[rowIndex].dom.style.display = state ? '' : 'none';
5846     },
5847     
5848     
5849     getSelectionModel : function(){
5850         if(!this.selModel){
5851             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5852         }
5853         return this.selModel;
5854     },
5855     /*
5856      * Render the Roo.bootstrap object from renderder
5857      */
5858     renderCellObject : function(r)
5859     {
5860         var _this = this;
5861         
5862         var t = r.cfg.render(r.container);
5863         
5864         if(r.cfg.cn){
5865             Roo.each(r.cfg.cn, function(c){
5866                 var child = {
5867                     container: t.getChildContainer(),
5868                     cfg: c
5869                 }
5870                 _this.renderCellObject(child);
5871             })
5872         }
5873     },
5874     
5875     getRowIndex : function(row)
5876     {
5877         var rowIndex = -1;
5878         
5879         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5880             if(el != row){
5881                 return;
5882             }
5883             
5884             rowIndex = index;
5885         });
5886         
5887         return rowIndex;
5888     }
5889    
5890 });
5891
5892  
5893
5894  /*
5895  * - LGPL
5896  *
5897  * table cell
5898  * 
5899  */
5900
5901 /**
5902  * @class Roo.bootstrap.TableCell
5903  * @extends Roo.bootstrap.Component
5904  * Bootstrap TableCell class
5905  * @cfg {String} html cell contain text
5906  * @cfg {String} cls cell class
5907  * @cfg {String} tag cell tag (td|th) default td
5908  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5909  * @cfg {String} align Aligns the content in a cell
5910  * @cfg {String} axis Categorizes cells
5911  * @cfg {String} bgcolor Specifies the background color of a cell
5912  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5913  * @cfg {Number} colspan Specifies the number of columns a cell should span
5914  * @cfg {String} headers Specifies one or more header cells a cell is related to
5915  * @cfg {Number} height Sets the height of a cell
5916  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5917  * @cfg {Number} rowspan Sets the number of rows a cell should span
5918  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5919  * @cfg {String} valign Vertical aligns the content in a cell
5920  * @cfg {Number} width Specifies the width of a cell
5921  * 
5922  * @constructor
5923  * Create a new TableCell
5924  * @param {Object} config The config object
5925  */
5926
5927 Roo.bootstrap.TableCell = function(config){
5928     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5929 };
5930
5931 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5932     
5933     html: false,
5934     cls: false,
5935     tag: false,
5936     abbr: false,
5937     align: false,
5938     axis: false,
5939     bgcolor: false,
5940     charoff: false,
5941     colspan: false,
5942     headers: false,
5943     height: false,
5944     nowrap: false,
5945     rowspan: false,
5946     scope: false,
5947     valign: false,
5948     width: false,
5949     
5950     
5951     getAutoCreate : function(){
5952         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5953         
5954         cfg = {
5955             tag: 'td'
5956         }
5957         
5958         if(this.tag){
5959             cfg.tag = this.tag;
5960         }
5961         
5962         if (this.html) {
5963             cfg.html=this.html
5964         }
5965         if (this.cls) {
5966             cfg.cls=this.cls
5967         }
5968         if (this.abbr) {
5969             cfg.abbr=this.abbr
5970         }
5971         if (this.align) {
5972             cfg.align=this.align
5973         }
5974         if (this.axis) {
5975             cfg.axis=this.axis
5976         }
5977         if (this.bgcolor) {
5978             cfg.bgcolor=this.bgcolor
5979         }
5980         if (this.charoff) {
5981             cfg.charoff=this.charoff
5982         }
5983         if (this.colspan) {
5984             cfg.colspan=this.colspan
5985         }
5986         if (this.headers) {
5987             cfg.headers=this.headers
5988         }
5989         if (this.height) {
5990             cfg.height=this.height
5991         }
5992         if (this.nowrap) {
5993             cfg.nowrap=this.nowrap
5994         }
5995         if (this.rowspan) {
5996             cfg.rowspan=this.rowspan
5997         }
5998         if (this.scope) {
5999             cfg.scope=this.scope
6000         }
6001         if (this.valign) {
6002             cfg.valign=this.valign
6003         }
6004         if (this.width) {
6005             cfg.width=this.width
6006         }
6007         
6008         
6009         return cfg;
6010     }
6011    
6012 });
6013
6014  
6015
6016  /*
6017  * - LGPL
6018  *
6019  * table row
6020  * 
6021  */
6022
6023 /**
6024  * @class Roo.bootstrap.TableRow
6025  * @extends Roo.bootstrap.Component
6026  * Bootstrap TableRow class
6027  * @cfg {String} cls row class
6028  * @cfg {String} align Aligns the content in a table row
6029  * @cfg {String} bgcolor Specifies a background color for a table row
6030  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6031  * @cfg {String} valign Vertical aligns the content in a table row
6032  * 
6033  * @constructor
6034  * Create a new TableRow
6035  * @param {Object} config The config object
6036  */
6037
6038 Roo.bootstrap.TableRow = function(config){
6039     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6040 };
6041
6042 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
6043     
6044     cls: false,
6045     align: false,
6046     bgcolor: false,
6047     charoff: false,
6048     valign: false,
6049     
6050     getAutoCreate : function(){
6051         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6052         
6053         cfg = {
6054             tag: 'tr'
6055         }
6056             
6057         if(this.cls){
6058             cfg.cls = this.cls;
6059         }
6060         if(this.align){
6061             cfg.align = this.align;
6062         }
6063         if(this.bgcolor){
6064             cfg.bgcolor = this.bgcolor;
6065         }
6066         if(this.charoff){
6067             cfg.charoff = this.charoff;
6068         }
6069         if(this.valign){
6070             cfg.valign = this.valign;
6071         }
6072         
6073         return cfg;
6074     }
6075    
6076 });
6077
6078  
6079
6080  /*
6081  * - LGPL
6082  *
6083  * table body
6084  * 
6085  */
6086
6087 /**
6088  * @class Roo.bootstrap.TableBody
6089  * @extends Roo.bootstrap.Component
6090  * Bootstrap TableBody class
6091  * @cfg {String} cls element class
6092  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6093  * @cfg {String} align Aligns the content inside the element
6094  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6095  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6096  * 
6097  * @constructor
6098  * Create a new TableBody
6099  * @param {Object} config The config object
6100  */
6101
6102 Roo.bootstrap.TableBody = function(config){
6103     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6104 };
6105
6106 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
6107     
6108     cls: false,
6109     tag: false,
6110     align: false,
6111     charoff: false,
6112     valign: false,
6113     
6114     getAutoCreate : function(){
6115         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6116         
6117         cfg = {
6118             tag: 'tbody'
6119         }
6120             
6121         if (this.cls) {
6122             cfg.cls=this.cls
6123         }
6124         if(this.tag){
6125             cfg.tag = this.tag;
6126         }
6127         
6128         if(this.align){
6129             cfg.align = this.align;
6130         }
6131         if(this.charoff){
6132             cfg.charoff = this.charoff;
6133         }
6134         if(this.valign){
6135             cfg.valign = this.valign;
6136         }
6137         
6138         return cfg;
6139     }
6140     
6141     
6142 //    initEvents : function()
6143 //    {
6144 //        
6145 //        if(!this.store){
6146 //            return;
6147 //        }
6148 //        
6149 //        this.store = Roo.factory(this.store, Roo.data);
6150 //        this.store.on('load', this.onLoad, this);
6151 //        
6152 //        this.store.load();
6153 //        
6154 //    },
6155 //    
6156 //    onLoad: function () 
6157 //    {   
6158 //        this.fireEvent('load', this);
6159 //    }
6160 //    
6161 //   
6162 });
6163
6164  
6165
6166  /*
6167  * Based on:
6168  * Ext JS Library 1.1.1
6169  * Copyright(c) 2006-2007, Ext JS, LLC.
6170  *
6171  * Originally Released Under LGPL - original licence link has changed is not relivant.
6172  *
6173  * Fork - LGPL
6174  * <script type="text/javascript">
6175  */
6176
6177 // as we use this in bootstrap.
6178 Roo.namespace('Roo.form');
6179  /**
6180  * @class Roo.form.Action
6181  * Internal Class used to handle form actions
6182  * @constructor
6183  * @param {Roo.form.BasicForm} el The form element or its id
6184  * @param {Object} config Configuration options
6185  */
6186
6187  
6188  
6189 // define the action interface
6190 Roo.form.Action = function(form, options){
6191     this.form = form;
6192     this.options = options || {};
6193 };
6194 /**
6195  * Client Validation Failed
6196  * @const 
6197  */
6198 Roo.form.Action.CLIENT_INVALID = 'client';
6199 /**
6200  * Server Validation Failed
6201  * @const 
6202  */
6203 Roo.form.Action.SERVER_INVALID = 'server';
6204  /**
6205  * Connect to Server Failed
6206  * @const 
6207  */
6208 Roo.form.Action.CONNECT_FAILURE = 'connect';
6209 /**
6210  * Reading Data from Server Failed
6211  * @const 
6212  */
6213 Roo.form.Action.LOAD_FAILURE = 'load';
6214
6215 Roo.form.Action.prototype = {
6216     type : 'default',
6217     failureType : undefined,
6218     response : undefined,
6219     result : undefined,
6220
6221     // interface method
6222     run : function(options){
6223
6224     },
6225
6226     // interface method
6227     success : function(response){
6228
6229     },
6230
6231     // interface method
6232     handleResponse : function(response){
6233
6234     },
6235
6236     // default connection failure
6237     failure : function(response){
6238         
6239         this.response = response;
6240         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6241         this.form.afterAction(this, false);
6242     },
6243
6244     processResponse : function(response){
6245         this.response = response;
6246         if(!response.responseText){
6247             return true;
6248         }
6249         this.result = this.handleResponse(response);
6250         return this.result;
6251     },
6252
6253     // utility functions used internally
6254     getUrl : function(appendParams){
6255         var url = this.options.url || this.form.url || this.form.el.dom.action;
6256         if(appendParams){
6257             var p = this.getParams();
6258             if(p){
6259                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6260             }
6261         }
6262         return url;
6263     },
6264
6265     getMethod : function(){
6266         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6267     },
6268
6269     getParams : function(){
6270         var bp = this.form.baseParams;
6271         var p = this.options.params;
6272         if(p){
6273             if(typeof p == "object"){
6274                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6275             }else if(typeof p == 'string' && bp){
6276                 p += '&' + Roo.urlEncode(bp);
6277             }
6278         }else if(bp){
6279             p = Roo.urlEncode(bp);
6280         }
6281         return p;
6282     },
6283
6284     createCallback : function(){
6285         return {
6286             success: this.success,
6287             failure: this.failure,
6288             scope: this,
6289             timeout: (this.form.timeout*1000),
6290             upload: this.form.fileUpload ? this.success : undefined
6291         };
6292     }
6293 };
6294
6295 Roo.form.Action.Submit = function(form, options){
6296     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6297 };
6298
6299 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6300     type : 'submit',
6301
6302     haveProgress : false,
6303     uploadComplete : false,
6304     
6305     // uploadProgress indicator.
6306     uploadProgress : function()
6307     {
6308         if (!this.form.progressUrl) {
6309             return;
6310         }
6311         
6312         if (!this.haveProgress) {
6313             Roo.MessageBox.progress("Uploading", "Uploading");
6314         }
6315         if (this.uploadComplete) {
6316            Roo.MessageBox.hide();
6317            return;
6318         }
6319         
6320         this.haveProgress = true;
6321    
6322         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6323         
6324         var c = new Roo.data.Connection();
6325         c.request({
6326             url : this.form.progressUrl,
6327             params: {
6328                 id : uid
6329             },
6330             method: 'GET',
6331             success : function(req){
6332                //console.log(data);
6333                 var rdata = false;
6334                 var edata;
6335                 try  {
6336                    rdata = Roo.decode(req.responseText)
6337                 } catch (e) {
6338                     Roo.log("Invalid data from server..");
6339                     Roo.log(edata);
6340                     return;
6341                 }
6342                 if (!rdata || !rdata.success) {
6343                     Roo.log(rdata);
6344                     Roo.MessageBox.alert(Roo.encode(rdata));
6345                     return;
6346                 }
6347                 var data = rdata.data;
6348                 
6349                 if (this.uploadComplete) {
6350                    Roo.MessageBox.hide();
6351                    return;
6352                 }
6353                    
6354                 if (data){
6355                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6356                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6357                     );
6358                 }
6359                 this.uploadProgress.defer(2000,this);
6360             },
6361        
6362             failure: function(data) {
6363                 Roo.log('progress url failed ');
6364                 Roo.log(data);
6365             },
6366             scope : this
6367         });
6368            
6369     },
6370     
6371     
6372     run : function()
6373     {
6374         // run get Values on the form, so it syncs any secondary forms.
6375         this.form.getValues();
6376         
6377         var o = this.options;
6378         var method = this.getMethod();
6379         var isPost = method == 'POST';
6380         if(o.clientValidation === false || this.form.isValid()){
6381             
6382             if (this.form.progressUrl) {
6383                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6384                     (new Date() * 1) + '' + Math.random());
6385                     
6386             } 
6387             
6388             
6389             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6390                 form:this.form.el.dom,
6391                 url:this.getUrl(!isPost),
6392                 method: method,
6393                 params:isPost ? this.getParams() : null,
6394                 isUpload: this.form.fileUpload
6395             }));
6396             
6397             this.uploadProgress();
6398
6399         }else if (o.clientValidation !== false){ // client validation failed
6400             this.failureType = Roo.form.Action.CLIENT_INVALID;
6401             this.form.afterAction(this, false);
6402         }
6403     },
6404
6405     success : function(response)
6406     {
6407         this.uploadComplete= true;
6408         if (this.haveProgress) {
6409             Roo.MessageBox.hide();
6410         }
6411         
6412         
6413         var result = this.processResponse(response);
6414         if(result === true || result.success){
6415             this.form.afterAction(this, true);
6416             return;
6417         }
6418         if(result.errors){
6419             this.form.markInvalid(result.errors);
6420             this.failureType = Roo.form.Action.SERVER_INVALID;
6421         }
6422         this.form.afterAction(this, false);
6423     },
6424     failure : function(response)
6425     {
6426         this.uploadComplete= true;
6427         if (this.haveProgress) {
6428             Roo.MessageBox.hide();
6429         }
6430         
6431         this.response = response;
6432         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6433         this.form.afterAction(this, false);
6434     },
6435     
6436     handleResponse : function(response){
6437         if(this.form.errorReader){
6438             var rs = this.form.errorReader.read(response);
6439             var errors = [];
6440             if(rs.records){
6441                 for(var i = 0, len = rs.records.length; i < len; i++) {
6442                     var r = rs.records[i];
6443                     errors[i] = r.data;
6444                 }
6445             }
6446             if(errors.length < 1){
6447                 errors = null;
6448             }
6449             return {
6450                 success : rs.success,
6451                 errors : errors
6452             };
6453         }
6454         var ret = false;
6455         try {
6456             ret = Roo.decode(response.responseText);
6457         } catch (e) {
6458             ret = {
6459                 success: false,
6460                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6461                 errors : []
6462             };
6463         }
6464         return ret;
6465         
6466     }
6467 });
6468
6469
6470 Roo.form.Action.Load = function(form, options){
6471     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6472     this.reader = this.form.reader;
6473 };
6474
6475 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6476     type : 'load',
6477
6478     run : function(){
6479         
6480         Roo.Ajax.request(Roo.apply(
6481                 this.createCallback(), {
6482                     method:this.getMethod(),
6483                     url:this.getUrl(false),
6484                     params:this.getParams()
6485         }));
6486     },
6487
6488     success : function(response){
6489         
6490         var result = this.processResponse(response);
6491         if(result === true || !result.success || !result.data){
6492             this.failureType = Roo.form.Action.LOAD_FAILURE;
6493             this.form.afterAction(this, false);
6494             return;
6495         }
6496         this.form.clearInvalid();
6497         this.form.setValues(result.data);
6498         this.form.afterAction(this, true);
6499     },
6500
6501     handleResponse : function(response){
6502         if(this.form.reader){
6503             var rs = this.form.reader.read(response);
6504             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6505             return {
6506                 success : rs.success,
6507                 data : data
6508             };
6509         }
6510         return Roo.decode(response.responseText);
6511     }
6512 });
6513
6514 Roo.form.Action.ACTION_TYPES = {
6515     'load' : Roo.form.Action.Load,
6516     'submit' : Roo.form.Action.Submit
6517 };/*
6518  * - LGPL
6519  *
6520  * form
6521  * 
6522  */
6523
6524 /**
6525  * @class Roo.bootstrap.Form
6526  * @extends Roo.bootstrap.Component
6527  * Bootstrap Form class
6528  * @cfg {String} method  GET | POST (default POST)
6529  * @cfg {String} labelAlign top | left (default top)
6530  * @cfg {String} align left  | right - for navbars
6531  * @cfg {Boolean} loadMask load mask when submit (default true)
6532
6533  * 
6534  * @constructor
6535  * Create a new Form
6536  * @param {Object} config The config object
6537  */
6538
6539
6540 Roo.bootstrap.Form = function(config){
6541     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6542     this.addEvents({
6543         /**
6544          * @event clientvalidation
6545          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6546          * @param {Form} this
6547          * @param {Boolean} valid true if the form has passed client-side validation
6548          */
6549         clientvalidation: true,
6550         /**
6551          * @event beforeaction
6552          * Fires before any action is performed. Return false to cancel the action.
6553          * @param {Form} this
6554          * @param {Action} action The action to be performed
6555          */
6556         beforeaction: true,
6557         /**
6558          * @event actionfailed
6559          * Fires when an action fails.
6560          * @param {Form} this
6561          * @param {Action} action The action that failed
6562          */
6563         actionfailed : true,
6564         /**
6565          * @event actioncomplete
6566          * Fires when an action is completed.
6567          * @param {Form} this
6568          * @param {Action} action The action that completed
6569          */
6570         actioncomplete : true
6571     });
6572     
6573 };
6574
6575 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6576       
6577      /**
6578      * @cfg {String} method
6579      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6580      */
6581     method : 'POST',
6582     /**
6583      * @cfg {String} url
6584      * The URL to use for form actions if one isn't supplied in the action options.
6585      */
6586     /**
6587      * @cfg {Boolean} fileUpload
6588      * Set to true if this form is a file upload.
6589      */
6590      
6591     /**
6592      * @cfg {Object} baseParams
6593      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6594      */
6595       
6596     /**
6597      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6598      */
6599     timeout: 30,
6600     /**
6601      * @cfg {Sting} align (left|right) for navbar forms
6602      */
6603     align : 'left',
6604
6605     // private
6606     activeAction : null,
6607  
6608     /**
6609      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6610      * element by passing it or its id or mask the form itself by passing in true.
6611      * @type Mixed
6612      */
6613     waitMsgTarget : false,
6614     
6615     loadMask : true,
6616     
6617     getAutoCreate : function(){
6618         
6619         var cfg = {
6620             tag: 'form',
6621             method : this.method || 'POST',
6622             id : this.id || Roo.id(),
6623             cls : ''
6624         }
6625         if (this.parent().xtype.match(/^Nav/)) {
6626             cfg.cls = 'navbar-form navbar-' + this.align;
6627             
6628         }
6629         
6630         if (this.labelAlign == 'left' ) {
6631             cfg.cls += ' form-horizontal';
6632         }
6633         
6634         
6635         return cfg;
6636     },
6637     initEvents : function()
6638     {
6639         this.el.on('submit', this.onSubmit, this);
6640         // this was added as random key presses on the form where triggering form submit.
6641         this.el.on('keypress', function(e) {
6642             if (e.getCharCode() != 13) {
6643                 return true;
6644             }
6645             // we might need to allow it for textareas.. and some other items.
6646             // check e.getTarget().
6647             
6648             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6649                 return true;
6650             }
6651         
6652             Roo.log("keypress blocked");
6653             
6654             e.preventDefault();
6655             return false;
6656         });
6657         
6658     },
6659     // private
6660     onSubmit : function(e){
6661         e.stopEvent();
6662     },
6663     
6664      /**
6665      * Returns true if client-side validation on the form is successful.
6666      * @return Boolean
6667      */
6668     isValid : function(){
6669         var items = this.getItems();
6670         var valid = true;
6671         items.each(function(f){
6672            if(!f.validate()){
6673                valid = false;
6674                
6675            }
6676         });
6677         return valid;
6678     },
6679     /**
6680      * Returns true if any fields in this form have changed since their original load.
6681      * @return Boolean
6682      */
6683     isDirty : function(){
6684         var dirty = false;
6685         var items = this.getItems();
6686         items.each(function(f){
6687            if(f.isDirty()){
6688                dirty = true;
6689                return false;
6690            }
6691            return true;
6692         });
6693         return dirty;
6694     },
6695      /**
6696      * Performs a predefined action (submit or load) or custom actions you define on this form.
6697      * @param {String} actionName The name of the action type
6698      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6699      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6700      * accept other config options):
6701      * <pre>
6702 Property          Type             Description
6703 ----------------  ---------------  ----------------------------------------------------------------------------------
6704 url               String           The url for the action (defaults to the form's url)
6705 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6706 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6707 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6708                                    validate the form on the client (defaults to false)
6709      * </pre>
6710      * @return {BasicForm} this
6711      */
6712     doAction : function(action, options){
6713         if(typeof action == 'string'){
6714             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6715         }
6716         if(this.fireEvent('beforeaction', this, action) !== false){
6717             this.beforeAction(action);
6718             action.run.defer(100, action);
6719         }
6720         return this;
6721     },
6722     
6723     // private
6724     beforeAction : function(action){
6725         var o = action.options;
6726         
6727         if(this.loadMask){
6728             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6729         }
6730         // not really supported yet.. ??
6731         
6732         //if(this.waitMsgTarget === true){
6733         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6734         //}else if(this.waitMsgTarget){
6735         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6736         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6737         //}else {
6738         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6739        // }
6740          
6741     },
6742
6743     // private
6744     afterAction : function(action, success){
6745         this.activeAction = null;
6746         var o = action.options;
6747         
6748         //if(this.waitMsgTarget === true){
6749             this.el.unmask();
6750         //}else if(this.waitMsgTarget){
6751         //    this.waitMsgTarget.unmask();
6752         //}else{
6753         //    Roo.MessageBox.updateProgress(1);
6754         //    Roo.MessageBox.hide();
6755        // }
6756         // 
6757         if(success){
6758             if(o.reset){
6759                 this.reset();
6760             }
6761             Roo.callback(o.success, o.scope, [this, action]);
6762             this.fireEvent('actioncomplete', this, action);
6763             
6764         }else{
6765             
6766             // failure condition..
6767             // we have a scenario where updates need confirming.
6768             // eg. if a locking scenario exists..
6769             // we look for { errors : { needs_confirm : true }} in the response.
6770             if (
6771                 (typeof(action.result) != 'undefined')  &&
6772                 (typeof(action.result.errors) != 'undefined')  &&
6773                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6774            ){
6775                 var _t = this;
6776                 Roo.log("not supported yet");
6777                  /*
6778                 
6779                 Roo.MessageBox.confirm(
6780                     "Change requires confirmation",
6781                     action.result.errorMsg,
6782                     function(r) {
6783                         if (r != 'yes') {
6784                             return;
6785                         }
6786                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6787                     }
6788                     
6789                 );
6790                 */
6791                 
6792                 
6793                 return;
6794             }
6795             
6796             Roo.callback(o.failure, o.scope, [this, action]);
6797             // show an error message if no failed handler is set..
6798             if (!this.hasListener('actionfailed')) {
6799                 Roo.log("need to add dialog support");
6800                 /*
6801                 Roo.MessageBox.alert("Error",
6802                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6803                         action.result.errorMsg :
6804                         "Saving Failed, please check your entries or try again"
6805                 );
6806                 */
6807             }
6808             
6809             this.fireEvent('actionfailed', this, action);
6810         }
6811         
6812     },
6813     /**
6814      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6815      * @param {String} id The value to search for
6816      * @return Field
6817      */
6818     findField : function(id){
6819         var items = this.getItems();
6820         var field = items.get(id);
6821         if(!field){
6822              items.each(function(f){
6823                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6824                     field = f;
6825                     return false;
6826                 }
6827                 return true;
6828             });
6829         }
6830         return field || null;
6831     },
6832      /**
6833      * Mark fields in this form invalid in bulk.
6834      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6835      * @return {BasicForm} this
6836      */
6837     markInvalid : function(errors){
6838         if(errors instanceof Array){
6839             for(var i = 0, len = errors.length; i < len; i++){
6840                 var fieldError = errors[i];
6841                 var f = this.findField(fieldError.id);
6842                 if(f){
6843                     f.markInvalid(fieldError.msg);
6844                 }
6845             }
6846         }else{
6847             var field, id;
6848             for(id in errors){
6849                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6850                     field.markInvalid(errors[id]);
6851                 }
6852             }
6853         }
6854         //Roo.each(this.childForms || [], function (f) {
6855         //    f.markInvalid(errors);
6856         //});
6857         
6858         return this;
6859     },
6860
6861     /**
6862      * Set values for fields in this form in bulk.
6863      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6864      * @return {BasicForm} this
6865      */
6866     setValues : function(values){
6867         if(values instanceof Array){ // array of objects
6868             for(var i = 0, len = values.length; i < len; i++){
6869                 var v = values[i];
6870                 var f = this.findField(v.id);
6871                 if(f){
6872                     f.setValue(v.value);
6873                     if(this.trackResetOnLoad){
6874                         f.originalValue = f.getValue();
6875                     }
6876                 }
6877             }
6878         }else{ // object hash
6879             var field, id;
6880             for(id in values){
6881                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6882                     
6883                     if (field.setFromData && 
6884                         field.valueField && 
6885                         field.displayField &&
6886                         // combos' with local stores can 
6887                         // be queried via setValue()
6888                         // to set their value..
6889                         (field.store && !field.store.isLocal)
6890                         ) {
6891                         // it's a combo
6892                         var sd = { };
6893                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6894                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6895                         field.setFromData(sd);
6896                         
6897                     } else {
6898                         field.setValue(values[id]);
6899                     }
6900                     
6901                     
6902                     if(this.trackResetOnLoad){
6903                         field.originalValue = field.getValue();
6904                     }
6905                 }
6906             }
6907         }
6908          
6909         //Roo.each(this.childForms || [], function (f) {
6910         //    f.setValues(values);
6911         //});
6912                 
6913         return this;
6914     },
6915
6916     /**
6917      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6918      * they are returned as an array.
6919      * @param {Boolean} asString
6920      * @return {Object}
6921      */
6922     getValues : function(asString){
6923         //if (this.childForms) {
6924             // copy values from the child forms
6925         //    Roo.each(this.childForms, function (f) {
6926         //        this.setValues(f.getValues());
6927         //    }, this);
6928         //}
6929         
6930         
6931         
6932         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6933         if(asString === true){
6934             return fs;
6935         }
6936         return Roo.urlDecode(fs);
6937     },
6938     
6939     /**
6940      * Returns the fields in this form as an object with key/value pairs. 
6941      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6942      * @return {Object}
6943      */
6944     getFieldValues : function(with_hidden)
6945     {
6946         var items = this.getItems();
6947         var ret = {};
6948         items.each(function(f){
6949             if (!f.getName()) {
6950                 return;
6951             }
6952             var v = f.getValue();
6953             if (f.inputType =='radio') {
6954                 if (typeof(ret[f.getName()]) == 'undefined') {
6955                     ret[f.getName()] = ''; // empty..
6956                 }
6957                 
6958                 if (!f.el.dom.checked) {
6959                     return;
6960                     
6961                 }
6962                 v = f.el.dom.value;
6963                 
6964             }
6965             
6966             // not sure if this supported any more..
6967             if ((typeof(v) == 'object') && f.getRawValue) {
6968                 v = f.getRawValue() ; // dates..
6969             }
6970             // combo boxes where name != hiddenName...
6971             if (f.name != f.getName()) {
6972                 ret[f.name] = f.getRawValue();
6973             }
6974             ret[f.getName()] = v;
6975         });
6976         
6977         return ret;
6978     },
6979
6980     /**
6981      * Clears all invalid messages in this form.
6982      * @return {BasicForm} this
6983      */
6984     clearInvalid : function(){
6985         var items = this.getItems();
6986         
6987         items.each(function(f){
6988            f.clearInvalid();
6989         });
6990         
6991         
6992         
6993         return this;
6994     },
6995
6996     /**
6997      * Resets this form.
6998      * @return {BasicForm} this
6999      */
7000     reset : function(){
7001         var items = this.getItems();
7002         items.each(function(f){
7003             f.reset();
7004         });
7005         
7006         Roo.each(this.childForms || [], function (f) {
7007             f.reset();
7008         });
7009        
7010         
7011         return this;
7012     },
7013     getItems : function()
7014     {
7015         var r=new Roo.util.MixedCollection(false, function(o){
7016             return o.id || (o.id = Roo.id());
7017         });
7018         var iter = function(el) {
7019             if (el.inputEl) {
7020                 r.add(el);
7021             }
7022             if (!el.items) {
7023                 return;
7024             }
7025             Roo.each(el.items,function(e) {
7026                 iter(e);
7027             });
7028             
7029             
7030         };
7031         
7032         iter(this);
7033         return r;
7034         
7035         
7036         
7037         
7038     }
7039     
7040 });
7041
7042  
7043 /*
7044  * Based on:
7045  * Ext JS Library 1.1.1
7046  * Copyright(c) 2006-2007, Ext JS, LLC.
7047  *
7048  * Originally Released Under LGPL - original licence link has changed is not relivant.
7049  *
7050  * Fork - LGPL
7051  * <script type="text/javascript">
7052  */
7053 /**
7054  * @class Roo.form.VTypes
7055  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7056  * @singleton
7057  */
7058 Roo.form.VTypes = function(){
7059     // closure these in so they are only created once.
7060     var alpha = /^[a-zA-Z_]+$/;
7061     var alphanum = /^[a-zA-Z0-9_]+$/;
7062     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7063     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7064
7065     // All these messages and functions are configurable
7066     return {
7067         /**
7068          * The function used to validate email addresses
7069          * @param {String} value The email address
7070          */
7071         'email' : function(v){
7072             return email.test(v);
7073         },
7074         /**
7075          * The error text to display when the email validation function returns false
7076          * @type String
7077          */
7078         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7079         /**
7080          * The keystroke filter mask to be applied on email input
7081          * @type RegExp
7082          */
7083         'emailMask' : /[a-z0-9_\.\-@]/i,
7084
7085         /**
7086          * The function used to validate URLs
7087          * @param {String} value The URL
7088          */
7089         'url' : function(v){
7090             return url.test(v);
7091         },
7092         /**
7093          * The error text to display when the url validation function returns false
7094          * @type String
7095          */
7096         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7097         
7098         /**
7099          * The function used to validate alpha values
7100          * @param {String} value The value
7101          */
7102         'alpha' : function(v){
7103             return alpha.test(v);
7104         },
7105         /**
7106          * The error text to display when the alpha validation function returns false
7107          * @type String
7108          */
7109         'alphaText' : 'This field should only contain letters and _',
7110         /**
7111          * The keystroke filter mask to be applied on alpha input
7112          * @type RegExp
7113          */
7114         'alphaMask' : /[a-z_]/i,
7115
7116         /**
7117          * The function used to validate alphanumeric values
7118          * @param {String} value The value
7119          */
7120         'alphanum' : function(v){
7121             return alphanum.test(v);
7122         },
7123         /**
7124          * The error text to display when the alphanumeric validation function returns false
7125          * @type String
7126          */
7127         'alphanumText' : 'This field should only contain letters, numbers and _',
7128         /**
7129          * The keystroke filter mask to be applied on alphanumeric input
7130          * @type RegExp
7131          */
7132         'alphanumMask' : /[a-z0-9_]/i
7133     };
7134 }();/*
7135  * - LGPL
7136  *
7137  * Input
7138  * 
7139  */
7140
7141 /**
7142  * @class Roo.bootstrap.Input
7143  * @extends Roo.bootstrap.Component
7144  * Bootstrap Input class
7145  * @cfg {Boolean} disabled is it disabled
7146  * @cfg {String} fieldLabel - the label associated
7147  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7148  * @cfg {String} name name of the input
7149  * @cfg {string} fieldLabel - the label associated
7150  * @cfg {string}  inputType - input / file submit ...
7151  * @cfg {string} placeholder - placeholder to put in text.
7152  * @cfg {string}  before - input group add on before
7153  * @cfg {string} after - input group add on after
7154  * @cfg {string} size - (lg|sm) or leave empty..
7155  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7156  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7157  * @cfg {Number} md colspan out of 12 for computer-sized screens
7158  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7159  * @cfg {string} value default value of the input
7160  * @cfg {Number} labelWidth set the width of label (0-12)
7161  * @cfg {String} labelAlign (top|left)
7162  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7163  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7164
7165  * @cfg {String} align (left|center|right) Default left
7166  * 
7167  * 
7168  * 
7169  * @constructor
7170  * Create a new Input
7171  * @param {Object} config The config object
7172  */
7173
7174 Roo.bootstrap.Input = function(config){
7175     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7176    
7177         this.addEvents({
7178             /**
7179              * @event focus
7180              * Fires when this field receives input focus.
7181              * @param {Roo.form.Field} this
7182              */
7183             focus : true,
7184             /**
7185              * @event blur
7186              * Fires when this field loses input focus.
7187              * @param {Roo.form.Field} this
7188              */
7189             blur : true,
7190             /**
7191              * @event specialkey
7192              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7193              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7194              * @param {Roo.form.Field} this
7195              * @param {Roo.EventObject} e The event object
7196              */
7197             specialkey : true,
7198             /**
7199              * @event change
7200              * Fires just before the field blurs if the field value has changed.
7201              * @param {Roo.form.Field} this
7202              * @param {Mixed} newValue The new value
7203              * @param {Mixed} oldValue The original value
7204              */
7205             change : true,
7206             /**
7207              * @event invalid
7208              * Fires after the field has been marked as invalid.
7209              * @param {Roo.form.Field} this
7210              * @param {String} msg The validation message
7211              */
7212             invalid : true,
7213             /**
7214              * @event valid
7215              * Fires after the field has been validated with no errors.
7216              * @param {Roo.form.Field} this
7217              */
7218             valid : true,
7219              /**
7220              * @event keyup
7221              * Fires after the key up
7222              * @param {Roo.form.Field} this
7223              * @param {Roo.EventObject}  e The event Object
7224              */
7225             keyup : true
7226         });
7227 };
7228
7229 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7230      /**
7231      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7232       automatic validation (defaults to "keyup").
7233      */
7234     validationEvent : "keyup",
7235      /**
7236      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7237      */
7238     validateOnBlur : true,
7239     /**
7240      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7241      */
7242     validationDelay : 250,
7243      /**
7244      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7245      */
7246     focusClass : "x-form-focus",  // not needed???
7247     
7248        
7249     /**
7250      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7251      */
7252     invalidClass : "has-warning",
7253     
7254     /**
7255      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7256      */
7257     validClass : "has-success",
7258     
7259     /**
7260      * @cfg {Boolean} hasFeedback (true|false) default true
7261      */
7262     hasFeedback : true,
7263     
7264     /**
7265      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7266      */
7267     invalidFeedbackClass : "glyphicon-warning-sign",
7268     
7269     /**
7270      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7271      */
7272     validFeedbackClass : "glyphicon-ok",
7273     
7274     /**
7275      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7276      */
7277     selectOnFocus : false,
7278     
7279      /**
7280      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7281      */
7282     maskRe : null,
7283        /**
7284      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7285      */
7286     vtype : null,
7287     
7288       /**
7289      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7290      */
7291     disableKeyFilter : false,
7292     
7293        /**
7294      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7295      */
7296     disabled : false,
7297      /**
7298      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7299      */
7300     allowBlank : true,
7301     /**
7302      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7303      */
7304     blankText : "This field is required",
7305     
7306      /**
7307      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7308      */
7309     minLength : 0,
7310     /**
7311      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7312      */
7313     maxLength : Number.MAX_VALUE,
7314     /**
7315      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7316      */
7317     minLengthText : "The minimum length for this field is {0}",
7318     /**
7319      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7320      */
7321     maxLengthText : "The maximum length for this field is {0}",
7322   
7323     
7324     /**
7325      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7326      * If available, this function will be called only after the basic validators all return true, and will be passed the
7327      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7328      */
7329     validator : null,
7330     /**
7331      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7332      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7333      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7334      */
7335     regex : null,
7336     /**
7337      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7338      */
7339     regexText : "",
7340     
7341     autocomplete: false,
7342     
7343     
7344     fieldLabel : '',
7345     inputType : 'text',
7346     
7347     name : false,
7348     placeholder: false,
7349     before : false,
7350     after : false,
7351     size : false,
7352     hasFocus : false,
7353     preventMark: false,
7354     isFormField : true,
7355     value : '',
7356     labelWidth : 2,
7357     labelAlign : false,
7358     readOnly : false,
7359     align : false,
7360     formatedValue : false,
7361     
7362     parentLabelAlign : function()
7363     {
7364         var parent = this;
7365         while (parent.parent()) {
7366             parent = parent.parent();
7367             if (typeof(parent.labelAlign) !='undefined') {
7368                 return parent.labelAlign;
7369             }
7370         }
7371         return 'left';
7372         
7373     },
7374     
7375     getAutoCreate : function(){
7376         
7377         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7378         
7379         var id = Roo.id();
7380         
7381         var cfg = {};
7382         
7383         if(this.inputType != 'hidden'){
7384             cfg.cls = 'form-group' //input-group
7385         }
7386         
7387         var input =  {
7388             tag: 'input',
7389             id : id,
7390             type : this.inputType,
7391             value : this.value,
7392             cls : 'form-control',
7393             placeholder : this.placeholder || '',
7394             autocomplete : this.autocomplete || 'new-password'
7395         };
7396         
7397         
7398         if(this.align){
7399             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7400         }
7401         
7402         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7403             input.maxLength = this.maxLength;
7404         }
7405         
7406         if (this.disabled) {
7407             input.disabled=true;
7408         }
7409         
7410         if (this.readOnly) {
7411             input.readonly=true;
7412         }
7413         
7414         if (this.name) {
7415             input.name = this.name;
7416         }
7417         if (this.size) {
7418             input.cls += ' input-' + this.size;
7419         }
7420         var settings=this;
7421         ['xs','sm','md','lg'].map(function(size){
7422             if (settings[size]) {
7423                 cfg.cls += ' col-' + size + '-' + settings[size];
7424             }
7425         });
7426         
7427         var inputblock = input;
7428         
7429         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7430             
7431             var feedback = {
7432                 tag: 'span',
7433                 cls: 'glyphicon form-control-feedback'
7434             };
7435
7436             inputblock = {
7437                 cls : 'has-feedback',
7438                 cn :  [
7439                     input,
7440                     feedback
7441                 ] 
7442             };  
7443         }
7444          
7445 //        var inputblock = input;
7446         
7447         if (this.before || this.after) {
7448             
7449             inputblock = {
7450                 cls : 'input-group',
7451                 cn :  [] 
7452             };
7453             
7454             if (this.before && typeof(this.before) == 'string') {
7455                 
7456                 inputblock.cn.push({
7457                     tag :'span',
7458                     cls : 'roo-input-before input-group-addon',
7459                     html : this.before
7460                 });
7461             }
7462             if (this.before && typeof(this.before) == 'object') {
7463                 this.before = Roo.factory(this.before);
7464                 Roo.log(this.before);
7465                 inputblock.cn.push({
7466                     tag :'span',
7467                     cls : 'roo-input-before input-group-' +
7468                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7469                 });
7470             }
7471             
7472             inputblock.cn.push(input);
7473             
7474             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7475                 inputblock.cls += ' has-feedback';
7476                 inputblock.cn.push(feedback);
7477             }
7478             
7479             if (this.after && typeof(this.after) == 'string') {
7480                 inputblock.cn.push({
7481                     tag :'span',
7482                     cls : 'roo-input-after input-group-addon',
7483                     html : this.after
7484                 });
7485             }
7486             if (this.after && typeof(this.after) == 'object') {
7487                 this.after = Roo.factory(this.after);
7488                 Roo.log(this.after);
7489                 inputblock.cn.push({
7490                     tag :'span',
7491                     cls : 'roo-input-after input-group-' +
7492                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7493                 });
7494             }
7495         };
7496         
7497         if (align ==='left' && this.fieldLabel.length) {
7498                 Roo.log("left and has label");
7499                 cfg.cn = [
7500                     
7501                     {
7502                         tag: 'label',
7503                         'for' :  id,
7504                         cls : 'control-label col-sm-' + this.labelWidth,
7505                         html : this.fieldLabel
7506                         
7507                     },
7508                     {
7509                         cls : "col-sm-" + (12 - this.labelWidth), 
7510                         cn: [
7511                             inputblock
7512                         ]
7513                     }
7514                     
7515                 ];
7516         } else if ( this.fieldLabel.length) {
7517                 Roo.log(" label");
7518                  cfg.cn = [
7519                    
7520                     {
7521                         tag: 'label',
7522                         //cls : 'input-group-addon',
7523                         html : this.fieldLabel
7524                         
7525                     },
7526                     
7527                     inputblock
7528                     
7529                 ];
7530
7531         } else {
7532             
7533                 Roo.log(" no label && no align");
7534                 cfg.cn = [
7535                     
7536                         inputblock
7537                     
7538                 ];
7539                 
7540                 
7541         };
7542         Roo.log('input-parentType: ' + this.parentType);
7543         
7544         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7545            cfg.cls += ' navbar-form';
7546            Roo.log(cfg);
7547         }
7548         
7549         return cfg;
7550         
7551     },
7552     /**
7553      * return the real input element.
7554      */
7555     inputEl: function ()
7556     {
7557         return this.el.select('input.form-control',true).first();
7558     },
7559     
7560     tooltipEl : function()
7561     {
7562         return this.inputEl();
7563     },
7564     
7565     setDisabled : function(v)
7566     {
7567         var i  = this.inputEl().dom;
7568         if (!v) {
7569             i.removeAttribute('disabled');
7570             return;
7571             
7572         }
7573         i.setAttribute('disabled','true');
7574     },
7575     initEvents : function()
7576     {
7577           
7578         this.inputEl().on("keydown" , this.fireKey,  this);
7579         this.inputEl().on("focus", this.onFocus,  this);
7580         this.inputEl().on("blur", this.onBlur,  this);
7581         
7582         this.inputEl().relayEvent('keyup', this);
7583
7584         // reference to original value for reset
7585         this.originalValue = this.getValue();
7586         //Roo.form.TextField.superclass.initEvents.call(this);
7587         if(this.validationEvent == 'keyup'){
7588             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7589             this.inputEl().on('keyup', this.filterValidation, this);
7590         }
7591         else if(this.validationEvent !== false){
7592             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7593         }
7594         
7595         if(this.selectOnFocus){
7596             this.on("focus", this.preFocus, this);
7597             
7598         }
7599         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7600             this.inputEl().on("keypress", this.filterKeys, this);
7601         }
7602        /* if(this.grow){
7603             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7604             this.el.on("click", this.autoSize,  this);
7605         }
7606         */
7607         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7608             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7609         }
7610         
7611         if (typeof(this.before) == 'object') {
7612             this.before.render(this.el.select('.roo-input-before',true).first());
7613         }
7614         if (typeof(this.after) == 'object') {
7615             this.after.render(this.el.select('.roo-input-after',true).first());
7616         }
7617         
7618         
7619     },
7620     filterValidation : function(e){
7621         if(!e.isNavKeyPress()){
7622             this.validationTask.delay(this.validationDelay);
7623         }
7624     },
7625      /**
7626      * Validates the field value
7627      * @return {Boolean} True if the value is valid, else false
7628      */
7629     validate : function(){
7630         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7631         if(this.disabled || this.validateValue(this.getRawValue())){
7632             this.markValid();
7633             return true;
7634         }
7635         
7636         this.markInvalid();
7637         return false;
7638     },
7639     
7640     
7641     /**
7642      * Validates a value according to the field's validation rules and marks the field as invalid
7643      * if the validation fails
7644      * @param {Mixed} value The value to validate
7645      * @return {Boolean} True if the value is valid, else false
7646      */
7647     validateValue : function(value){
7648         if(value.length < 1)  { // if it's blank
7649             if(this.allowBlank){
7650                 return true;
7651             }
7652             return false;
7653         }
7654         
7655         if(value.length < this.minLength){
7656             return false;
7657         }
7658         if(value.length > this.maxLength){
7659             return false;
7660         }
7661         if(this.vtype){
7662             var vt = Roo.form.VTypes;
7663             if(!vt[this.vtype](value, this)){
7664                 return false;
7665             }
7666         }
7667         if(typeof this.validator == "function"){
7668             var msg = this.validator(value);
7669             if(msg !== true){
7670                 return false;
7671             }
7672         }
7673         
7674         if(this.regex && !this.regex.test(value)){
7675             return false;
7676         }
7677         
7678         return true;
7679     },
7680
7681     
7682     
7683      // private
7684     fireKey : function(e){
7685         //Roo.log('field ' + e.getKey());
7686         if(e.isNavKeyPress()){
7687             this.fireEvent("specialkey", this, e);
7688         }
7689     },
7690     focus : function (selectText){
7691         if(this.rendered){
7692             this.inputEl().focus();
7693             if(selectText === true){
7694                 this.inputEl().dom.select();
7695             }
7696         }
7697         return this;
7698     } ,
7699     
7700     onFocus : function(){
7701         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7702            // this.el.addClass(this.focusClass);
7703         }
7704         if(!this.hasFocus){
7705             this.hasFocus = true;
7706             this.startValue = this.getValue();
7707             this.fireEvent("focus", this);
7708         }
7709     },
7710     
7711     beforeBlur : Roo.emptyFn,
7712
7713     
7714     // private
7715     onBlur : function(){
7716         this.beforeBlur();
7717         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7718             //this.el.removeClass(this.focusClass);
7719         }
7720         this.hasFocus = false;
7721         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7722             this.validate();
7723         }
7724         var v = this.getValue();
7725         if(String(v) !== String(this.startValue)){
7726             this.fireEvent('change', this, v, this.startValue);
7727         }
7728         this.fireEvent("blur", this);
7729     },
7730     
7731     /**
7732      * Resets the current field value to the originally loaded value and clears any validation messages
7733      */
7734     reset : function(){
7735         this.setValue(this.originalValue);
7736         this.validate();
7737     },
7738      /**
7739      * Returns the name of the field
7740      * @return {Mixed} name The name field
7741      */
7742     getName: function(){
7743         return this.name;
7744     },
7745      /**
7746      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7747      * @return {Mixed} value The field value
7748      */
7749     getValue : function(){
7750         
7751         var v = this.inputEl().getValue();
7752         
7753         return v;
7754     },
7755     /**
7756      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7757      * @return {Mixed} value The field value
7758      */
7759     getRawValue : function(){
7760         var v = this.inputEl().getValue();
7761         
7762         return v;
7763     },
7764     
7765     /**
7766      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7767      * @param {Mixed} value The value to set
7768      */
7769     setRawValue : function(v){
7770         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7771     },
7772     
7773     selectText : function(start, end){
7774         var v = this.getRawValue();
7775         if(v.length > 0){
7776             start = start === undefined ? 0 : start;
7777             end = end === undefined ? v.length : end;
7778             var d = this.inputEl().dom;
7779             if(d.setSelectionRange){
7780                 d.setSelectionRange(start, end);
7781             }else if(d.createTextRange){
7782                 var range = d.createTextRange();
7783                 range.moveStart("character", start);
7784                 range.moveEnd("character", v.length-end);
7785                 range.select();
7786             }
7787         }
7788     },
7789     
7790     /**
7791      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7792      * @param {Mixed} value The value to set
7793      */
7794     setValue : function(v){
7795         this.value = v;
7796         if(this.rendered){
7797             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7798             this.validate();
7799         }
7800     },
7801     
7802     /*
7803     processValue : function(value){
7804         if(this.stripCharsRe){
7805             var newValue = value.replace(this.stripCharsRe, '');
7806             if(newValue !== value){
7807                 this.setRawValue(newValue);
7808                 return newValue;
7809             }
7810         }
7811         return value;
7812     },
7813   */
7814     preFocus : function(){
7815         
7816         if(this.selectOnFocus){
7817             this.inputEl().dom.select();
7818         }
7819     },
7820     filterKeys : function(e){
7821         var k = e.getKey();
7822         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7823             return;
7824         }
7825         var c = e.getCharCode(), cc = String.fromCharCode(c);
7826         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7827             return;
7828         }
7829         if(!this.maskRe.test(cc)){
7830             e.stopEvent();
7831         }
7832     },
7833      /**
7834      * Clear any invalid styles/messages for this field
7835      */
7836     clearInvalid : function(){
7837         
7838         if(!this.el || this.preventMark){ // not rendered
7839             return;
7840         }
7841         this.el.removeClass(this.invalidClass);
7842         
7843         this.fireEvent('valid', this);
7844     },
7845     
7846      /**
7847      * Mark this field as valid
7848      */
7849     markValid : function(){
7850         if(!this.el  || this.preventMark){ // not rendered
7851             return;
7852         }
7853         
7854         this.el.removeClass([this.invalidClass, this.validClass]);
7855         
7856         if(this.disabled || this.allowBlank){
7857             return;
7858         }
7859         
7860         this.el.addClass(this.validClass);
7861         
7862         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7863             
7864             var feedback = this.el.select('.form-control-feedback', true).first();
7865             
7866             if(feedback){
7867                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7868                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7869             }
7870             
7871         }
7872         
7873         this.fireEvent('valid', this);
7874     },
7875     
7876      /**
7877      * Mark this field as invalid
7878      * @param {String} msg The validation message
7879      */
7880     markInvalid : function(msg){
7881         if(!this.el  || this.preventMark){ // not rendered
7882             return;
7883         }
7884         
7885         this.el.removeClass([this.invalidClass, this.validClass]);
7886         
7887         if(this.disabled || this.allowBlank){
7888             return;
7889         }
7890         
7891         this.el.addClass(this.invalidClass);
7892         
7893         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7894             
7895             var feedback = this.el.select('.form-control-feedback', true).first();
7896             
7897             if(feedback){
7898                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7899                 
7900                 if(this.getValue().length){
7901                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7902                 }
7903                 
7904             }
7905             
7906         }
7907         
7908         this.fireEvent('invalid', this, msg);
7909     },
7910     // private
7911     SafariOnKeyDown : function(event)
7912     {
7913         // this is a workaround for a password hang bug on chrome/ webkit.
7914         
7915         var isSelectAll = false;
7916         
7917         if(this.inputEl().dom.selectionEnd > 0){
7918             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7919         }
7920         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7921             event.preventDefault();
7922             this.setValue('');
7923             return;
7924         }
7925         
7926         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7927             
7928             event.preventDefault();
7929             // this is very hacky as keydown always get's upper case.
7930             //
7931             var cc = String.fromCharCode(event.getCharCode());
7932             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7933             
7934         }
7935     },
7936     adjustWidth : function(tag, w){
7937         tag = tag.toLowerCase();
7938         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7939             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7940                 if(tag == 'input'){
7941                     return w + 2;
7942                 }
7943                 if(tag == 'textarea'){
7944                     return w-2;
7945                 }
7946             }else if(Roo.isOpera){
7947                 if(tag == 'input'){
7948                     return w + 2;
7949                 }
7950                 if(tag == 'textarea'){
7951                     return w-2;
7952                 }
7953             }
7954         }
7955         return w;
7956     }
7957     
7958 });
7959
7960  
7961 /*
7962  * - LGPL
7963  *
7964  * Input
7965  * 
7966  */
7967
7968 /**
7969  * @class Roo.bootstrap.TextArea
7970  * @extends Roo.bootstrap.Input
7971  * Bootstrap TextArea class
7972  * @cfg {Number} cols Specifies the visible width of a text area
7973  * @cfg {Number} rows Specifies the visible number of lines in a text area
7974  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7975  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7976  * @cfg {string} html text
7977  * 
7978  * @constructor
7979  * Create a new TextArea
7980  * @param {Object} config The config object
7981  */
7982
7983 Roo.bootstrap.TextArea = function(config){
7984     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7985    
7986 };
7987
7988 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7989      
7990     cols : false,
7991     rows : 5,
7992     readOnly : false,
7993     warp : 'soft',
7994     resize : false,
7995     value: false,
7996     html: false,
7997     
7998     getAutoCreate : function(){
7999         
8000         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8001         
8002         var id = Roo.id();
8003         
8004         var cfg = {};
8005         
8006         var input =  {
8007             tag: 'textarea',
8008             id : id,
8009             warp : this.warp,
8010             rows : this.rows,
8011             value : this.value || '',
8012             html: this.html || '',
8013             cls : 'form-control',
8014             placeholder : this.placeholder || '' 
8015             
8016         };
8017         
8018         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8019             input.maxLength = this.maxLength;
8020         }
8021         
8022         if(this.resize){
8023             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8024         }
8025         
8026         if(this.cols){
8027             input.cols = this.cols;
8028         }
8029         
8030         if (this.readOnly) {
8031             input.readonly = true;
8032         }
8033         
8034         if (this.name) {
8035             input.name = this.name;
8036         }
8037         
8038         if (this.size) {
8039             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8040         }
8041         
8042         var settings=this;
8043         ['xs','sm','md','lg'].map(function(size){
8044             if (settings[size]) {
8045                 cfg.cls += ' col-' + size + '-' + settings[size];
8046             }
8047         });
8048         
8049         var inputblock = input;
8050         
8051         if(this.hasFeedback && !this.allowBlank){
8052             
8053             var feedback = {
8054                 tag: 'span',
8055                 cls: 'glyphicon form-control-feedback'
8056             };
8057
8058             inputblock = {
8059                 cls : 'has-feedback',
8060                 cn :  [
8061                     input,
8062                     feedback
8063                 ] 
8064             };  
8065         }
8066         
8067         
8068         if (this.before || this.after) {
8069             
8070             inputblock = {
8071                 cls : 'input-group',
8072                 cn :  [] 
8073             };
8074             if (this.before) {
8075                 inputblock.cn.push({
8076                     tag :'span',
8077                     cls : 'input-group-addon',
8078                     html : this.before
8079                 });
8080             }
8081             
8082             inputblock.cn.push(input);
8083             
8084             if(this.hasFeedback && !this.allowBlank){
8085                 inputblock.cls += ' has-feedback';
8086                 inputblock.cn.push(feedback);
8087             }
8088             
8089             if (this.after) {
8090                 inputblock.cn.push({
8091                     tag :'span',
8092                     cls : 'input-group-addon',
8093                     html : this.after
8094                 });
8095             }
8096             
8097         }
8098         
8099         if (align ==='left' && this.fieldLabel.length) {
8100                 Roo.log("left and has label");
8101                 cfg.cn = [
8102                     
8103                     {
8104                         tag: 'label',
8105                         'for' :  id,
8106                         cls : 'control-label col-sm-' + this.labelWidth,
8107                         html : this.fieldLabel
8108                         
8109                     },
8110                     {
8111                         cls : "col-sm-" + (12 - this.labelWidth), 
8112                         cn: [
8113                             inputblock
8114                         ]
8115                     }
8116                     
8117                 ];
8118         } else if ( this.fieldLabel.length) {
8119                 Roo.log(" label");
8120                  cfg.cn = [
8121                    
8122                     {
8123                         tag: 'label',
8124                         //cls : 'input-group-addon',
8125                         html : this.fieldLabel
8126                         
8127                     },
8128                     
8129                     inputblock
8130                     
8131                 ];
8132
8133         } else {
8134             
8135                    Roo.log(" no label && no align");
8136                 cfg.cn = [
8137                     
8138                         inputblock
8139                     
8140                 ];
8141                 
8142                 
8143         }
8144         
8145         if (this.disabled) {
8146             input.disabled=true;
8147         }
8148         
8149         return cfg;
8150         
8151     },
8152     /**
8153      * return the real textarea element.
8154      */
8155     inputEl: function ()
8156     {
8157         return this.el.select('textarea.form-control',true).first();
8158     }
8159 });
8160
8161  
8162 /*
8163  * - LGPL
8164  *
8165  * trigger field - base class for combo..
8166  * 
8167  */
8168  
8169 /**
8170  * @class Roo.bootstrap.TriggerField
8171  * @extends Roo.bootstrap.Input
8172  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8173  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8174  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8175  * for which you can provide a custom implementation.  For example:
8176  * <pre><code>
8177 var trigger = new Roo.bootstrap.TriggerField();
8178 trigger.onTriggerClick = myTriggerFn;
8179 trigger.applyTo('my-field');
8180 </code></pre>
8181  *
8182  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8183  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8184  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8185  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8186  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8187
8188  * @constructor
8189  * Create a new TriggerField.
8190  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8191  * to the base TextField)
8192  */
8193 Roo.bootstrap.TriggerField = function(config){
8194     this.mimicing = false;
8195     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8196 };
8197
8198 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8199     /**
8200      * @cfg {String} triggerClass A CSS class to apply to the trigger
8201      */
8202      /**
8203      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8204      */
8205     hideTrigger:false,
8206
8207     /** @cfg {Boolean} grow @hide */
8208     /** @cfg {Number} growMin @hide */
8209     /** @cfg {Number} growMax @hide */
8210
8211     /**
8212      * @hide 
8213      * @method
8214      */
8215     autoSize: Roo.emptyFn,
8216     // private
8217     monitorTab : true,
8218     // private
8219     deferHeight : true,
8220
8221     
8222     actionMode : 'wrap',
8223     
8224     caret : false,
8225     
8226     
8227     getAutoCreate : function(){
8228        
8229         var align = this.labelAlign || this.parentLabelAlign();
8230         
8231         var id = Roo.id();
8232         
8233         var cfg = {
8234             cls: 'form-group' //input-group
8235         };
8236         
8237         
8238         var input =  {
8239             tag: 'input',
8240             id : id,
8241             type : this.inputType,
8242             cls : 'form-control',
8243             autocomplete: 'new-password',
8244             placeholder : this.placeholder || '' 
8245             
8246         };
8247         if (this.name) {
8248             input.name = this.name;
8249         }
8250         if (this.size) {
8251             input.cls += ' input-' + this.size;
8252         }
8253         
8254         if (this.disabled) {
8255             input.disabled=true;
8256         }
8257         
8258         var inputblock = input;
8259         
8260         if(this.hasFeedback && !this.allowBlank){
8261             
8262             var feedback = {
8263                 tag: 'span',
8264                 cls: 'glyphicon form-control-feedback'
8265             };
8266
8267             inputblock = {
8268                 cls : 'has-feedback',
8269                 cn :  [
8270                     input,
8271                     feedback
8272                 ] 
8273             };  
8274         }
8275         
8276         if (this.before || this.after) {
8277             
8278             inputblock = {
8279                 cls : 'input-group',
8280                 cn :  [] 
8281             };
8282             if (this.before) {
8283                 inputblock.cn.push({
8284                     tag :'span',
8285                     cls : 'input-group-addon',
8286                     html : this.before
8287                 });
8288             }
8289             
8290             inputblock.cn.push(input);
8291             
8292             if(this.hasFeedback && !this.allowBlank){
8293                 inputblock.cls += ' has-feedback';
8294                 inputblock.cn.push(feedback);
8295             }
8296             
8297             if (this.after) {
8298                 inputblock.cn.push({
8299                     tag :'span',
8300                     cls : 'input-group-addon',
8301                     html : this.after
8302                 });
8303             }
8304             
8305         };
8306         
8307         var box = {
8308             tag: 'div',
8309             cn: [
8310                 {
8311                     tag: 'input',
8312                     type : 'hidden',
8313                     cls: 'form-hidden-field'
8314                 },
8315                 inputblock
8316             ]
8317             
8318         };
8319         
8320         if(this.multiple){
8321             Roo.log('multiple');
8322             
8323             box = {
8324                 tag: 'div',
8325                 cn: [
8326                     {
8327                         tag: 'input',
8328                         type : 'hidden',
8329                         cls: 'form-hidden-field'
8330                     },
8331                     {
8332                         tag: 'ul',
8333                         cls: 'select2-choices',
8334                         cn:[
8335                             {
8336                                 tag: 'li',
8337                                 cls: 'select2-search-field',
8338                                 cn: [
8339
8340                                     inputblock
8341                                 ]
8342                             }
8343                         ]
8344                     }
8345                 ]
8346             }
8347         };
8348         
8349         var combobox = {
8350             cls: 'select2-container input-group',
8351             cn: [
8352                 box
8353 //                {
8354 //                    tag: 'ul',
8355 //                    cls: 'typeahead typeahead-long dropdown-menu',
8356 //                    style: 'display:none'
8357 //                }
8358             ]
8359         };
8360         
8361         if(!this.multiple && this.showToggleBtn){
8362             
8363             var caret = {
8364                         tag: 'span',
8365                         cls: 'caret'
8366              };
8367             if (this.caret != false) {
8368                 caret = {
8369                      tag: 'i',
8370                      cls: 'fa fa-' + this.caret
8371                 };
8372                 
8373             }
8374             
8375             combobox.cn.push({
8376                 tag :'span',
8377                 cls : 'input-group-addon btn dropdown-toggle',
8378                 cn : [
8379                     caret,
8380                     {
8381                         tag: 'span',
8382                         cls: 'combobox-clear',
8383                         cn  : [
8384                             {
8385                                 tag : 'i',
8386                                 cls: 'icon-remove'
8387                             }
8388                         ]
8389                     }
8390                 ]
8391
8392             })
8393         }
8394         
8395         if(this.multiple){
8396             combobox.cls += ' select2-container-multi';
8397         }
8398         
8399         if (align ==='left' && this.fieldLabel.length) {
8400             
8401                 Roo.log("left and has label");
8402                 cfg.cn = [
8403                     
8404                     {
8405                         tag: 'label',
8406                         'for' :  id,
8407                         cls : 'control-label col-sm-' + this.labelWidth,
8408                         html : this.fieldLabel
8409                         
8410                     },
8411                     {
8412                         cls : "col-sm-" + (12 - this.labelWidth), 
8413                         cn: [
8414                             combobox
8415                         ]
8416                     }
8417                     
8418                 ];
8419         } else if ( this.fieldLabel.length) {
8420                 Roo.log(" label");
8421                  cfg.cn = [
8422                    
8423                     {
8424                         tag: 'label',
8425                         //cls : 'input-group-addon',
8426                         html : this.fieldLabel
8427                         
8428                     },
8429                     
8430                     combobox
8431                     
8432                 ];
8433
8434         } else {
8435             
8436                 Roo.log(" no label && no align");
8437                 cfg = combobox
8438                      
8439                 
8440         }
8441          
8442         var settings=this;
8443         ['xs','sm','md','lg'].map(function(size){
8444             if (settings[size]) {
8445                 cfg.cls += ' col-' + size + '-' + settings[size];
8446             }
8447         });
8448         
8449         return cfg;
8450         
8451     },
8452     
8453     
8454     
8455     // private
8456     onResize : function(w, h){
8457 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8458 //        if(typeof w == 'number'){
8459 //            var x = w - this.trigger.getWidth();
8460 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8461 //            this.trigger.setStyle('left', x+'px');
8462 //        }
8463     },
8464
8465     // private
8466     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8467
8468     // private
8469     getResizeEl : function(){
8470         return this.inputEl();
8471     },
8472
8473     // private
8474     getPositionEl : function(){
8475         return this.inputEl();
8476     },
8477
8478     // private
8479     alignErrorIcon : function(){
8480         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8481     },
8482
8483     // private
8484     initEvents : function(){
8485         
8486         this.createList();
8487         
8488         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8489         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8490         if(!this.multiple && this.showToggleBtn){
8491             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8492             if(this.hideTrigger){
8493                 this.trigger.setDisplayed(false);
8494             }
8495             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8496         }
8497         
8498         if(this.multiple){
8499             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8500         }
8501         
8502         //this.trigger.addClassOnOver('x-form-trigger-over');
8503         //this.trigger.addClassOnClick('x-form-trigger-click');
8504         
8505         //if(!this.width){
8506         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8507         //}
8508     },
8509     
8510     createList : function()
8511     {
8512         this.list = Roo.get(document.body).createChild({
8513             tag: 'ul',
8514             cls: 'typeahead typeahead-long dropdown-menu',
8515             style: 'display:none'
8516         });
8517         
8518         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8519         
8520     },
8521
8522     // private
8523     initTrigger : function(){
8524        
8525     },
8526
8527     // private
8528     onDestroy : function(){
8529         if(this.trigger){
8530             this.trigger.removeAllListeners();
8531           //  this.trigger.remove();
8532         }
8533         //if(this.wrap){
8534         //    this.wrap.remove();
8535         //}
8536         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8537     },
8538
8539     // private
8540     onFocus : function(){
8541         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8542         /*
8543         if(!this.mimicing){
8544             this.wrap.addClass('x-trigger-wrap-focus');
8545             this.mimicing = true;
8546             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8547             if(this.monitorTab){
8548                 this.el.on("keydown", this.checkTab, this);
8549             }
8550         }
8551         */
8552     },
8553
8554     // private
8555     checkTab : function(e){
8556         if(e.getKey() == e.TAB){
8557             this.triggerBlur();
8558         }
8559     },
8560
8561     // private
8562     onBlur : function(){
8563         // do nothing
8564     },
8565
8566     // private
8567     mimicBlur : function(e, t){
8568         /*
8569         if(!this.wrap.contains(t) && this.validateBlur()){
8570             this.triggerBlur();
8571         }
8572         */
8573     },
8574
8575     // private
8576     triggerBlur : function(){
8577         this.mimicing = false;
8578         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8579         if(this.monitorTab){
8580             this.el.un("keydown", this.checkTab, this);
8581         }
8582         //this.wrap.removeClass('x-trigger-wrap-focus');
8583         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8584     },
8585
8586     // private
8587     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8588     validateBlur : function(e, t){
8589         return true;
8590     },
8591
8592     // private
8593     onDisable : function(){
8594         this.inputEl().dom.disabled = true;
8595         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8596         //if(this.wrap){
8597         //    this.wrap.addClass('x-item-disabled');
8598         //}
8599     },
8600
8601     // private
8602     onEnable : function(){
8603         this.inputEl().dom.disabled = false;
8604         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8605         //if(this.wrap){
8606         //    this.el.removeClass('x-item-disabled');
8607         //}
8608     },
8609
8610     // private
8611     onShow : function(){
8612         var ae = this.getActionEl();
8613         
8614         if(ae){
8615             ae.dom.style.display = '';
8616             ae.dom.style.visibility = 'visible';
8617         }
8618     },
8619
8620     // private
8621     
8622     onHide : function(){
8623         var ae = this.getActionEl();
8624         ae.dom.style.display = 'none';
8625     },
8626
8627     /**
8628      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8629      * by an implementing function.
8630      * @method
8631      * @param {EventObject} e
8632      */
8633     onTriggerClick : Roo.emptyFn
8634 });
8635  /*
8636  * Based on:
8637  * Ext JS Library 1.1.1
8638  * Copyright(c) 2006-2007, Ext JS, LLC.
8639  *
8640  * Originally Released Under LGPL - original licence link has changed is not relivant.
8641  *
8642  * Fork - LGPL
8643  * <script type="text/javascript">
8644  */
8645
8646
8647 /**
8648  * @class Roo.data.SortTypes
8649  * @singleton
8650  * Defines the default sorting (casting?) comparison functions used when sorting data.
8651  */
8652 Roo.data.SortTypes = {
8653     /**
8654      * Default sort that does nothing
8655      * @param {Mixed} s The value being converted
8656      * @return {Mixed} The comparison value
8657      */
8658     none : function(s){
8659         return s;
8660     },
8661     
8662     /**
8663      * The regular expression used to strip tags
8664      * @type {RegExp}
8665      * @property
8666      */
8667     stripTagsRE : /<\/?[^>]+>/gi,
8668     
8669     /**
8670      * Strips all HTML tags to sort on text only
8671      * @param {Mixed} s The value being converted
8672      * @return {String} The comparison value
8673      */
8674     asText : function(s){
8675         return String(s).replace(this.stripTagsRE, "");
8676     },
8677     
8678     /**
8679      * Strips all HTML tags to sort on text only - Case insensitive
8680      * @param {Mixed} s The value being converted
8681      * @return {String} The comparison value
8682      */
8683     asUCText : function(s){
8684         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8685     },
8686     
8687     /**
8688      * Case insensitive string
8689      * @param {Mixed} s The value being converted
8690      * @return {String} The comparison value
8691      */
8692     asUCString : function(s) {
8693         return String(s).toUpperCase();
8694     },
8695     
8696     /**
8697      * Date sorting
8698      * @param {Mixed} s The value being converted
8699      * @return {Number} The comparison value
8700      */
8701     asDate : function(s) {
8702         if(!s){
8703             return 0;
8704         }
8705         if(s instanceof Date){
8706             return s.getTime();
8707         }
8708         return Date.parse(String(s));
8709     },
8710     
8711     /**
8712      * Float sorting
8713      * @param {Mixed} s The value being converted
8714      * @return {Float} The comparison value
8715      */
8716     asFloat : function(s) {
8717         var val = parseFloat(String(s).replace(/,/g, ""));
8718         if(isNaN(val)) val = 0;
8719         return val;
8720     },
8721     
8722     /**
8723      * Integer sorting
8724      * @param {Mixed} s The value being converted
8725      * @return {Number} The comparison value
8726      */
8727     asInt : function(s) {
8728         var val = parseInt(String(s).replace(/,/g, ""));
8729         if(isNaN(val)) val = 0;
8730         return val;
8731     }
8732 };/*
8733  * Based on:
8734  * Ext JS Library 1.1.1
8735  * Copyright(c) 2006-2007, Ext JS, LLC.
8736  *
8737  * Originally Released Under LGPL - original licence link has changed is not relivant.
8738  *
8739  * Fork - LGPL
8740  * <script type="text/javascript">
8741  */
8742
8743 /**
8744 * @class Roo.data.Record
8745  * Instances of this class encapsulate both record <em>definition</em> information, and record
8746  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8747  * to access Records cached in an {@link Roo.data.Store} object.<br>
8748  * <p>
8749  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8750  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8751  * objects.<br>
8752  * <p>
8753  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8754  * @constructor
8755  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8756  * {@link #create}. The parameters are the same.
8757  * @param {Array} data An associative Array of data values keyed by the field name.
8758  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8759  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8760  * not specified an integer id is generated.
8761  */
8762 Roo.data.Record = function(data, id){
8763     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8764     this.data = data;
8765 };
8766
8767 /**
8768  * Generate a constructor for a specific record layout.
8769  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8770  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8771  * Each field definition object may contain the following properties: <ul>
8772  * <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,
8773  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8774  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8775  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8776  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8777  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8778  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8779  * this may be omitted.</p></li>
8780  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8781  * <ul><li>auto (Default, implies no conversion)</li>
8782  * <li>string</li>
8783  * <li>int</li>
8784  * <li>float</li>
8785  * <li>boolean</li>
8786  * <li>date</li></ul></p></li>
8787  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8788  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8789  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8790  * by the Reader into an object that will be stored in the Record. It is passed the
8791  * following parameters:<ul>
8792  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8793  * </ul></p></li>
8794  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8795  * </ul>
8796  * <br>usage:<br><pre><code>
8797 var TopicRecord = Roo.data.Record.create(
8798     {name: 'title', mapping: 'topic_title'},
8799     {name: 'author', mapping: 'username'},
8800     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8801     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8802     {name: 'lastPoster', mapping: 'user2'},
8803     {name: 'excerpt', mapping: 'post_text'}
8804 );
8805
8806 var myNewRecord = new TopicRecord({
8807     title: 'Do my job please',
8808     author: 'noobie',
8809     totalPosts: 1,
8810     lastPost: new Date(),
8811     lastPoster: 'Animal',
8812     excerpt: 'No way dude!'
8813 });
8814 myStore.add(myNewRecord);
8815 </code></pre>
8816  * @method create
8817  * @static
8818  */
8819 Roo.data.Record.create = function(o){
8820     var f = function(){
8821         f.superclass.constructor.apply(this, arguments);
8822     };
8823     Roo.extend(f, Roo.data.Record);
8824     var p = f.prototype;
8825     p.fields = new Roo.util.MixedCollection(false, function(field){
8826         return field.name;
8827     });
8828     for(var i = 0, len = o.length; i < len; i++){
8829         p.fields.add(new Roo.data.Field(o[i]));
8830     }
8831     f.getField = function(name){
8832         return p.fields.get(name);  
8833     };
8834     return f;
8835 };
8836
8837 Roo.data.Record.AUTO_ID = 1000;
8838 Roo.data.Record.EDIT = 'edit';
8839 Roo.data.Record.REJECT = 'reject';
8840 Roo.data.Record.COMMIT = 'commit';
8841
8842 Roo.data.Record.prototype = {
8843     /**
8844      * Readonly flag - true if this record has been modified.
8845      * @type Boolean
8846      */
8847     dirty : false,
8848     editing : false,
8849     error: null,
8850     modified: null,
8851
8852     // private
8853     join : function(store){
8854         this.store = store;
8855     },
8856
8857     /**
8858      * Set the named field to the specified value.
8859      * @param {String} name The name of the field to set.
8860      * @param {Object} value The value to set the field to.
8861      */
8862     set : function(name, value){
8863         if(this.data[name] == value){
8864             return;
8865         }
8866         this.dirty = true;
8867         if(!this.modified){
8868             this.modified = {};
8869         }
8870         if(typeof this.modified[name] == 'undefined'){
8871             this.modified[name] = this.data[name];
8872         }
8873         this.data[name] = value;
8874         if(!this.editing && this.store){
8875             this.store.afterEdit(this);
8876         }       
8877     },
8878
8879     /**
8880      * Get the value of the named field.
8881      * @param {String} name The name of the field to get the value of.
8882      * @return {Object} The value of the field.
8883      */
8884     get : function(name){
8885         return this.data[name]; 
8886     },
8887
8888     // private
8889     beginEdit : function(){
8890         this.editing = true;
8891         this.modified = {}; 
8892     },
8893
8894     // private
8895     cancelEdit : function(){
8896         this.editing = false;
8897         delete this.modified;
8898     },
8899
8900     // private
8901     endEdit : function(){
8902         this.editing = false;
8903         if(this.dirty && this.store){
8904             this.store.afterEdit(this);
8905         }
8906     },
8907
8908     /**
8909      * Usually called by the {@link Roo.data.Store} which owns the Record.
8910      * Rejects all changes made to the Record since either creation, or the last commit operation.
8911      * Modified fields are reverted to their original values.
8912      * <p>
8913      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8914      * of reject operations.
8915      */
8916     reject : function(){
8917         var m = this.modified;
8918         for(var n in m){
8919             if(typeof m[n] != "function"){
8920                 this.data[n] = m[n];
8921             }
8922         }
8923         this.dirty = false;
8924         delete this.modified;
8925         this.editing = false;
8926         if(this.store){
8927             this.store.afterReject(this);
8928         }
8929     },
8930
8931     /**
8932      * Usually called by the {@link Roo.data.Store} which owns the Record.
8933      * Commits all changes made to the Record since either creation, or the last commit operation.
8934      * <p>
8935      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8936      * of commit operations.
8937      */
8938     commit : function(){
8939         this.dirty = false;
8940         delete this.modified;
8941         this.editing = false;
8942         if(this.store){
8943             this.store.afterCommit(this);
8944         }
8945     },
8946
8947     // private
8948     hasError : function(){
8949         return this.error != null;
8950     },
8951
8952     // private
8953     clearError : function(){
8954         this.error = null;
8955     },
8956
8957     /**
8958      * Creates a copy of this record.
8959      * @param {String} id (optional) A new record id if you don't want to use this record's id
8960      * @return {Record}
8961      */
8962     copy : function(newId) {
8963         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8964     }
8965 };/*
8966  * Based on:
8967  * Ext JS Library 1.1.1
8968  * Copyright(c) 2006-2007, Ext JS, LLC.
8969  *
8970  * Originally Released Under LGPL - original licence link has changed is not relivant.
8971  *
8972  * Fork - LGPL
8973  * <script type="text/javascript">
8974  */
8975
8976
8977
8978 /**
8979  * @class Roo.data.Store
8980  * @extends Roo.util.Observable
8981  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8982  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8983  * <p>
8984  * 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
8985  * has no knowledge of the format of the data returned by the Proxy.<br>
8986  * <p>
8987  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8988  * instances from the data object. These records are cached and made available through accessor functions.
8989  * @constructor
8990  * Creates a new Store.
8991  * @param {Object} config A config object containing the objects needed for the Store to access data,
8992  * and read the data into Records.
8993  */
8994 Roo.data.Store = function(config){
8995     this.data = new Roo.util.MixedCollection(false);
8996     this.data.getKey = function(o){
8997         return o.id;
8998     };
8999     this.baseParams = {};
9000     // private
9001     this.paramNames = {
9002         "start" : "start",
9003         "limit" : "limit",
9004         "sort" : "sort",
9005         "dir" : "dir",
9006         "multisort" : "_multisort"
9007     };
9008
9009     if(config && config.data){
9010         this.inlineData = config.data;
9011         delete config.data;
9012     }
9013
9014     Roo.apply(this, config);
9015     
9016     if(this.reader){ // reader passed
9017         this.reader = Roo.factory(this.reader, Roo.data);
9018         this.reader.xmodule = this.xmodule || false;
9019         if(!this.recordType){
9020             this.recordType = this.reader.recordType;
9021         }
9022         if(this.reader.onMetaChange){
9023             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9024         }
9025     }
9026
9027     if(this.recordType){
9028         this.fields = this.recordType.prototype.fields;
9029     }
9030     this.modified = [];
9031
9032     this.addEvents({
9033         /**
9034          * @event datachanged
9035          * Fires when the data cache has changed, and a widget which is using this Store
9036          * as a Record cache should refresh its view.
9037          * @param {Store} this
9038          */
9039         datachanged : true,
9040         /**
9041          * @event metachange
9042          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9043          * @param {Store} this
9044          * @param {Object} meta The JSON metadata
9045          */
9046         metachange : true,
9047         /**
9048          * @event add
9049          * Fires when Records have been added to the Store
9050          * @param {Store} this
9051          * @param {Roo.data.Record[]} records The array of Records added
9052          * @param {Number} index The index at which the record(s) were added
9053          */
9054         add : true,
9055         /**
9056          * @event remove
9057          * Fires when a Record has been removed from the Store
9058          * @param {Store} this
9059          * @param {Roo.data.Record} record The Record that was removed
9060          * @param {Number} index The index at which the record was removed
9061          */
9062         remove : true,
9063         /**
9064          * @event update
9065          * Fires when a Record has been updated
9066          * @param {Store} this
9067          * @param {Roo.data.Record} record The Record that was updated
9068          * @param {String} operation The update operation being performed.  Value may be one of:
9069          * <pre><code>
9070  Roo.data.Record.EDIT
9071  Roo.data.Record.REJECT
9072  Roo.data.Record.COMMIT
9073          * </code></pre>
9074          */
9075         update : true,
9076         /**
9077          * @event clear
9078          * Fires when the data cache has been cleared.
9079          * @param {Store} this
9080          */
9081         clear : true,
9082         /**
9083          * @event beforeload
9084          * Fires before a request is made for a new data object.  If the beforeload handler returns false
9085          * the load action will be canceled.
9086          * @param {Store} this
9087          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9088          */
9089         beforeload : true,
9090         /**
9091          * @event beforeloadadd
9092          * Fires after a new set of Records has been loaded.
9093          * @param {Store} this
9094          * @param {Roo.data.Record[]} records The Records that were loaded
9095          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9096          */
9097         beforeloadadd : true,
9098         /**
9099          * @event load
9100          * Fires after a new set of Records has been loaded, before they are added to the store.
9101          * @param {Store} this
9102          * @param {Roo.data.Record[]} records The Records that were loaded
9103          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9104          * @params {Object} return from reader
9105          */
9106         load : true,
9107         /**
9108          * @event loadexception
9109          * Fires if an exception occurs in the Proxy during loading.
9110          * Called with the signature of the Proxy's "loadexception" event.
9111          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9112          * 
9113          * @param {Proxy} 
9114          * @param {Object} return from JsonData.reader() - success, totalRecords, records
9115          * @param {Object} load options 
9116          * @param {Object} jsonData from your request (normally this contains the Exception)
9117          */
9118         loadexception : true
9119     });
9120     
9121     if(this.proxy){
9122         this.proxy = Roo.factory(this.proxy, Roo.data);
9123         this.proxy.xmodule = this.xmodule || false;
9124         this.relayEvents(this.proxy,  ["loadexception"]);
9125     }
9126     this.sortToggle = {};
9127     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9128
9129     Roo.data.Store.superclass.constructor.call(this);
9130
9131     if(this.inlineData){
9132         this.loadData(this.inlineData);
9133         delete this.inlineData;
9134     }
9135 };
9136
9137 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9138      /**
9139     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9140     * without a remote query - used by combo/forms at present.
9141     */
9142     
9143     /**
9144     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9145     */
9146     /**
9147     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9148     */
9149     /**
9150     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9151     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9152     */
9153     /**
9154     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9155     * on any HTTP request
9156     */
9157     /**
9158     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9159     */
9160     /**
9161     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9162     */
9163     multiSort: false,
9164     /**
9165     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9166     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9167     */
9168     remoteSort : false,
9169
9170     /**
9171     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9172      * loaded or when a record is removed. (defaults to false).
9173     */
9174     pruneModifiedRecords : false,
9175
9176     // private
9177     lastOptions : null,
9178
9179     /**
9180      * Add Records to the Store and fires the add event.
9181      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9182      */
9183     add : function(records){
9184         records = [].concat(records);
9185         for(var i = 0, len = records.length; i < len; i++){
9186             records[i].join(this);
9187         }
9188         var index = this.data.length;
9189         this.data.addAll(records);
9190         this.fireEvent("add", this, records, index);
9191     },
9192
9193     /**
9194      * Remove a Record from the Store and fires the remove event.
9195      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9196      */
9197     remove : function(record){
9198         var index = this.data.indexOf(record);
9199         this.data.removeAt(index);
9200         if(this.pruneModifiedRecords){
9201             this.modified.remove(record);
9202         }
9203         this.fireEvent("remove", this, record, index);
9204     },
9205
9206     /**
9207      * Remove all Records from the Store and fires the clear event.
9208      */
9209     removeAll : function(){
9210         this.data.clear();
9211         if(this.pruneModifiedRecords){
9212             this.modified = [];
9213         }
9214         this.fireEvent("clear", this);
9215     },
9216
9217     /**
9218      * Inserts Records to the Store at the given index and fires the add event.
9219      * @param {Number} index The start index at which to insert the passed Records.
9220      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9221      */
9222     insert : function(index, records){
9223         records = [].concat(records);
9224         for(var i = 0, len = records.length; i < len; i++){
9225             this.data.insert(index, records[i]);
9226             records[i].join(this);
9227         }
9228         this.fireEvent("add", this, records, index);
9229     },
9230
9231     /**
9232      * Get the index within the cache of the passed Record.
9233      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9234      * @return {Number} The index of the passed Record. Returns -1 if not found.
9235      */
9236     indexOf : function(record){
9237         return this.data.indexOf(record);
9238     },
9239
9240     /**
9241      * Get the index within the cache of the Record with the passed id.
9242      * @param {String} id The id of the Record to find.
9243      * @return {Number} The index of the Record. Returns -1 if not found.
9244      */
9245     indexOfId : function(id){
9246         return this.data.indexOfKey(id);
9247     },
9248
9249     /**
9250      * Get the Record with the specified id.
9251      * @param {String} id The id of the Record to find.
9252      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9253      */
9254     getById : function(id){
9255         return this.data.key(id);
9256     },
9257
9258     /**
9259      * Get the Record at the specified index.
9260      * @param {Number} index The index of the Record to find.
9261      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9262      */
9263     getAt : function(index){
9264         return this.data.itemAt(index);
9265     },
9266
9267     /**
9268      * Returns a range of Records between specified indices.
9269      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9270      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9271      * @return {Roo.data.Record[]} An array of Records
9272      */
9273     getRange : function(start, end){
9274         return this.data.getRange(start, end);
9275     },
9276
9277     // private
9278     storeOptions : function(o){
9279         o = Roo.apply({}, o);
9280         delete o.callback;
9281         delete o.scope;
9282         this.lastOptions = o;
9283     },
9284
9285     /**
9286      * Loads the Record cache from the configured Proxy using the configured Reader.
9287      * <p>
9288      * If using remote paging, then the first load call must specify the <em>start</em>
9289      * and <em>limit</em> properties in the options.params property to establish the initial
9290      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9291      * <p>
9292      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9293      * and this call will return before the new data has been loaded. Perform any post-processing
9294      * in a callback function, or in a "load" event handler.</strong>
9295      * <p>
9296      * @param {Object} options An object containing properties which control loading options:<ul>
9297      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9298      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9299      * passed the following arguments:<ul>
9300      * <li>r : Roo.data.Record[]</li>
9301      * <li>options: Options object from the load call</li>
9302      * <li>success: Boolean success indicator</li></ul></li>
9303      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9304      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9305      * </ul>
9306      */
9307     load : function(options){
9308         options = options || {};
9309         if(this.fireEvent("beforeload", this, options) !== false){
9310             this.storeOptions(options);
9311             var p = Roo.apply(options.params || {}, this.baseParams);
9312             // if meta was not loaded from remote source.. try requesting it.
9313             if (!this.reader.metaFromRemote) {
9314                 p._requestMeta = 1;
9315             }
9316             if(this.sortInfo && this.remoteSort){
9317                 var pn = this.paramNames;
9318                 p[pn["sort"]] = this.sortInfo.field;
9319                 p[pn["dir"]] = this.sortInfo.direction;
9320             }
9321             if (this.multiSort) {
9322                 var pn = this.paramNames;
9323                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9324             }
9325             
9326             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9327         }
9328     },
9329
9330     /**
9331      * Reloads the Record cache from the configured Proxy using the configured Reader and
9332      * the options from the last load operation performed.
9333      * @param {Object} options (optional) An object containing properties which may override the options
9334      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9335      * the most recently used options are reused).
9336      */
9337     reload : function(options){
9338         this.load(Roo.applyIf(options||{}, this.lastOptions));
9339     },
9340
9341     // private
9342     // Called as a callback by the Reader during a load operation.
9343     loadRecords : function(o, options, success){
9344         if(!o || success === false){
9345             if(success !== false){
9346                 this.fireEvent("load", this, [], options, o);
9347             }
9348             if(options.callback){
9349                 options.callback.call(options.scope || this, [], options, false);
9350             }
9351             return;
9352         }
9353         // if data returned failure - throw an exception.
9354         if (o.success === false) {
9355             // show a message if no listener is registered.
9356             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9357                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9358             }
9359             // loadmask wil be hooked into this..
9360             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9361             return;
9362         }
9363         var r = o.records, t = o.totalRecords || r.length;
9364         
9365         this.fireEvent("beforeloadadd", this, r, options, o);
9366         
9367         if(!options || options.add !== true){
9368             if(this.pruneModifiedRecords){
9369                 this.modified = [];
9370             }
9371             for(var i = 0, len = r.length; i < len; i++){
9372                 r[i].join(this);
9373             }
9374             if(this.snapshot){
9375                 this.data = this.snapshot;
9376                 delete this.snapshot;
9377             }
9378             this.data.clear();
9379             this.data.addAll(r);
9380             this.totalLength = t;
9381             this.applySort();
9382             this.fireEvent("datachanged", this);
9383         }else{
9384             this.totalLength = Math.max(t, this.data.length+r.length);
9385             this.add(r);
9386         }
9387         this.fireEvent("load", this, r, options, o);
9388         if(options.callback){
9389             options.callback.call(options.scope || this, r, options, true);
9390         }
9391     },
9392
9393
9394     /**
9395      * Loads data from a passed data block. A Reader which understands the format of the data
9396      * must have been configured in the constructor.
9397      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9398      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9399      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9400      */
9401     loadData : function(o, append){
9402         var r = this.reader.readRecords(o);
9403         this.loadRecords(r, {add: append}, true);
9404     },
9405
9406     /**
9407      * Gets the number of cached records.
9408      * <p>
9409      * <em>If using paging, this may not be the total size of the dataset. If the data object
9410      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9411      * the data set size</em>
9412      */
9413     getCount : function(){
9414         return this.data.length || 0;
9415     },
9416
9417     /**
9418      * Gets the total number of records in the dataset as returned by the server.
9419      * <p>
9420      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9421      * the dataset size</em>
9422      */
9423     getTotalCount : function(){
9424         return this.totalLength || 0;
9425     },
9426
9427     /**
9428      * Returns the sort state of the Store as an object with two properties:
9429      * <pre><code>
9430  field {String} The name of the field by which the Records are sorted
9431  direction {String} The sort order, "ASC" or "DESC"
9432      * </code></pre>
9433      */
9434     getSortState : function(){
9435         return this.sortInfo;
9436     },
9437
9438     // private
9439     applySort : function(){
9440         if(this.sortInfo && !this.remoteSort){
9441             var s = this.sortInfo, f = s.field;
9442             var st = this.fields.get(f).sortType;
9443             var fn = function(r1, r2){
9444                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9445                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9446             };
9447             this.data.sort(s.direction, fn);
9448             if(this.snapshot && this.snapshot != this.data){
9449                 this.snapshot.sort(s.direction, fn);
9450             }
9451         }
9452     },
9453
9454     /**
9455      * Sets the default sort column and order to be used by the next load operation.
9456      * @param {String} fieldName The name of the field to sort by.
9457      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9458      */
9459     setDefaultSort : function(field, dir){
9460         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9461     },
9462
9463     /**
9464      * Sort the Records.
9465      * If remote sorting is used, the sort is performed on the server, and the cache is
9466      * reloaded. If local sorting is used, the cache is sorted internally.
9467      * @param {String} fieldName The name of the field to sort by.
9468      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9469      */
9470     sort : function(fieldName, dir){
9471         var f = this.fields.get(fieldName);
9472         if(!dir){
9473             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9474             
9475             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9476                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9477             }else{
9478                 dir = f.sortDir;
9479             }
9480         }
9481         this.sortToggle[f.name] = dir;
9482         this.sortInfo = {field: f.name, direction: dir};
9483         if(!this.remoteSort){
9484             this.applySort();
9485             this.fireEvent("datachanged", this);
9486         }else{
9487             this.load(this.lastOptions);
9488         }
9489     },
9490
9491     /**
9492      * Calls the specified function for each of the Records in the cache.
9493      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9494      * Returning <em>false</em> aborts and exits the iteration.
9495      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9496      */
9497     each : function(fn, scope){
9498         this.data.each(fn, scope);
9499     },
9500
9501     /**
9502      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9503      * (e.g., during paging).
9504      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9505      */
9506     getModifiedRecords : function(){
9507         return this.modified;
9508     },
9509
9510     // private
9511     createFilterFn : function(property, value, anyMatch){
9512         if(!value.exec){ // not a regex
9513             value = String(value);
9514             if(value.length == 0){
9515                 return false;
9516             }
9517             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9518         }
9519         return function(r){
9520             return value.test(r.data[property]);
9521         };
9522     },
9523
9524     /**
9525      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9526      * @param {String} property A field on your records
9527      * @param {Number} start The record index to start at (defaults to 0)
9528      * @param {Number} end The last record index to include (defaults to length - 1)
9529      * @return {Number} The sum
9530      */
9531     sum : function(property, start, end){
9532         var rs = this.data.items, v = 0;
9533         start = start || 0;
9534         end = (end || end === 0) ? end : rs.length-1;
9535
9536         for(var i = start; i <= end; i++){
9537             v += (rs[i].data[property] || 0);
9538         }
9539         return v;
9540     },
9541
9542     /**
9543      * Filter the records by a specified property.
9544      * @param {String} field A field on your records
9545      * @param {String/RegExp} value Either a string that the field
9546      * should start with or a RegExp to test against the field
9547      * @param {Boolean} anyMatch True to match any part not just the beginning
9548      */
9549     filter : function(property, value, anyMatch){
9550         var fn = this.createFilterFn(property, value, anyMatch);
9551         return fn ? this.filterBy(fn) : this.clearFilter();
9552     },
9553
9554     /**
9555      * Filter by a function. The specified function will be called with each
9556      * record in this data source. If the function returns true the record is included,
9557      * otherwise it is filtered.
9558      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9559      * @param {Object} scope (optional) The scope of the function (defaults to this)
9560      */
9561     filterBy : function(fn, scope){
9562         this.snapshot = this.snapshot || this.data;
9563         this.data = this.queryBy(fn, scope||this);
9564         this.fireEvent("datachanged", this);
9565     },
9566
9567     /**
9568      * Query the records by a specified property.
9569      * @param {String} field A field on your records
9570      * @param {String/RegExp} value Either a string that the field
9571      * should start with or a RegExp to test against the field
9572      * @param {Boolean} anyMatch True to match any part not just the beginning
9573      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9574      */
9575     query : function(property, value, anyMatch){
9576         var fn = this.createFilterFn(property, value, anyMatch);
9577         return fn ? this.queryBy(fn) : this.data.clone();
9578     },
9579
9580     /**
9581      * Query by a function. The specified function will be called with each
9582      * record in this data source. If the function returns true the record is included
9583      * in the results.
9584      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9585      * @param {Object} scope (optional) The scope of the function (defaults to this)
9586       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9587      **/
9588     queryBy : function(fn, scope){
9589         var data = this.snapshot || this.data;
9590         return data.filterBy(fn, scope||this);
9591     },
9592
9593     /**
9594      * Collects unique values for a particular dataIndex from this store.
9595      * @param {String} dataIndex The property to collect
9596      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9597      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9598      * @return {Array} An array of the unique values
9599      **/
9600     collect : function(dataIndex, allowNull, bypassFilter){
9601         var d = (bypassFilter === true && this.snapshot) ?
9602                 this.snapshot.items : this.data.items;
9603         var v, sv, r = [], l = {};
9604         for(var i = 0, len = d.length; i < len; i++){
9605             v = d[i].data[dataIndex];
9606             sv = String(v);
9607             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9608                 l[sv] = true;
9609                 r[r.length] = v;
9610             }
9611         }
9612         return r;
9613     },
9614
9615     /**
9616      * Revert to a view of the Record cache with no filtering applied.
9617      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9618      */
9619     clearFilter : function(suppressEvent){
9620         if(this.snapshot && this.snapshot != this.data){
9621             this.data = this.snapshot;
9622             delete this.snapshot;
9623             if(suppressEvent !== true){
9624                 this.fireEvent("datachanged", this);
9625             }
9626         }
9627     },
9628
9629     // private
9630     afterEdit : function(record){
9631         if(this.modified.indexOf(record) == -1){
9632             this.modified.push(record);
9633         }
9634         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9635     },
9636     
9637     // private
9638     afterReject : function(record){
9639         this.modified.remove(record);
9640         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9641     },
9642
9643     // private
9644     afterCommit : function(record){
9645         this.modified.remove(record);
9646         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9647     },
9648
9649     /**
9650      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9651      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9652      */
9653     commitChanges : function(){
9654         var m = this.modified.slice(0);
9655         this.modified = [];
9656         for(var i = 0, len = m.length; i < len; i++){
9657             m[i].commit();
9658         }
9659     },
9660
9661     /**
9662      * Cancel outstanding changes on all changed records.
9663      */
9664     rejectChanges : function(){
9665         var m = this.modified.slice(0);
9666         this.modified = [];
9667         for(var i = 0, len = m.length; i < len; i++){
9668             m[i].reject();
9669         }
9670     },
9671
9672     onMetaChange : function(meta, rtype, o){
9673         this.recordType = rtype;
9674         this.fields = rtype.prototype.fields;
9675         delete this.snapshot;
9676         this.sortInfo = meta.sortInfo || this.sortInfo;
9677         this.modified = [];
9678         this.fireEvent('metachange', this, this.reader.meta);
9679     },
9680     
9681     moveIndex : function(data, type)
9682     {
9683         var index = this.indexOf(data);
9684         
9685         var newIndex = index + type;
9686         
9687         this.remove(data);
9688         
9689         this.insert(newIndex, data);
9690         
9691     }
9692 });/*
9693  * Based on:
9694  * Ext JS Library 1.1.1
9695  * Copyright(c) 2006-2007, Ext JS, LLC.
9696  *
9697  * Originally Released Under LGPL - original licence link has changed is not relivant.
9698  *
9699  * Fork - LGPL
9700  * <script type="text/javascript">
9701  */
9702
9703 /**
9704  * @class Roo.data.SimpleStore
9705  * @extends Roo.data.Store
9706  * Small helper class to make creating Stores from Array data easier.
9707  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9708  * @cfg {Array} fields An array of field definition objects, or field name strings.
9709  * @cfg {Array} data The multi-dimensional array of data
9710  * @constructor
9711  * @param {Object} config
9712  */
9713 Roo.data.SimpleStore = function(config){
9714     Roo.data.SimpleStore.superclass.constructor.call(this, {
9715         isLocal : true,
9716         reader: new Roo.data.ArrayReader({
9717                 id: config.id
9718             },
9719             Roo.data.Record.create(config.fields)
9720         ),
9721         proxy : new Roo.data.MemoryProxy(config.data)
9722     });
9723     this.load();
9724 };
9725 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9726  * Based on:
9727  * Ext JS Library 1.1.1
9728  * Copyright(c) 2006-2007, Ext JS, LLC.
9729  *
9730  * Originally Released Under LGPL - original licence link has changed is not relivant.
9731  *
9732  * Fork - LGPL
9733  * <script type="text/javascript">
9734  */
9735
9736 /**
9737 /**
9738  * @extends Roo.data.Store
9739  * @class Roo.data.JsonStore
9740  * Small helper class to make creating Stores for JSON data easier. <br/>
9741 <pre><code>
9742 var store = new Roo.data.JsonStore({
9743     url: 'get-images.php',
9744     root: 'images',
9745     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9746 });
9747 </code></pre>
9748  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9749  * JsonReader and HttpProxy (unless inline data is provided).</b>
9750  * @cfg {Array} fields An array of field definition objects, or field name strings.
9751  * @constructor
9752  * @param {Object} config
9753  */
9754 Roo.data.JsonStore = function(c){
9755     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9756         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9757         reader: new Roo.data.JsonReader(c, c.fields)
9758     }));
9759 };
9760 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9761  * Based on:
9762  * Ext JS Library 1.1.1
9763  * Copyright(c) 2006-2007, Ext JS, LLC.
9764  *
9765  * Originally Released Under LGPL - original licence link has changed is not relivant.
9766  *
9767  * Fork - LGPL
9768  * <script type="text/javascript">
9769  */
9770
9771  
9772 Roo.data.Field = function(config){
9773     if(typeof config == "string"){
9774         config = {name: config};
9775     }
9776     Roo.apply(this, config);
9777     
9778     if(!this.type){
9779         this.type = "auto";
9780     }
9781     
9782     var st = Roo.data.SortTypes;
9783     // named sortTypes are supported, here we look them up
9784     if(typeof this.sortType == "string"){
9785         this.sortType = st[this.sortType];
9786     }
9787     
9788     // set default sortType for strings and dates
9789     if(!this.sortType){
9790         switch(this.type){
9791             case "string":
9792                 this.sortType = st.asUCString;
9793                 break;
9794             case "date":
9795                 this.sortType = st.asDate;
9796                 break;
9797             default:
9798                 this.sortType = st.none;
9799         }
9800     }
9801
9802     // define once
9803     var stripRe = /[\$,%]/g;
9804
9805     // prebuilt conversion function for this field, instead of
9806     // switching every time we're reading a value
9807     if(!this.convert){
9808         var cv, dateFormat = this.dateFormat;
9809         switch(this.type){
9810             case "":
9811             case "auto":
9812             case undefined:
9813                 cv = function(v){ return v; };
9814                 break;
9815             case "string":
9816                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9817                 break;
9818             case "int":
9819                 cv = function(v){
9820                     return v !== undefined && v !== null && v !== '' ?
9821                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9822                     };
9823                 break;
9824             case "float":
9825                 cv = function(v){
9826                     return v !== undefined && v !== null && v !== '' ?
9827                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9828                     };
9829                 break;
9830             case "bool":
9831             case "boolean":
9832                 cv = function(v){ return v === true || v === "true" || v == 1; };
9833                 break;
9834             case "date":
9835                 cv = function(v){
9836                     if(!v){
9837                         return '';
9838                     }
9839                     if(v instanceof Date){
9840                         return v;
9841                     }
9842                     if(dateFormat){
9843                         if(dateFormat == "timestamp"){
9844                             return new Date(v*1000);
9845                         }
9846                         return Date.parseDate(v, dateFormat);
9847                     }
9848                     var parsed = Date.parse(v);
9849                     return parsed ? new Date(parsed) : null;
9850                 };
9851              break;
9852             
9853         }
9854         this.convert = cv;
9855     }
9856 };
9857
9858 Roo.data.Field.prototype = {
9859     dateFormat: null,
9860     defaultValue: "",
9861     mapping: null,
9862     sortType : null,
9863     sortDir : "ASC"
9864 };/*
9865  * Based on:
9866  * Ext JS Library 1.1.1
9867  * Copyright(c) 2006-2007, Ext JS, LLC.
9868  *
9869  * Originally Released Under LGPL - original licence link has changed is not relivant.
9870  *
9871  * Fork - LGPL
9872  * <script type="text/javascript">
9873  */
9874  
9875 // Base class for reading structured data from a data source.  This class is intended to be
9876 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9877
9878 /**
9879  * @class Roo.data.DataReader
9880  * Base class for reading structured data from a data source.  This class is intended to be
9881  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9882  */
9883
9884 Roo.data.DataReader = function(meta, recordType){
9885     
9886     this.meta = meta;
9887     
9888     this.recordType = recordType instanceof Array ? 
9889         Roo.data.Record.create(recordType) : recordType;
9890 };
9891
9892 Roo.data.DataReader.prototype = {
9893      /**
9894      * Create an empty record
9895      * @param {Object} data (optional) - overlay some values
9896      * @return {Roo.data.Record} record created.
9897      */
9898     newRow :  function(d) {
9899         var da =  {};
9900         this.recordType.prototype.fields.each(function(c) {
9901             switch( c.type) {
9902                 case 'int' : da[c.name] = 0; break;
9903                 case 'date' : da[c.name] = new Date(); break;
9904                 case 'float' : da[c.name] = 0.0; break;
9905                 case 'boolean' : da[c.name] = false; break;
9906                 default : da[c.name] = ""; break;
9907             }
9908             
9909         });
9910         return new this.recordType(Roo.apply(da, d));
9911     }
9912     
9913 };/*
9914  * Based on:
9915  * Ext JS Library 1.1.1
9916  * Copyright(c) 2006-2007, Ext JS, LLC.
9917  *
9918  * Originally Released Under LGPL - original licence link has changed is not relivant.
9919  *
9920  * Fork - LGPL
9921  * <script type="text/javascript">
9922  */
9923
9924 /**
9925  * @class Roo.data.DataProxy
9926  * @extends Roo.data.Observable
9927  * This class is an abstract base class for implementations which provide retrieval of
9928  * unformatted data objects.<br>
9929  * <p>
9930  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9931  * (of the appropriate type which knows how to parse the data object) to provide a block of
9932  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9933  * <p>
9934  * Custom implementations must implement the load method as described in
9935  * {@link Roo.data.HttpProxy#load}.
9936  */
9937 Roo.data.DataProxy = function(){
9938     this.addEvents({
9939         /**
9940          * @event beforeload
9941          * Fires before a network request is made to retrieve a data object.
9942          * @param {Object} This DataProxy object.
9943          * @param {Object} params The params parameter to the load function.
9944          */
9945         beforeload : true,
9946         /**
9947          * @event load
9948          * Fires before the load method's callback is called.
9949          * @param {Object} This DataProxy object.
9950          * @param {Object} o The data object.
9951          * @param {Object} arg The callback argument object passed to the load function.
9952          */
9953         load : true,
9954         /**
9955          * @event loadexception
9956          * Fires if an Exception occurs during data retrieval.
9957          * @param {Object} This DataProxy object.
9958          * @param {Object} o The data object.
9959          * @param {Object} arg The callback argument object passed to the load function.
9960          * @param {Object} e The Exception.
9961          */
9962         loadexception : true
9963     });
9964     Roo.data.DataProxy.superclass.constructor.call(this);
9965 };
9966
9967 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9968
9969     /**
9970      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9971      */
9972 /*
9973  * Based on:
9974  * Ext JS Library 1.1.1
9975  * Copyright(c) 2006-2007, Ext JS, LLC.
9976  *
9977  * Originally Released Under LGPL - original licence link has changed is not relivant.
9978  *
9979  * Fork - LGPL
9980  * <script type="text/javascript">
9981  */
9982 /**
9983  * @class Roo.data.MemoryProxy
9984  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9985  * to the Reader when its load method is called.
9986  * @constructor
9987  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9988  */
9989 Roo.data.MemoryProxy = function(data){
9990     if (data.data) {
9991         data = data.data;
9992     }
9993     Roo.data.MemoryProxy.superclass.constructor.call(this);
9994     this.data = data;
9995 };
9996
9997 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9998     /**
9999      * Load data from the requested source (in this case an in-memory
10000      * data object passed to the constructor), read the data object into
10001      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10002      * process that block using the passed callback.
10003      * @param {Object} params This parameter is not used by the MemoryProxy class.
10004      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10005      * object into a block of Roo.data.Records.
10006      * @param {Function} callback The function into which to pass the block of Roo.data.records.
10007      * The function must be passed <ul>
10008      * <li>The Record block object</li>
10009      * <li>The "arg" argument from the load function</li>
10010      * <li>A boolean success indicator</li>
10011      * </ul>
10012      * @param {Object} scope The scope in which to call the callback
10013      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10014      */
10015     load : function(params, reader, callback, scope, arg){
10016         params = params || {};
10017         var result;
10018         try {
10019             result = reader.readRecords(this.data);
10020         }catch(e){
10021             this.fireEvent("loadexception", this, arg, null, e);
10022             callback.call(scope, null, arg, false);
10023             return;
10024         }
10025         callback.call(scope, result, arg, true);
10026     },
10027     
10028     // private
10029     update : function(params, records){
10030         
10031     }
10032 });/*
10033  * Based on:
10034  * Ext JS Library 1.1.1
10035  * Copyright(c) 2006-2007, Ext JS, LLC.
10036  *
10037  * Originally Released Under LGPL - original licence link has changed is not relivant.
10038  *
10039  * Fork - LGPL
10040  * <script type="text/javascript">
10041  */
10042 /**
10043  * @class Roo.data.HttpProxy
10044  * @extends Roo.data.DataProxy
10045  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10046  * configured to reference a certain URL.<br><br>
10047  * <p>
10048  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10049  * from which the running page was served.<br><br>
10050  * <p>
10051  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10052  * <p>
10053  * Be aware that to enable the browser to parse an XML document, the server must set
10054  * the Content-Type header in the HTTP response to "text/xml".
10055  * @constructor
10056  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10057  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
10058  * will be used to make the request.
10059  */
10060 Roo.data.HttpProxy = function(conn){
10061     Roo.data.HttpProxy.superclass.constructor.call(this);
10062     // is conn a conn config or a real conn?
10063     this.conn = conn;
10064     this.useAjax = !conn || !conn.events;
10065   
10066 };
10067
10068 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10069     // thse are take from connection...
10070     
10071     /**
10072      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10073      */
10074     /**
10075      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10076      * extra parameters to each request made by this object. (defaults to undefined)
10077      */
10078     /**
10079      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10080      *  to each request made by this object. (defaults to undefined)
10081      */
10082     /**
10083      * @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)
10084      */
10085     /**
10086      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10087      */
10088      /**
10089      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10090      * @type Boolean
10091      */
10092   
10093
10094     /**
10095      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10096      * @type Boolean
10097      */
10098     /**
10099      * Return the {@link Roo.data.Connection} object being used by this Proxy.
10100      * @return {Connection} The Connection object. This object may be used to subscribe to events on
10101      * a finer-grained basis than the DataProxy events.
10102      */
10103     getConnection : function(){
10104         return this.useAjax ? Roo.Ajax : this.conn;
10105     },
10106
10107     /**
10108      * Load data from the configured {@link Roo.data.Connection}, read the data object into
10109      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10110      * process that block using the passed callback.
10111      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10112      * for the request to the remote server.
10113      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10114      * object into a block of Roo.data.Records.
10115      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10116      * The function must be passed <ul>
10117      * <li>The Record block object</li>
10118      * <li>The "arg" argument from the load function</li>
10119      * <li>A boolean success indicator</li>
10120      * </ul>
10121      * @param {Object} scope The scope in which to call the callback
10122      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10123      */
10124     load : function(params, reader, callback, scope, arg){
10125         if(this.fireEvent("beforeload", this, params) !== false){
10126             var  o = {
10127                 params : params || {},
10128                 request: {
10129                     callback : callback,
10130                     scope : scope,
10131                     arg : arg
10132                 },
10133                 reader: reader,
10134                 callback : this.loadResponse,
10135                 scope: this
10136             };
10137             if(this.useAjax){
10138                 Roo.applyIf(o, this.conn);
10139                 if(this.activeRequest){
10140                     Roo.Ajax.abort(this.activeRequest);
10141                 }
10142                 this.activeRequest = Roo.Ajax.request(o);
10143             }else{
10144                 this.conn.request(o);
10145             }
10146         }else{
10147             callback.call(scope||this, null, arg, false);
10148         }
10149     },
10150
10151     // private
10152     loadResponse : function(o, success, response){
10153         delete this.activeRequest;
10154         if(!success){
10155             this.fireEvent("loadexception", this, o, response);
10156             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10157             return;
10158         }
10159         var result;
10160         try {
10161             result = o.reader.read(response);
10162         }catch(e){
10163             this.fireEvent("loadexception", this, o, response, e);
10164             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10165             return;
10166         }
10167         
10168         this.fireEvent("load", this, o, o.request.arg);
10169         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10170     },
10171
10172     // private
10173     update : function(dataSet){
10174
10175     },
10176
10177     // private
10178     updateResponse : function(dataSet){
10179
10180     }
10181 });/*
10182  * Based on:
10183  * Ext JS Library 1.1.1
10184  * Copyright(c) 2006-2007, Ext JS, LLC.
10185  *
10186  * Originally Released Under LGPL - original licence link has changed is not relivant.
10187  *
10188  * Fork - LGPL
10189  * <script type="text/javascript">
10190  */
10191
10192 /**
10193  * @class Roo.data.ScriptTagProxy
10194  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10195  * other than the originating domain of the running page.<br><br>
10196  * <p>
10197  * <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
10198  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10199  * <p>
10200  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10201  * source code that is used as the source inside a &lt;script> tag.<br><br>
10202  * <p>
10203  * In order for the browser to process the returned data, the server must wrap the data object
10204  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10205  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10206  * depending on whether the callback name was passed:
10207  * <p>
10208  * <pre><code>
10209 boolean scriptTag = false;
10210 String cb = request.getParameter("callback");
10211 if (cb != null) {
10212     scriptTag = true;
10213     response.setContentType("text/javascript");
10214 } else {
10215     response.setContentType("application/x-json");
10216 }
10217 Writer out = response.getWriter();
10218 if (scriptTag) {
10219     out.write(cb + "(");
10220 }
10221 out.print(dataBlock.toJsonString());
10222 if (scriptTag) {
10223     out.write(");");
10224 }
10225 </pre></code>
10226  *
10227  * @constructor
10228  * @param {Object} config A configuration object.
10229  */
10230 Roo.data.ScriptTagProxy = function(config){
10231     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10232     Roo.apply(this, config);
10233     this.head = document.getElementsByTagName("head")[0];
10234 };
10235
10236 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10237
10238 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10239     /**
10240      * @cfg {String} url The URL from which to request the data object.
10241      */
10242     /**
10243      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10244      */
10245     timeout : 30000,
10246     /**
10247      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10248      * the server the name of the callback function set up by the load call to process the returned data object.
10249      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10250      * javascript output which calls this named function passing the data object as its only parameter.
10251      */
10252     callbackParam : "callback",
10253     /**
10254      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10255      * name to the request.
10256      */
10257     nocache : true,
10258
10259     /**
10260      * Load data from the configured URL, read the data object into
10261      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10262      * process that block using the passed callback.
10263      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10264      * for the request to the remote server.
10265      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10266      * object into a block of Roo.data.Records.
10267      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10268      * The function must be passed <ul>
10269      * <li>The Record block object</li>
10270      * <li>The "arg" argument from the load function</li>
10271      * <li>A boolean success indicator</li>
10272      * </ul>
10273      * @param {Object} scope The scope in which to call the callback
10274      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10275      */
10276     load : function(params, reader, callback, scope, arg){
10277         if(this.fireEvent("beforeload", this, params) !== false){
10278
10279             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10280
10281             var url = this.url;
10282             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10283             if(this.nocache){
10284                 url += "&_dc=" + (new Date().getTime());
10285             }
10286             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10287             var trans = {
10288                 id : transId,
10289                 cb : "stcCallback"+transId,
10290                 scriptId : "stcScript"+transId,
10291                 params : params,
10292                 arg : arg,
10293                 url : url,
10294                 callback : callback,
10295                 scope : scope,
10296                 reader : reader
10297             };
10298             var conn = this;
10299
10300             window[trans.cb] = function(o){
10301                 conn.handleResponse(o, trans);
10302             };
10303
10304             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10305
10306             if(this.autoAbort !== false){
10307                 this.abort();
10308             }
10309
10310             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10311
10312             var script = document.createElement("script");
10313             script.setAttribute("src", url);
10314             script.setAttribute("type", "text/javascript");
10315             script.setAttribute("id", trans.scriptId);
10316             this.head.appendChild(script);
10317
10318             this.trans = trans;
10319         }else{
10320             callback.call(scope||this, null, arg, false);
10321         }
10322     },
10323
10324     // private
10325     isLoading : function(){
10326         return this.trans ? true : false;
10327     },
10328
10329     /**
10330      * Abort the current server request.
10331      */
10332     abort : function(){
10333         if(this.isLoading()){
10334             this.destroyTrans(this.trans);
10335         }
10336     },
10337
10338     // private
10339     destroyTrans : function(trans, isLoaded){
10340         this.head.removeChild(document.getElementById(trans.scriptId));
10341         clearTimeout(trans.timeoutId);
10342         if(isLoaded){
10343             window[trans.cb] = undefined;
10344             try{
10345                 delete window[trans.cb];
10346             }catch(e){}
10347         }else{
10348             // if hasn't been loaded, wait for load to remove it to prevent script error
10349             window[trans.cb] = function(){
10350                 window[trans.cb] = undefined;
10351                 try{
10352                     delete window[trans.cb];
10353                 }catch(e){}
10354             };
10355         }
10356     },
10357
10358     // private
10359     handleResponse : function(o, trans){
10360         this.trans = false;
10361         this.destroyTrans(trans, true);
10362         var result;
10363         try {
10364             result = trans.reader.readRecords(o);
10365         }catch(e){
10366             this.fireEvent("loadexception", this, o, trans.arg, e);
10367             trans.callback.call(trans.scope||window, null, trans.arg, false);
10368             return;
10369         }
10370         this.fireEvent("load", this, o, trans.arg);
10371         trans.callback.call(trans.scope||window, result, trans.arg, true);
10372     },
10373
10374     // private
10375     handleFailure : function(trans){
10376         this.trans = false;
10377         this.destroyTrans(trans, false);
10378         this.fireEvent("loadexception", this, null, trans.arg);
10379         trans.callback.call(trans.scope||window, null, trans.arg, false);
10380     }
10381 });/*
10382  * Based on:
10383  * Ext JS Library 1.1.1
10384  * Copyright(c) 2006-2007, Ext JS, LLC.
10385  *
10386  * Originally Released Under LGPL - original licence link has changed is not relivant.
10387  *
10388  * Fork - LGPL
10389  * <script type="text/javascript">
10390  */
10391
10392 /**
10393  * @class Roo.data.JsonReader
10394  * @extends Roo.data.DataReader
10395  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10396  * based on mappings in a provided Roo.data.Record constructor.
10397  * 
10398  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10399  * in the reply previously. 
10400  * 
10401  * <p>
10402  * Example code:
10403  * <pre><code>
10404 var RecordDef = Roo.data.Record.create([
10405     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10406     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10407 ]);
10408 var myReader = new Roo.data.JsonReader({
10409     totalProperty: "results",    // The property which contains the total dataset size (optional)
10410     root: "rows",                // The property which contains an Array of row objects
10411     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10412 }, RecordDef);
10413 </code></pre>
10414  * <p>
10415  * This would consume a JSON file like this:
10416  * <pre><code>
10417 { 'results': 2, 'rows': [
10418     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10419     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10420 }
10421 </code></pre>
10422  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10423  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10424  * paged from the remote server.
10425  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10426  * @cfg {String} root name of the property which contains the Array of row objects.
10427  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10428  * @constructor
10429  * Create a new JsonReader
10430  * @param {Object} meta Metadata configuration options
10431  * @param {Object} recordType Either an Array of field definition objects,
10432  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10433  */
10434 Roo.data.JsonReader = function(meta, recordType){
10435     
10436     meta = meta || {};
10437     // set some defaults:
10438     Roo.applyIf(meta, {
10439         totalProperty: 'total',
10440         successProperty : 'success',
10441         root : 'data',
10442         id : 'id'
10443     });
10444     
10445     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10446 };
10447 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10448     
10449     /**
10450      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10451      * Used by Store query builder to append _requestMeta to params.
10452      * 
10453      */
10454     metaFromRemote : false,
10455     /**
10456      * This method is only used by a DataProxy which has retrieved data from a remote server.
10457      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10458      * @return {Object} data A data block which is used by an Roo.data.Store object as
10459      * a cache of Roo.data.Records.
10460      */
10461     read : function(response){
10462         var json = response.responseText;
10463        
10464         var o = /* eval:var:o */ eval("("+json+")");
10465         if(!o) {
10466             throw {message: "JsonReader.read: Json object not found"};
10467         }
10468         
10469         if(o.metaData){
10470             
10471             delete this.ef;
10472             this.metaFromRemote = true;
10473             this.meta = o.metaData;
10474             this.recordType = Roo.data.Record.create(o.metaData.fields);
10475             this.onMetaChange(this.meta, this.recordType, o);
10476         }
10477         return this.readRecords(o);
10478     },
10479
10480     // private function a store will implement
10481     onMetaChange : function(meta, recordType, o){
10482
10483     },
10484
10485     /**
10486          * @ignore
10487          */
10488     simpleAccess: function(obj, subsc) {
10489         return obj[subsc];
10490     },
10491
10492         /**
10493          * @ignore
10494          */
10495     getJsonAccessor: function(){
10496         var re = /[\[\.]/;
10497         return function(expr) {
10498             try {
10499                 return(re.test(expr))
10500                     ? new Function("obj", "return obj." + expr)
10501                     : function(obj){
10502                         return obj[expr];
10503                     };
10504             } catch(e){}
10505             return Roo.emptyFn;
10506         };
10507     }(),
10508
10509     /**
10510      * Create a data block containing Roo.data.Records from an XML document.
10511      * @param {Object} o An object which contains an Array of row objects in the property specified
10512      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10513      * which contains the total size of the dataset.
10514      * @return {Object} data A data block which is used by an Roo.data.Store object as
10515      * a cache of Roo.data.Records.
10516      */
10517     readRecords : function(o){
10518         /**
10519          * After any data loads, the raw JSON data is available for further custom processing.
10520          * @type Object
10521          */
10522         this.o = o;
10523         var s = this.meta, Record = this.recordType,
10524             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10525
10526 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10527         if (!this.ef) {
10528             if(s.totalProperty) {
10529                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10530                 }
10531                 if(s.successProperty) {
10532                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10533                 }
10534                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10535                 if (s.id) {
10536                         var g = this.getJsonAccessor(s.id);
10537                         this.getId = function(rec) {
10538                                 var r = g(rec);  
10539                                 return (r === undefined || r === "") ? null : r;
10540                         };
10541                 } else {
10542                         this.getId = function(){return null;};
10543                 }
10544             this.ef = [];
10545             for(var jj = 0; jj < fl; jj++){
10546                 f = fi[jj];
10547                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10548                 this.ef[jj] = this.getJsonAccessor(map);
10549             }
10550         }
10551
10552         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10553         if(s.totalProperty){
10554             var vt = parseInt(this.getTotal(o), 10);
10555             if(!isNaN(vt)){
10556                 totalRecords = vt;
10557             }
10558         }
10559         if(s.successProperty){
10560             var vs = this.getSuccess(o);
10561             if(vs === false || vs === 'false'){
10562                 success = false;
10563             }
10564         }
10565         var records = [];
10566         for(var i = 0; i < c; i++){
10567                 var n = root[i];
10568             var values = {};
10569             var id = this.getId(n);
10570             for(var j = 0; j < fl; j++){
10571                 f = fi[j];
10572             var v = this.ef[j](n);
10573             if (!f.convert) {
10574                 Roo.log('missing convert for ' + f.name);
10575                 Roo.log(f);
10576                 continue;
10577             }
10578             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10579             }
10580             var record = new Record(values, id);
10581             record.json = n;
10582             records[i] = record;
10583         }
10584         return {
10585             raw : o,
10586             success : success,
10587             records : records,
10588             totalRecords : totalRecords
10589         };
10590     }
10591 });/*
10592  * Based on:
10593  * Ext JS Library 1.1.1
10594  * Copyright(c) 2006-2007, Ext JS, LLC.
10595  *
10596  * Originally Released Under LGPL - original licence link has changed is not relivant.
10597  *
10598  * Fork - LGPL
10599  * <script type="text/javascript">
10600  */
10601
10602 /**
10603  * @class Roo.data.ArrayReader
10604  * @extends Roo.data.DataReader
10605  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10606  * Each element of that Array represents a row of data fields. The
10607  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10608  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10609  * <p>
10610  * Example code:.
10611  * <pre><code>
10612 var RecordDef = Roo.data.Record.create([
10613     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10614     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10615 ]);
10616 var myReader = new Roo.data.ArrayReader({
10617     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10618 }, RecordDef);
10619 </code></pre>
10620  * <p>
10621  * This would consume an Array like this:
10622  * <pre><code>
10623 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10624   </code></pre>
10625  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10626  * @constructor
10627  * Create a new JsonReader
10628  * @param {Object} meta Metadata configuration options.
10629  * @param {Object} recordType Either an Array of field definition objects
10630  * as specified to {@link Roo.data.Record#create},
10631  * or an {@link Roo.data.Record} object
10632  * created using {@link Roo.data.Record#create}.
10633  */
10634 Roo.data.ArrayReader = function(meta, recordType){
10635     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10636 };
10637
10638 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10639     /**
10640      * Create a data block containing Roo.data.Records from an XML document.
10641      * @param {Object} o An Array of row objects which represents the dataset.
10642      * @return {Object} data A data block which is used by an Roo.data.Store object as
10643      * a cache of Roo.data.Records.
10644      */
10645     readRecords : function(o){
10646         var sid = this.meta ? this.meta.id : null;
10647         var recordType = this.recordType, fields = recordType.prototype.fields;
10648         var records = [];
10649         var root = o;
10650             for(var i = 0; i < root.length; i++){
10651                     var n = root[i];
10652                 var values = {};
10653                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10654                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10655                 var f = fields.items[j];
10656                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10657                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10658                 v = f.convert(v);
10659                 values[f.name] = v;
10660             }
10661                 var record = new recordType(values, id);
10662                 record.json = n;
10663                 records[records.length] = record;
10664             }
10665             return {
10666                 records : records,
10667                 totalRecords : records.length
10668             };
10669     }
10670 });/*
10671  * - LGPL
10672  * * 
10673  */
10674
10675 /**
10676  * @class Roo.bootstrap.ComboBox
10677  * @extends Roo.bootstrap.TriggerField
10678  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10679  * @cfg {Boolean} append (true|false) default false
10680  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10681  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10682  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10683  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10684  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10685  * @constructor
10686  * Create a new ComboBox.
10687  * @param {Object} config Configuration options
10688  */
10689 Roo.bootstrap.ComboBox = function(config){
10690     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10691     this.addEvents({
10692         /**
10693          * @event expand
10694          * Fires when the dropdown list is expanded
10695              * @param {Roo.bootstrap.ComboBox} combo This combo box
10696              */
10697         'expand' : true,
10698         /**
10699          * @event collapse
10700          * Fires when the dropdown list is collapsed
10701              * @param {Roo.bootstrap.ComboBox} combo This combo box
10702              */
10703         'collapse' : true,
10704         /**
10705          * @event beforeselect
10706          * Fires before a list item is selected. Return false to cancel the selection.
10707              * @param {Roo.bootstrap.ComboBox} combo This combo box
10708              * @param {Roo.data.Record} record The data record returned from the underlying store
10709              * @param {Number} index The index of the selected item in the dropdown list
10710              */
10711         'beforeselect' : true,
10712         /**
10713          * @event select
10714          * Fires when a list item is selected
10715              * @param {Roo.bootstrap.ComboBox} combo This combo box
10716              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10717              * @param {Number} index The index of the selected item in the dropdown list
10718              */
10719         'select' : true,
10720         /**
10721          * @event beforequery
10722          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10723          * The event object passed has these properties:
10724              * @param {Roo.bootstrap.ComboBox} combo This combo box
10725              * @param {String} query The query
10726              * @param {Boolean} forceAll true to force "all" query
10727              * @param {Boolean} cancel true to cancel the query
10728              * @param {Object} e The query event object
10729              */
10730         'beforequery': true,
10731          /**
10732          * @event add
10733          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10734              * @param {Roo.bootstrap.ComboBox} combo This combo box
10735              */
10736         'add' : true,
10737         /**
10738          * @event edit
10739          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10740              * @param {Roo.bootstrap.ComboBox} combo This combo box
10741              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10742              */
10743         'edit' : true,
10744         /**
10745          * @event remove
10746          * Fires when the remove value from the combobox array
10747              * @param {Roo.bootstrap.ComboBox} combo This combo box
10748              */
10749         'remove' : true
10750         
10751     });
10752     
10753     this.item = [];
10754     this.tickItems = [];
10755     
10756     this.selectedIndex = -1;
10757     if(this.mode == 'local'){
10758         if(config.queryDelay === undefined){
10759             this.queryDelay = 10;
10760         }
10761         if(config.minChars === undefined){
10762             this.minChars = 0;
10763         }
10764     }
10765 };
10766
10767 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10768      
10769     /**
10770      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10771      * rendering into an Roo.Editor, defaults to false)
10772      */
10773     /**
10774      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10775      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10776      */
10777     /**
10778      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10779      */
10780     /**
10781      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10782      * the dropdown list (defaults to undefined, with no header element)
10783      */
10784
10785      /**
10786      * @cfg {String/Roo.Template} tpl The template to use to render the output
10787      */
10788      
10789      /**
10790      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10791      */
10792     listWidth: undefined,
10793     /**
10794      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10795      * mode = 'remote' or 'text' if mode = 'local')
10796      */
10797     displayField: undefined,
10798     /**
10799      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10800      * mode = 'remote' or 'value' if mode = 'local'). 
10801      * Note: use of a valueField requires the user make a selection
10802      * in order for a value to be mapped.
10803      */
10804     valueField: undefined,
10805     
10806     
10807     /**
10808      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10809      * field's data value (defaults to the underlying DOM element's name)
10810      */
10811     hiddenName: undefined,
10812     /**
10813      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10814      */
10815     listClass: '',
10816     /**
10817      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10818      */
10819     selectedClass: 'active',
10820     
10821     /**
10822      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10823      */
10824     shadow:'sides',
10825     /**
10826      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10827      * anchor positions (defaults to 'tl-bl')
10828      */
10829     listAlign: 'tl-bl?',
10830     /**
10831      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10832      */
10833     maxHeight: 300,
10834     /**
10835      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10836      * query specified by the allQuery config option (defaults to 'query')
10837      */
10838     triggerAction: 'query',
10839     /**
10840      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10841      * (defaults to 4, does not apply if editable = false)
10842      */
10843     minChars : 4,
10844     /**
10845      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10846      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10847      */
10848     typeAhead: false,
10849     /**
10850      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10851      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10852      */
10853     queryDelay: 500,
10854     /**
10855      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10856      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10857      */
10858     pageSize: 0,
10859     /**
10860      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10861      * when editable = true (defaults to false)
10862      */
10863     selectOnFocus:false,
10864     /**
10865      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10866      */
10867     queryParam: 'query',
10868     /**
10869      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10870      * when mode = 'remote' (defaults to 'Loading...')
10871      */
10872     loadingText: 'Loading...',
10873     /**
10874      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10875      */
10876     resizable: false,
10877     /**
10878      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10879      */
10880     handleHeight : 8,
10881     /**
10882      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10883      * traditional select (defaults to true)
10884      */
10885     editable: true,
10886     /**
10887      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10888      */
10889     allQuery: '',
10890     /**
10891      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10892      */
10893     mode: 'remote',
10894     /**
10895      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10896      * listWidth has a higher value)
10897      */
10898     minListWidth : 70,
10899     /**
10900      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10901      * allow the user to set arbitrary text into the field (defaults to false)
10902      */
10903     forceSelection:false,
10904     /**
10905      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10906      * if typeAhead = true (defaults to 250)
10907      */
10908     typeAheadDelay : 250,
10909     /**
10910      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10911      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10912      */
10913     valueNotFoundText : undefined,
10914     /**
10915      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10916      */
10917     blockFocus : false,
10918     
10919     /**
10920      * @cfg {Boolean} disableClear Disable showing of clear button.
10921      */
10922     disableClear : false,
10923     /**
10924      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10925      */
10926     alwaysQuery : false,
10927     
10928     /**
10929      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10930      */
10931     multiple : false,
10932     
10933     /**
10934      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10935      */
10936     invalidClass : "has-warning",
10937     
10938     /**
10939      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10940      */
10941     validClass : "has-success",
10942     
10943     //private
10944     addicon : false,
10945     editicon: false,
10946     
10947     page: 0,
10948     hasQuery: false,
10949     append: false,
10950     loadNext: false,
10951     autoFocus : true,
10952     tickable : false,
10953     btnPosition : 'right',
10954     triggerList : true,
10955     showToggleBtn : true,
10956     // element that contains real text value.. (when hidden is used..)
10957     
10958     getAutoCreate : function()
10959     {
10960         var cfg = false;
10961         
10962         /*
10963          *  Normal ComboBox
10964          */
10965         if(!this.tickable){
10966             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10967             return cfg;
10968         }
10969         
10970         /*
10971          *  ComboBox with tickable selections
10972          */
10973              
10974         var align = this.labelAlign || this.parentLabelAlign();
10975         
10976         cfg = {
10977             cls : 'form-group roo-combobox-tickable' //input-group
10978         };
10979         
10980         var buttons = {
10981             tag : 'div',
10982             cls : 'tickable-buttons',
10983             cn : [
10984                 {
10985                     tag : 'button',
10986                     type : 'button',
10987                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10988                     html : 'Edit'
10989                 },
10990                 {
10991                     tag : 'button',
10992                     type : 'button',
10993                     name : 'ok',
10994                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10995                     html : 'Done'
10996                 },
10997                 {
10998                     tag : 'button',
10999                     type : 'button',
11000                     name : 'cancel',
11001                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11002                     html : 'Cancel'
11003                 }
11004             ]
11005         };
11006         
11007         if(this.editable){
11008             buttons.cn.unshift({
11009                 tag: 'input',
11010                 cls: 'select2-search-field-input'
11011             });
11012         }
11013         
11014         var _this = this;
11015         
11016         Roo.each(buttons.cn, function(c){
11017             if (_this.size) {
11018                 c.cls += ' btn-' + _this.size;
11019             }
11020
11021             if (_this.disabled) {
11022                 c.disabled = true;
11023             }
11024         });
11025         
11026         var box = {
11027             tag: 'div',
11028             cn: [
11029                 {
11030                     tag: 'input',
11031                     type : 'hidden',
11032                     cls: 'form-hidden-field'
11033                 },
11034                 {
11035                     tag: 'ul',
11036                     cls: 'select2-choices',
11037                     cn:[
11038                         {
11039                             tag: 'li',
11040                             cls: 'select2-search-field',
11041                             cn: [
11042
11043                                 buttons
11044                             ]
11045                         }
11046                     ]
11047                 }
11048             ]
11049         }
11050         
11051         var combobox = {
11052             cls: 'select2-container input-group select2-container-multi',
11053             cn: [
11054                 box
11055 //                {
11056 //                    tag: 'ul',
11057 //                    cls: 'typeahead typeahead-long dropdown-menu',
11058 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
11059 //                }
11060             ]
11061         };
11062         
11063         if(this.hasFeedback && !this.allowBlank){
11064             
11065             var feedback = {
11066                 tag: 'span',
11067                 cls: 'glyphicon form-control-feedback'
11068             };
11069
11070             combobox.cn.push(feedback);
11071         }
11072         
11073         if (align ==='left' && this.fieldLabel.length) {
11074             
11075                 Roo.log("left and has label");
11076                 cfg.cn = [
11077                     
11078                     {
11079                         tag: 'label',
11080                         'for' :  id,
11081                         cls : 'control-label col-sm-' + this.labelWidth,
11082                         html : this.fieldLabel
11083                         
11084                     },
11085                     {
11086                         cls : "col-sm-" + (12 - this.labelWidth), 
11087                         cn: [
11088                             combobox
11089                         ]
11090                     }
11091                     
11092                 ];
11093         } else if ( this.fieldLabel.length) {
11094                 Roo.log(" label");
11095                  cfg.cn = [
11096                    
11097                     {
11098                         tag: 'label',
11099                         //cls : 'input-group-addon',
11100                         html : this.fieldLabel
11101                         
11102                     },
11103                     
11104                     combobox
11105                     
11106                 ];
11107
11108         } else {
11109             
11110                 Roo.log(" no label && no align");
11111                 cfg = combobox
11112                      
11113                 
11114         }
11115          
11116         var settings=this;
11117         ['xs','sm','md','lg'].map(function(size){
11118             if (settings[size]) {
11119                 cfg.cls += ' col-' + size + '-' + settings[size];
11120             }
11121         });
11122         
11123         return cfg;
11124         
11125     },
11126     
11127     // private
11128     initEvents: function()
11129     {
11130         
11131         if (!this.store) {
11132             throw "can not find store for combo";
11133         }
11134         this.store = Roo.factory(this.store, Roo.data);
11135         
11136         if(this.tickable){
11137             this.initTickableEvents();
11138             return;
11139         }
11140         
11141         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11142         
11143         if(this.hiddenName){
11144             
11145             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11146             
11147             this.hiddenField.dom.value =
11148                 this.hiddenValue !== undefined ? this.hiddenValue :
11149                 this.value !== undefined ? this.value : '';
11150
11151             // prevent input submission
11152             this.el.dom.removeAttribute('name');
11153             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11154              
11155              
11156         }
11157         //if(Roo.isGecko){
11158         //    this.el.dom.setAttribute('autocomplete', 'off');
11159         //}
11160         
11161         var cls = 'x-combo-list';
11162         
11163         //this.list = new Roo.Layer({
11164         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11165         //});
11166         
11167         var _this = this;
11168         
11169         (function(){
11170             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11171             _this.list.setWidth(lw);
11172         }).defer(100);
11173         
11174         this.list.on('mouseover', this.onViewOver, this);
11175         this.list.on('mousemove', this.onViewMove, this);
11176         
11177         this.list.on('scroll', this.onViewScroll, this);
11178         
11179         /*
11180         this.list.swallowEvent('mousewheel');
11181         this.assetHeight = 0;
11182
11183         if(this.title){
11184             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11185             this.assetHeight += this.header.getHeight();
11186         }
11187
11188         this.innerList = this.list.createChild({cls:cls+'-inner'});
11189         this.innerList.on('mouseover', this.onViewOver, this);
11190         this.innerList.on('mousemove', this.onViewMove, this);
11191         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11192         
11193         if(this.allowBlank && !this.pageSize && !this.disableClear){
11194             this.footer = this.list.createChild({cls:cls+'-ft'});
11195             this.pageTb = new Roo.Toolbar(this.footer);
11196            
11197         }
11198         if(this.pageSize){
11199             this.footer = this.list.createChild({cls:cls+'-ft'});
11200             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11201                     {pageSize: this.pageSize});
11202             
11203         }
11204         
11205         if (this.pageTb && this.allowBlank && !this.disableClear) {
11206             var _this = this;
11207             this.pageTb.add(new Roo.Toolbar.Fill(), {
11208                 cls: 'x-btn-icon x-btn-clear',
11209                 text: '&#160;',
11210                 handler: function()
11211                 {
11212                     _this.collapse();
11213                     _this.clearValue();
11214                     _this.onSelect(false, -1);
11215                 }
11216             });
11217         }
11218         if (this.footer) {
11219             this.assetHeight += this.footer.getHeight();
11220         }
11221         */
11222             
11223         if(!this.tpl){
11224             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11225         }
11226
11227         this.view = new Roo.View(this.list, this.tpl, {
11228             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11229         });
11230         //this.view.wrapEl.setDisplayed(false);
11231         this.view.on('click', this.onViewClick, this);
11232         
11233         
11234         
11235         this.store.on('beforeload', this.onBeforeLoad, this);
11236         this.store.on('load', this.onLoad, this);
11237         this.store.on('loadexception', this.onLoadException, this);
11238         /*
11239         if(this.resizable){
11240             this.resizer = new Roo.Resizable(this.list,  {
11241                pinned:true, handles:'se'
11242             });
11243             this.resizer.on('resize', function(r, w, h){
11244                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11245                 this.listWidth = w;
11246                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11247                 this.restrictHeight();
11248             }, this);
11249             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11250         }
11251         */
11252         if(!this.editable){
11253             this.editable = true;
11254             this.setEditable(false);
11255         }
11256         
11257         /*
11258         
11259         if (typeof(this.events.add.listeners) != 'undefined') {
11260             
11261             this.addicon = this.wrap.createChild(
11262                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11263        
11264             this.addicon.on('click', function(e) {
11265                 this.fireEvent('add', this);
11266             }, this);
11267         }
11268         if (typeof(this.events.edit.listeners) != 'undefined') {
11269             
11270             this.editicon = this.wrap.createChild(
11271                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11272             if (this.addicon) {
11273                 this.editicon.setStyle('margin-left', '40px');
11274             }
11275             this.editicon.on('click', function(e) {
11276                 
11277                 // we fire even  if inothing is selected..
11278                 this.fireEvent('edit', this, this.lastData );
11279                 
11280             }, this);
11281         }
11282         */
11283         
11284         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11285             "up" : function(e){
11286                 this.inKeyMode = true;
11287                 this.selectPrev();
11288             },
11289
11290             "down" : function(e){
11291                 if(!this.isExpanded()){
11292                     this.onTriggerClick();
11293                 }else{
11294                     this.inKeyMode = true;
11295                     this.selectNext();
11296                 }
11297             },
11298
11299             "enter" : function(e){
11300 //                this.onViewClick();
11301                 //return true;
11302                 this.collapse();
11303                 
11304                 if(this.fireEvent("specialkey", this, e)){
11305                     this.onViewClick(false);
11306                 }
11307                 
11308                 return true;
11309             },
11310
11311             "esc" : function(e){
11312                 this.collapse();
11313             },
11314
11315             "tab" : function(e){
11316                 this.collapse();
11317                 
11318                 if(this.fireEvent("specialkey", this, e)){
11319                     this.onViewClick(false);
11320                 }
11321                 
11322                 return true;
11323             },
11324
11325             scope : this,
11326
11327             doRelay : function(foo, bar, hname){
11328                 if(hname == 'down' || this.scope.isExpanded()){
11329                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11330                 }
11331                 return true;
11332             },
11333
11334             forceKeyDown: true
11335         });
11336         
11337         
11338         this.queryDelay = Math.max(this.queryDelay || 10,
11339                 this.mode == 'local' ? 10 : 250);
11340         
11341         
11342         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11343         
11344         if(this.typeAhead){
11345             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11346         }
11347         if(this.editable !== false){
11348             this.inputEl().on("keyup", this.onKeyUp, this);
11349         }
11350         if(this.forceSelection){
11351             this.inputEl().on('blur', this.doForce, this);
11352         }
11353         
11354         if(this.multiple){
11355             this.choices = this.el.select('ul.select2-choices', true).first();
11356             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11357         }
11358     },
11359     
11360     initTickableEvents: function()
11361     {   
11362         this.createList();
11363         
11364         if(this.hiddenName){
11365             
11366             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11367             
11368             this.hiddenField.dom.value =
11369                 this.hiddenValue !== undefined ? this.hiddenValue :
11370                 this.value !== undefined ? this.value : '';
11371
11372             // prevent input submission
11373             this.el.dom.removeAttribute('name');
11374             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11375              
11376              
11377         }
11378         
11379 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11380         
11381         this.choices = this.el.select('ul.select2-choices', true).first();
11382         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11383         if(this.triggerList){
11384             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11385         }
11386          
11387         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11388         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11389         
11390         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11391         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11392         
11393         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11394         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11395         
11396         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11397         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11398         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11399         
11400         this.okBtn.hide();
11401         this.cancelBtn.hide();
11402         
11403         var _this = this;
11404         
11405         (function(){
11406             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11407             _this.list.setWidth(lw);
11408         }).defer(100);
11409         
11410         this.list.on('mouseover', this.onViewOver, this);
11411         this.list.on('mousemove', this.onViewMove, this);
11412         
11413         this.list.on('scroll', this.onViewScroll, this);
11414         
11415         if(!this.tpl){
11416             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>';
11417         }
11418
11419         this.view = new Roo.View(this.list, this.tpl, {
11420             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11421         });
11422         
11423         //this.view.wrapEl.setDisplayed(false);
11424         this.view.on('click', this.onViewClick, this);
11425         
11426         
11427         
11428         this.store.on('beforeload', this.onBeforeLoad, this);
11429         this.store.on('load', this.onLoad, this);
11430         this.store.on('loadexception', this.onLoadException, this);
11431         
11432         if(this.editable){
11433             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11434                 "up" : function(e){
11435                     this.inKeyMode = true;
11436                     this.selectPrev();
11437                 },
11438
11439                 "down" : function(e){
11440                     this.inKeyMode = true;
11441                     this.selectNext();
11442                 },
11443
11444                 "enter" : function(e){
11445                     if(this.fireEvent("specialkey", this, e)){
11446                         this.onViewClick(false);
11447                     }
11448                     
11449                     return true;
11450                 },
11451
11452                 "esc" : function(e){
11453                     this.onTickableFooterButtonClick(e, false, false);
11454                 },
11455
11456                 "tab" : function(e){
11457                     this.fireEvent("specialkey", this, e);
11458                     
11459                     this.onTickableFooterButtonClick(e, false, false);
11460                     
11461                     return true;
11462                 },
11463
11464                 scope : this,
11465
11466                 doRelay : function(e, fn, key){
11467                     if(this.scope.isExpanded()){
11468                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11469                     }
11470                     return true;
11471                 },
11472
11473                 forceKeyDown: true
11474             });
11475         }
11476         
11477         this.queryDelay = Math.max(this.queryDelay || 10,
11478                 this.mode == 'local' ? 10 : 250);
11479         
11480         
11481         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11482         
11483         if(this.typeAhead){
11484             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11485         }
11486         
11487         if(this.editable !== false){
11488             this.tickableInputEl().on("keyup", this.onKeyUp, this);
11489         }
11490         
11491     },
11492
11493     onDestroy : function(){
11494         if(this.view){
11495             this.view.setStore(null);
11496             this.view.el.removeAllListeners();
11497             this.view.el.remove();
11498             this.view.purgeListeners();
11499         }
11500         if(this.list){
11501             this.list.dom.innerHTML  = '';
11502         }
11503         
11504         if(this.store){
11505             this.store.un('beforeload', this.onBeforeLoad, this);
11506             this.store.un('load', this.onLoad, this);
11507             this.store.un('loadexception', this.onLoadException, this);
11508         }
11509         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11510     },
11511
11512     // private
11513     fireKey : function(e){
11514         if(e.isNavKeyPress() && !this.list.isVisible()){
11515             this.fireEvent("specialkey", this, e);
11516         }
11517     },
11518
11519     // private
11520     onResize: function(w, h){
11521 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11522 //        
11523 //        if(typeof w != 'number'){
11524 //            // we do not handle it!?!?
11525 //            return;
11526 //        }
11527 //        var tw = this.trigger.getWidth();
11528 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11529 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11530 //        var x = w - tw;
11531 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11532 //            
11533 //        //this.trigger.setStyle('left', x+'px');
11534 //        
11535 //        if(this.list && this.listWidth === undefined){
11536 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11537 //            this.list.setWidth(lw);
11538 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11539 //        }
11540         
11541     
11542         
11543     },
11544
11545     /**
11546      * Allow or prevent the user from directly editing the field text.  If false is passed,
11547      * the user will only be able to select from the items defined in the dropdown list.  This method
11548      * is the runtime equivalent of setting the 'editable' config option at config time.
11549      * @param {Boolean} value True to allow the user to directly edit the field text
11550      */
11551     setEditable : function(value){
11552         if(value == this.editable){
11553             return;
11554         }
11555         this.editable = value;
11556         if(!value){
11557             this.inputEl().dom.setAttribute('readOnly', true);
11558             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11559             this.inputEl().addClass('x-combo-noedit');
11560         }else{
11561             this.inputEl().dom.setAttribute('readOnly', false);
11562             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11563             this.inputEl().removeClass('x-combo-noedit');
11564         }
11565     },
11566
11567     // private
11568     
11569     onBeforeLoad : function(combo,opts){
11570         if(!this.hasFocus){
11571             return;
11572         }
11573          if (!opts.add) {
11574             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11575          }
11576         this.restrictHeight();
11577         this.selectedIndex = -1;
11578     },
11579
11580     // private
11581     onLoad : function(){
11582         
11583         this.hasQuery = false;
11584         
11585         if(!this.hasFocus){
11586             return;
11587         }
11588         
11589         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11590             this.loading.hide();
11591         }
11592              
11593         if(this.store.getCount() > 0){
11594             this.expand();
11595             this.restrictHeight();
11596             if(this.lastQuery == this.allQuery){
11597                 if(this.editable && !this.tickable){
11598                     this.inputEl().dom.select();
11599                 }
11600                 
11601                 if(
11602                     !this.selectByValue(this.value, true) &&
11603                     this.autoFocus && 
11604                     (
11605                         !this.store.lastOptions ||
11606                         typeof(this.store.lastOptions.add) == 'undefined' || 
11607                         this.store.lastOptions.add != true
11608                     )
11609                 ){
11610                     this.select(0, true);
11611                 }
11612             }else{
11613                 if(this.autoFocus){
11614                     this.selectNext();
11615                 }
11616                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11617                     this.taTask.delay(this.typeAheadDelay);
11618                 }
11619             }
11620         }else{
11621             this.onEmptyResults();
11622         }
11623         
11624         //this.el.focus();
11625     },
11626     // private
11627     onLoadException : function()
11628     {
11629         this.hasQuery = false;
11630         
11631         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11632             this.loading.hide();
11633         }
11634         
11635         if(this.tickable && this.editable){
11636             return;
11637         }
11638         
11639         this.collapse();
11640         
11641         Roo.log(this.store.reader.jsonData);
11642         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11643             // fixme
11644             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11645         }
11646         
11647         
11648     },
11649     // private
11650     onTypeAhead : function(){
11651         if(this.store.getCount() > 0){
11652             var r = this.store.getAt(0);
11653             var newValue = r.data[this.displayField];
11654             var len = newValue.length;
11655             var selStart = this.getRawValue().length;
11656             
11657             if(selStart != len){
11658                 this.setRawValue(newValue);
11659                 this.selectText(selStart, newValue.length);
11660             }
11661         }
11662     },
11663
11664     // private
11665     onSelect : function(record, index){
11666         
11667         if(this.fireEvent('beforeselect', this, record, index) !== false){
11668         
11669             this.setFromData(index > -1 ? record.data : false);
11670             
11671             this.collapse();
11672             this.fireEvent('select', this, record, index);
11673         }
11674     },
11675
11676     /**
11677      * Returns the currently selected field value or empty string if no value is set.
11678      * @return {String} value The selected value
11679      */
11680     getValue : function(){
11681         
11682         if(this.multiple){
11683             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11684         }
11685         
11686         if(this.valueField){
11687             return typeof this.value != 'undefined' ? this.value : '';
11688         }else{
11689             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11690         }
11691     },
11692
11693     /**
11694      * Clears any text/value currently set in the field
11695      */
11696     clearValue : function(){
11697         if(this.hiddenField){
11698             this.hiddenField.dom.value = '';
11699         }
11700         this.value = '';
11701         this.setRawValue('');
11702         this.lastSelectionText = '';
11703         this.lastData = false;
11704         
11705     },
11706
11707     /**
11708      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11709      * will be displayed in the field.  If the value does not match the data value of an existing item,
11710      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11711      * Otherwise the field will be blank (although the value will still be set).
11712      * @param {String} value The value to match
11713      */
11714     setValue : function(v){
11715         if(this.multiple){
11716             this.syncValue();
11717             return;
11718         }
11719         
11720         var text = v;
11721         if(this.valueField){
11722             var r = this.findRecord(this.valueField, v);
11723             if(r){
11724                 text = r.data[this.displayField];
11725             }else if(this.valueNotFoundText !== undefined){
11726                 text = this.valueNotFoundText;
11727             }
11728         }
11729         this.lastSelectionText = text;
11730         if(this.hiddenField){
11731             this.hiddenField.dom.value = v;
11732         }
11733         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11734         this.value = v;
11735     },
11736     /**
11737      * @property {Object} the last set data for the element
11738      */
11739     
11740     lastData : false,
11741     /**
11742      * Sets the value of the field based on a object which is related to the record format for the store.
11743      * @param {Object} value the value to set as. or false on reset?
11744      */
11745     setFromData : function(o){
11746         
11747         if(this.multiple){
11748             this.addItem(o);
11749             return;
11750         }
11751             
11752         var dv = ''; // display value
11753         var vv = ''; // value value..
11754         this.lastData = o;
11755         if (this.displayField) {
11756             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11757         } else {
11758             // this is an error condition!!!
11759             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11760         }
11761         
11762         if(this.valueField){
11763             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11764         }
11765         
11766         if(this.hiddenField){
11767             this.hiddenField.dom.value = vv;
11768             
11769             this.lastSelectionText = dv;
11770             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11771             this.value = vv;
11772             return;
11773         }
11774         // no hidden field.. - we store the value in 'value', but still display
11775         // display field!!!!
11776         this.lastSelectionText = dv;
11777         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11778         this.value = vv;
11779         
11780         
11781     },
11782     // private
11783     reset : function(){
11784         // overridden so that last data is reset..
11785         
11786         if(!this.multiple){
11787             this.clearItem();
11788             return;
11789         }
11790         
11791         this.setValue(this.originalValue);
11792         this.clearInvalid();
11793         this.lastData = false;
11794         if (this.view) {
11795             this.view.clearSelections();
11796         }
11797     },
11798     // private
11799     findRecord : function(prop, value){
11800         var record;
11801         if(this.store.getCount() > 0){
11802             this.store.each(function(r){
11803                 if(r.data[prop] == value){
11804                     record = r;
11805                     return false;
11806                 }
11807                 return true;
11808             });
11809         }
11810         return record;
11811     },
11812     
11813     getName: function()
11814     {
11815         // returns hidden if it's set..
11816         if (!this.rendered) {return ''};
11817         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11818         
11819     },
11820     // private
11821     onViewMove : function(e, t){
11822         this.inKeyMode = false;
11823     },
11824
11825     // private
11826     onViewOver : function(e, t){
11827         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11828             return;
11829         }
11830         var item = this.view.findItemFromChild(t);
11831         
11832         if(item){
11833             var index = this.view.indexOf(item);
11834             this.select(index, false);
11835         }
11836     },
11837
11838     // private
11839     onViewClick : function(view, doFocus, el, e)
11840     {
11841         var index = this.view.getSelectedIndexes()[0];
11842         
11843         var r = this.store.getAt(index);
11844         
11845         if(this.tickable){
11846             
11847             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11848                 return;
11849             }
11850             
11851             var rm = false;
11852             var _this = this;
11853             
11854             Roo.each(this.tickItems, function(v,k){
11855                 
11856                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11857                     _this.tickItems.splice(k, 1);
11858                     
11859                     if(typeof(e) == 'undefined' && view == false){
11860                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11861                     }
11862                     
11863                     rm = true;
11864                     return;
11865                 }
11866             });
11867             
11868             if(rm){
11869                 return;
11870             }
11871             
11872             this.tickItems.push(r.data);
11873             
11874             if(typeof(e) == 'undefined' && view == false){
11875                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11876             }
11877                     
11878             return;
11879         }
11880         
11881         if(r){
11882             this.onSelect(r, index);
11883         }
11884         if(doFocus !== false && !this.blockFocus){
11885             this.inputEl().focus();
11886         }
11887     },
11888
11889     // private
11890     restrictHeight : function(){
11891         //this.innerList.dom.style.height = '';
11892         //var inner = this.innerList.dom;
11893         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11894         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11895         //this.list.beginUpdate();
11896         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11897         this.list.alignTo(this.inputEl(), this.listAlign);
11898         this.list.alignTo(this.inputEl(), this.listAlign);
11899         //this.list.endUpdate();
11900     },
11901
11902     // private
11903     onEmptyResults : function(){
11904         
11905         if(this.tickable && this.editable){
11906             this.restrictHeight();
11907             return;
11908         }
11909         
11910         this.collapse();
11911     },
11912
11913     /**
11914      * Returns true if the dropdown list is expanded, else false.
11915      */
11916     isExpanded : function(){
11917         return this.list.isVisible();
11918     },
11919
11920     /**
11921      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11922      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11923      * @param {String} value The data value of the item to select
11924      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11925      * selected item if it is not currently in view (defaults to true)
11926      * @return {Boolean} True if the value matched an item in the list, else false
11927      */
11928     selectByValue : function(v, scrollIntoView){
11929         if(v !== undefined && v !== null){
11930             var r = this.findRecord(this.valueField || this.displayField, v);
11931             if(r){
11932                 this.select(this.store.indexOf(r), scrollIntoView);
11933                 return true;
11934             }
11935         }
11936         return false;
11937     },
11938
11939     /**
11940      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11941      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11942      * @param {Number} index The zero-based index of the list item to select
11943      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11944      * selected item if it is not currently in view (defaults to true)
11945      */
11946     select : function(index, scrollIntoView){
11947         this.selectedIndex = index;
11948         this.view.select(index);
11949         if(scrollIntoView !== false){
11950             var el = this.view.getNode(index);
11951             /*
11952              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11953              */
11954             if(el){
11955                 this.list.scrollChildIntoView(el, false);
11956             }
11957         }
11958     },
11959
11960     // private
11961     selectNext : function(){
11962         var ct = this.store.getCount();
11963         if(ct > 0){
11964             if(this.selectedIndex == -1){
11965                 this.select(0);
11966             }else if(this.selectedIndex < ct-1){
11967                 this.select(this.selectedIndex+1);
11968             }
11969         }
11970     },
11971
11972     // private
11973     selectPrev : function(){
11974         var ct = this.store.getCount();
11975         if(ct > 0){
11976             if(this.selectedIndex == -1){
11977                 this.select(0);
11978             }else if(this.selectedIndex != 0){
11979                 this.select(this.selectedIndex-1);
11980             }
11981         }
11982     },
11983
11984     // private
11985     onKeyUp : function(e){
11986         if(this.editable !== false && !e.isSpecialKey()){
11987             this.lastKey = e.getKey();
11988             this.dqTask.delay(this.queryDelay);
11989         }
11990     },
11991
11992     // private
11993     validateBlur : function(){
11994         return !this.list || !this.list.isVisible();   
11995     },
11996
11997     // private
11998     initQuery : function(){
11999         
12000         var v = this.getRawValue();
12001         
12002         if(this.tickable && this.editable){
12003             v = this.tickableInputEl().getValue();
12004         }
12005         
12006         this.doQuery(v);
12007     },
12008
12009     // private
12010     doForce : function(){
12011         if(this.inputEl().dom.value.length > 0){
12012             this.inputEl().dom.value =
12013                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12014              
12015         }
12016     },
12017
12018     /**
12019      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
12020      * query allowing the query action to be canceled if needed.
12021      * @param {String} query The SQL query to execute
12022      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12023      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
12024      * saved in the current store (defaults to false)
12025      */
12026     doQuery : function(q, forceAll){
12027         
12028         if(q === undefined || q === null){
12029             q = '';
12030         }
12031         var qe = {
12032             query: q,
12033             forceAll: forceAll,
12034             combo: this,
12035             cancel:false
12036         };
12037         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12038             return false;
12039         }
12040         q = qe.query;
12041         
12042         forceAll = qe.forceAll;
12043         if(forceAll === true || (q.length >= this.minChars)){
12044             
12045             this.hasQuery = true;
12046             
12047             if(this.lastQuery != q || this.alwaysQuery){
12048                 this.lastQuery = q;
12049                 if(this.mode == 'local'){
12050                     this.selectedIndex = -1;
12051                     if(forceAll){
12052                         this.store.clearFilter();
12053                     }else{
12054                         this.store.filter(this.displayField, q);
12055                     }
12056                     this.onLoad();
12057                 }else{
12058                     
12059                     this.store.baseParams[this.queryParam] = q;
12060                     
12061                     var options = {params : this.getParams(q)};
12062                     
12063                     if(this.loadNext){
12064                         options.add = true;
12065                         options.params.start = this.page * this.pageSize;
12066                     }
12067                     
12068                     this.store.load(options);
12069                     
12070                     /*
12071                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
12072                      *  we should expand the list on onLoad
12073                      *  so command out it
12074                      */
12075 //                    this.expand();
12076                 }
12077             }else{
12078                 this.selectedIndex = -1;
12079                 this.onLoad();   
12080             }
12081         }
12082         
12083         this.loadNext = false;
12084     },
12085
12086     // private
12087     getParams : function(q){
12088         var p = {};
12089         //p[this.queryParam] = q;
12090         
12091         if(this.pageSize){
12092             p.start = 0;
12093             p.limit = this.pageSize;
12094         }
12095         return p;
12096     },
12097
12098     /**
12099      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12100      */
12101     collapse : function(){
12102         if(!this.isExpanded()){
12103             return;
12104         }
12105         
12106         this.list.hide();
12107         
12108         if(this.tickable){
12109             this.hasFocus = false;
12110             this.okBtn.hide();
12111             this.cancelBtn.hide();
12112             this.trigger.show();
12113             
12114             if(this.editable){
12115                 this.tickableInputEl().dom.value = '';
12116                 this.tickableInputEl().blur();
12117             }
12118             
12119         }
12120         
12121         Roo.get(document).un('mousedown', this.collapseIf, this);
12122         Roo.get(document).un('mousewheel', this.collapseIf, this);
12123         if (!this.editable) {
12124             Roo.get(document).un('keydown', this.listKeyPress, this);
12125         }
12126         this.fireEvent('collapse', this);
12127     },
12128
12129     // private
12130     collapseIf : function(e){
12131         var in_combo  = e.within(this.el);
12132         var in_list =  e.within(this.list);
12133         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12134         
12135         if (in_combo || in_list || is_list) {
12136             //e.stopPropagation();
12137             return;
12138         }
12139         
12140         if(this.tickable){
12141             this.onTickableFooterButtonClick(e, false, false);
12142         }
12143
12144         this.collapse();
12145         
12146     },
12147
12148     /**
12149      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12150      */
12151     expand : function(){
12152        
12153         if(this.isExpanded() || !this.hasFocus){
12154             return;
12155         }
12156         
12157         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12158         this.list.setWidth(lw);
12159         
12160         
12161          Roo.log('expand');
12162         
12163         this.list.show();
12164         
12165         this.restrictHeight();
12166         
12167         if(this.tickable){
12168             
12169             this.tickItems = Roo.apply([], this.item);
12170             
12171             this.okBtn.show();
12172             this.cancelBtn.show();
12173             this.trigger.hide();
12174             
12175             if(this.editable){
12176                 this.tickableInputEl().focus();
12177             }
12178             
12179         }
12180         
12181         Roo.get(document).on('mousedown', this.collapseIf, this);
12182         Roo.get(document).on('mousewheel', this.collapseIf, this);
12183         if (!this.editable) {
12184             Roo.get(document).on('keydown', this.listKeyPress, this);
12185         }
12186         
12187         this.fireEvent('expand', this);
12188     },
12189
12190     // private
12191     // Implements the default empty TriggerField.onTriggerClick function
12192     onTriggerClick : function(e)
12193     {
12194         Roo.log('trigger click');
12195         
12196         if(this.disabled || !this.triggerList){
12197             return;
12198         }
12199         
12200         this.page = 0;
12201         this.loadNext = false;
12202         
12203         if(this.isExpanded()){
12204             this.collapse();
12205             if (!this.blockFocus) {
12206                 this.inputEl().focus();
12207             }
12208             
12209         }else {
12210             this.hasFocus = true;
12211             if(this.triggerAction == 'all') {
12212                 this.doQuery(this.allQuery, true);
12213             } else {
12214                 this.doQuery(this.getRawValue());
12215             }
12216             if (!this.blockFocus) {
12217                 this.inputEl().focus();
12218             }
12219         }
12220     },
12221     
12222     onTickableTriggerClick : function(e)
12223     {
12224         if(this.disabled){
12225             return;
12226         }
12227         
12228         this.page = 0;
12229         this.loadNext = false;
12230         this.hasFocus = true;
12231         
12232         if(this.triggerAction == 'all') {
12233             this.doQuery(this.allQuery, true);
12234         } else {
12235             this.doQuery(this.getRawValue());
12236         }
12237     },
12238     
12239     onSearchFieldClick : function(e)
12240     {
12241         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12242             this.onTickableFooterButtonClick(e, false, false);
12243             return;
12244         }
12245         
12246         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12247             return;
12248         }
12249         
12250         this.page = 0;
12251         this.loadNext = false;
12252         this.hasFocus = true;
12253         
12254         if(this.triggerAction == 'all') {
12255             this.doQuery(this.allQuery, true);
12256         } else {
12257             this.doQuery(this.getRawValue());
12258         }
12259     },
12260     
12261     listKeyPress : function(e)
12262     {
12263         //Roo.log('listkeypress');
12264         // scroll to first matching element based on key pres..
12265         if (e.isSpecialKey()) {
12266             return false;
12267         }
12268         var k = String.fromCharCode(e.getKey()).toUpperCase();
12269         //Roo.log(k);
12270         var match  = false;
12271         var csel = this.view.getSelectedNodes();
12272         var cselitem = false;
12273         if (csel.length) {
12274             var ix = this.view.indexOf(csel[0]);
12275             cselitem  = this.store.getAt(ix);
12276             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12277                 cselitem = false;
12278             }
12279             
12280         }
12281         
12282         this.store.each(function(v) { 
12283             if (cselitem) {
12284                 // start at existing selection.
12285                 if (cselitem.id == v.id) {
12286                     cselitem = false;
12287                 }
12288                 return true;
12289             }
12290                 
12291             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12292                 match = this.store.indexOf(v);
12293                 return false;
12294             }
12295             return true;
12296         }, this);
12297         
12298         if (match === false) {
12299             return true; // no more action?
12300         }
12301         // scroll to?
12302         this.view.select(match);
12303         var sn = Roo.get(this.view.getSelectedNodes()[0])
12304         sn.scrollIntoView(sn.dom.parentNode, false);
12305     },
12306     
12307     onViewScroll : function(e, t){
12308         
12309         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){
12310             return;
12311         }
12312         
12313         this.hasQuery = true;
12314         
12315         this.loading = this.list.select('.loading', true).first();
12316         
12317         if(this.loading === null){
12318             this.list.createChild({
12319                 tag: 'div',
12320                 cls: 'loading select2-more-results select2-active',
12321                 html: 'Loading more results...'
12322             })
12323             
12324             this.loading = this.list.select('.loading', true).first();
12325             
12326             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12327             
12328             this.loading.hide();
12329         }
12330         
12331         this.loading.show();
12332         
12333         var _combo = this;
12334         
12335         this.page++;
12336         this.loadNext = true;
12337         
12338         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12339         
12340         return;
12341     },
12342     
12343     addItem : function(o)
12344     {   
12345         var dv = ''; // display value
12346         
12347         if (this.displayField) {
12348             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12349         } else {
12350             // this is an error condition!!!
12351             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12352         }
12353         
12354         if(!dv.length){
12355             return;
12356         }
12357         
12358         var choice = this.choices.createChild({
12359             tag: 'li',
12360             cls: 'select2-search-choice',
12361             cn: [
12362                 {
12363                     tag: 'div',
12364                     html: dv
12365                 },
12366                 {
12367                     tag: 'a',
12368                     href: '#',
12369                     cls: 'select2-search-choice-close',
12370                     tabindex: '-1'
12371                 }
12372             ]
12373             
12374         }, this.searchField);
12375         
12376         var close = choice.select('a.select2-search-choice-close', true).first()
12377         
12378         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12379         
12380         this.item.push(o);
12381         
12382         this.lastData = o;
12383         
12384         this.syncValue();
12385         
12386         this.inputEl().dom.value = '';
12387         
12388         this.validate();
12389     },
12390     
12391     onRemoveItem : function(e, _self, o)
12392     {
12393         e.preventDefault();
12394         
12395         this.lastItem = Roo.apply([], this.item);
12396         
12397         var index = this.item.indexOf(o.data) * 1;
12398         
12399         if( index < 0){
12400             Roo.log('not this item?!');
12401             return;
12402         }
12403         
12404         this.item.splice(index, 1);
12405         o.item.remove();
12406         
12407         this.syncValue();
12408         
12409         this.fireEvent('remove', this, e);
12410         
12411         this.validate();
12412         
12413     },
12414     
12415     syncValue : function()
12416     {
12417         if(!this.item.length){
12418             this.clearValue();
12419             return;
12420         }
12421             
12422         var value = [];
12423         var _this = this;
12424         Roo.each(this.item, function(i){
12425             if(_this.valueField){
12426                 value.push(i[_this.valueField]);
12427                 return;
12428             }
12429
12430             value.push(i);
12431         });
12432
12433         this.value = value.join(',');
12434
12435         if(this.hiddenField){
12436             this.hiddenField.dom.value = this.value;
12437         }
12438     },
12439     
12440     clearItem : function()
12441     {
12442         if(!this.multiple){
12443             return;
12444         }
12445         
12446         this.item = [];
12447         
12448         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12449            c.remove();
12450         });
12451         
12452         this.syncValue();
12453         
12454         this.validate();
12455     },
12456     
12457     inputEl: function ()
12458     {
12459         if(this.tickable){
12460             return this.searchField;
12461         }
12462         return this.el.select('input.form-control',true).first();
12463     },
12464     
12465     
12466     onTickableFooterButtonClick : function(e, btn, el)
12467     {
12468         e.preventDefault();
12469         
12470         this.lastItem = Roo.apply([], this.item);
12471         
12472         if(btn && btn.name == 'cancel'){
12473             this.tickItems = Roo.apply([], this.item);
12474             this.collapse();
12475             return;
12476         }
12477         
12478         this.clearItem();
12479         
12480         var _this = this;
12481         
12482         Roo.each(this.tickItems, function(o){
12483             _this.addItem(o);
12484         });
12485         
12486         this.collapse();
12487         
12488     },
12489     
12490     validate : function()
12491     {
12492         var v = this.getRawValue();
12493         
12494         if(this.multiple){
12495             v = this.getValue();
12496         }
12497         
12498         if(this.disabled || this.allowBlank || v.length){
12499             this.markValid();
12500             return true;
12501         }
12502         
12503         this.markInvalid();
12504         return false;
12505     },
12506     
12507     tickableInputEl : function()
12508     {
12509         if(!this.tickable || !this.editable){
12510             return this.inputEl();
12511         }
12512         
12513         return this.inputEl().select('.select2-search-field-input', true).first();
12514     }
12515     
12516     
12517
12518     /** 
12519     * @cfg {Boolean} grow 
12520     * @hide 
12521     */
12522     /** 
12523     * @cfg {Number} growMin 
12524     * @hide 
12525     */
12526     /** 
12527     * @cfg {Number} growMax 
12528     * @hide 
12529     */
12530     /**
12531      * @hide
12532      * @method autoSize
12533      */
12534 });
12535 /*
12536  * Based on:
12537  * Ext JS Library 1.1.1
12538  * Copyright(c) 2006-2007, Ext JS, LLC.
12539  *
12540  * Originally Released Under LGPL - original licence link has changed is not relivant.
12541  *
12542  * Fork - LGPL
12543  * <script type="text/javascript">
12544  */
12545
12546 /**
12547  * @class Roo.View
12548  * @extends Roo.util.Observable
12549  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12550  * This class also supports single and multi selection modes. <br>
12551  * Create a data model bound view:
12552  <pre><code>
12553  var store = new Roo.data.Store(...);
12554
12555  var view = new Roo.View({
12556     el : "my-element",
12557     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12558  
12559     singleSelect: true,
12560     selectedClass: "ydataview-selected",
12561     store: store
12562  });
12563
12564  // listen for node click?
12565  view.on("click", function(vw, index, node, e){
12566  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12567  });
12568
12569  // load XML data
12570  dataModel.load("foobar.xml");
12571  </code></pre>
12572  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12573  * <br><br>
12574  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12575  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12576  * 
12577  * Note: old style constructor is still suported (container, template, config)
12578  * 
12579  * @constructor
12580  * Create a new View
12581  * @param {Object} config The config object
12582  * 
12583  */
12584 Roo.View = function(config, depreciated_tpl, depreciated_config){
12585     
12586     this.parent = false;
12587     
12588     if (typeof(depreciated_tpl) == 'undefined') {
12589         // new way.. - universal constructor.
12590         Roo.apply(this, config);
12591         this.el  = Roo.get(this.el);
12592     } else {
12593         // old format..
12594         this.el  = Roo.get(config);
12595         this.tpl = depreciated_tpl;
12596         Roo.apply(this, depreciated_config);
12597     }
12598     this.wrapEl  = this.el.wrap().wrap();
12599     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12600     
12601     
12602     if(typeof(this.tpl) == "string"){
12603         this.tpl = new Roo.Template(this.tpl);
12604     } else {
12605         // support xtype ctors..
12606         this.tpl = new Roo.factory(this.tpl, Roo);
12607     }
12608     
12609     
12610     this.tpl.compile();
12611     
12612     /** @private */
12613     this.addEvents({
12614         /**
12615          * @event beforeclick
12616          * Fires before a click is processed. Returns false to cancel the default action.
12617          * @param {Roo.View} this
12618          * @param {Number} index The index of the target node
12619          * @param {HTMLElement} node The target node
12620          * @param {Roo.EventObject} e The raw event object
12621          */
12622             "beforeclick" : true,
12623         /**
12624          * @event click
12625          * Fires when a template node is clicked.
12626          * @param {Roo.View} this
12627          * @param {Number} index The index of the target node
12628          * @param {HTMLElement} node The target node
12629          * @param {Roo.EventObject} e The raw event object
12630          */
12631             "click" : true,
12632         /**
12633          * @event dblclick
12634          * Fires when a template node is double clicked.
12635          * @param {Roo.View} this
12636          * @param {Number} index The index of the target node
12637          * @param {HTMLElement} node The target node
12638          * @param {Roo.EventObject} e The raw event object
12639          */
12640             "dblclick" : true,
12641         /**
12642          * @event contextmenu
12643          * Fires when a template node is right clicked.
12644          * @param {Roo.View} this
12645          * @param {Number} index The index of the target node
12646          * @param {HTMLElement} node The target node
12647          * @param {Roo.EventObject} e The raw event object
12648          */
12649             "contextmenu" : true,
12650         /**
12651          * @event selectionchange
12652          * Fires when the selected nodes change.
12653          * @param {Roo.View} this
12654          * @param {Array} selections Array of the selected nodes
12655          */
12656             "selectionchange" : true,
12657     
12658         /**
12659          * @event beforeselect
12660          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12661          * @param {Roo.View} this
12662          * @param {HTMLElement} node The node to be selected
12663          * @param {Array} selections Array of currently selected nodes
12664          */
12665             "beforeselect" : true,
12666         /**
12667          * @event preparedata
12668          * Fires on every row to render, to allow you to change the data.
12669          * @param {Roo.View} this
12670          * @param {Object} data to be rendered (change this)
12671          */
12672           "preparedata" : true
12673           
12674           
12675         });
12676
12677
12678
12679     this.el.on({
12680         "click": this.onClick,
12681         "dblclick": this.onDblClick,
12682         "contextmenu": this.onContextMenu,
12683         scope:this
12684     });
12685
12686     this.selections = [];
12687     this.nodes = [];
12688     this.cmp = new Roo.CompositeElementLite([]);
12689     if(this.store){
12690         this.store = Roo.factory(this.store, Roo.data);
12691         this.setStore(this.store, true);
12692     }
12693     
12694     if ( this.footer && this.footer.xtype) {
12695            
12696          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12697         
12698         this.footer.dataSource = this.store
12699         this.footer.container = fctr;
12700         this.footer = Roo.factory(this.footer, Roo);
12701         fctr.insertFirst(this.el);
12702         
12703         // this is a bit insane - as the paging toolbar seems to detach the el..
12704 //        dom.parentNode.parentNode.parentNode
12705          // they get detached?
12706     }
12707     
12708     
12709     Roo.View.superclass.constructor.call(this);
12710     
12711     
12712 };
12713
12714 Roo.extend(Roo.View, Roo.util.Observable, {
12715     
12716      /**
12717      * @cfg {Roo.data.Store} store Data store to load data from.
12718      */
12719     store : false,
12720     
12721     /**
12722      * @cfg {String|Roo.Element} el The container element.
12723      */
12724     el : '',
12725     
12726     /**
12727      * @cfg {String|Roo.Template} tpl The template used by this View 
12728      */
12729     tpl : false,
12730     /**
12731      * @cfg {String} dataName the named area of the template to use as the data area
12732      *                          Works with domtemplates roo-name="name"
12733      */
12734     dataName: false,
12735     /**
12736      * @cfg {String} selectedClass The css class to add to selected nodes
12737      */
12738     selectedClass : "x-view-selected",
12739      /**
12740      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12741      */
12742     emptyText : "",
12743     
12744     /**
12745      * @cfg {String} text to display on mask (default Loading)
12746      */
12747     mask : false,
12748     /**
12749      * @cfg {Boolean} multiSelect Allow multiple selection
12750      */
12751     multiSelect : false,
12752     /**
12753      * @cfg {Boolean} singleSelect Allow single selection
12754      */
12755     singleSelect:  false,
12756     
12757     /**
12758      * @cfg {Boolean} toggleSelect - selecting 
12759      */
12760     toggleSelect : false,
12761     
12762     /**
12763      * @cfg {Boolean} tickable - selecting 
12764      */
12765     tickable : false,
12766     
12767     /**
12768      * Returns the element this view is bound to.
12769      * @return {Roo.Element}
12770      */
12771     getEl : function(){
12772         return this.wrapEl;
12773     },
12774     
12775     
12776
12777     /**
12778      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12779      */
12780     refresh : function(){
12781         //Roo.log('refresh');
12782         var t = this.tpl;
12783         
12784         // if we are using something like 'domtemplate', then
12785         // the what gets used is:
12786         // t.applySubtemplate(NAME, data, wrapping data..)
12787         // the outer template then get' applied with
12788         //     the store 'extra data'
12789         // and the body get's added to the
12790         //      roo-name="data" node?
12791         //      <span class='roo-tpl-{name}'></span> ?????
12792         
12793         
12794         
12795         this.clearSelections();
12796         this.el.update("");
12797         var html = [];
12798         var records = this.store.getRange();
12799         if(records.length < 1) {
12800             
12801             // is this valid??  = should it render a template??
12802             
12803             this.el.update(this.emptyText);
12804             return;
12805         }
12806         var el = this.el;
12807         if (this.dataName) {
12808             this.el.update(t.apply(this.store.meta)); //????
12809             el = this.el.child('.roo-tpl-' + this.dataName);
12810         }
12811         
12812         for(var i = 0, len = records.length; i < len; i++){
12813             var data = this.prepareData(records[i].data, i, records[i]);
12814             this.fireEvent("preparedata", this, data, i, records[i]);
12815             
12816             var d = Roo.apply({}, data);
12817             
12818             if(this.tickable){
12819                 Roo.apply(d, {'roo-id' : Roo.id()});
12820                 
12821                 var _this = this;
12822             
12823                 Roo.each(this.parent.item, function(item){
12824                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12825                         return;
12826                     }
12827                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12828                 });
12829             }
12830             
12831             html[html.length] = Roo.util.Format.trim(
12832                 this.dataName ?
12833                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12834                     t.apply(d)
12835             );
12836         }
12837         
12838         
12839         
12840         el.update(html.join(""));
12841         this.nodes = el.dom.childNodes;
12842         this.updateIndexes(0);
12843     },
12844     
12845
12846     /**
12847      * Function to override to reformat the data that is sent to
12848      * the template for each node.
12849      * DEPRICATED - use the preparedata event handler.
12850      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12851      * a JSON object for an UpdateManager bound view).
12852      */
12853     prepareData : function(data, index, record)
12854     {
12855         this.fireEvent("preparedata", this, data, index, record);
12856         return data;
12857     },
12858
12859     onUpdate : function(ds, record){
12860         // Roo.log('on update');   
12861         this.clearSelections();
12862         var index = this.store.indexOf(record);
12863         var n = this.nodes[index];
12864         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12865         n.parentNode.removeChild(n);
12866         this.updateIndexes(index, index);
12867     },
12868
12869     
12870     
12871 // --------- FIXME     
12872     onAdd : function(ds, records, index)
12873     {
12874         //Roo.log(['on Add', ds, records, index] );        
12875         this.clearSelections();
12876         if(this.nodes.length == 0){
12877             this.refresh();
12878             return;
12879         }
12880         var n = this.nodes[index];
12881         for(var i = 0, len = records.length; i < len; i++){
12882             var d = this.prepareData(records[i].data, i, records[i]);
12883             if(n){
12884                 this.tpl.insertBefore(n, d);
12885             }else{
12886                 
12887                 this.tpl.append(this.el, d);
12888             }
12889         }
12890         this.updateIndexes(index);
12891     },
12892
12893     onRemove : function(ds, record, index){
12894        // Roo.log('onRemove');
12895         this.clearSelections();
12896         var el = this.dataName  ?
12897             this.el.child('.roo-tpl-' + this.dataName) :
12898             this.el; 
12899         
12900         el.dom.removeChild(this.nodes[index]);
12901         this.updateIndexes(index);
12902     },
12903
12904     /**
12905      * Refresh an individual node.
12906      * @param {Number} index
12907      */
12908     refreshNode : function(index){
12909         this.onUpdate(this.store, this.store.getAt(index));
12910     },
12911
12912     updateIndexes : function(startIndex, endIndex){
12913         var ns = this.nodes;
12914         startIndex = startIndex || 0;
12915         endIndex = endIndex || ns.length - 1;
12916         for(var i = startIndex; i <= endIndex; i++){
12917             ns[i].nodeIndex = i;
12918         }
12919     },
12920
12921     /**
12922      * Changes the data store this view uses and refresh the view.
12923      * @param {Store} store
12924      */
12925     setStore : function(store, initial){
12926         if(!initial && this.store){
12927             this.store.un("datachanged", this.refresh);
12928             this.store.un("add", this.onAdd);
12929             this.store.un("remove", this.onRemove);
12930             this.store.un("update", this.onUpdate);
12931             this.store.un("clear", this.refresh);
12932             this.store.un("beforeload", this.onBeforeLoad);
12933             this.store.un("load", this.onLoad);
12934             this.store.un("loadexception", this.onLoad);
12935         }
12936         if(store){
12937           
12938             store.on("datachanged", this.refresh, this);
12939             store.on("add", this.onAdd, this);
12940             store.on("remove", this.onRemove, this);
12941             store.on("update", this.onUpdate, this);
12942             store.on("clear", this.refresh, this);
12943             store.on("beforeload", this.onBeforeLoad, this);
12944             store.on("load", this.onLoad, this);
12945             store.on("loadexception", this.onLoad, this);
12946         }
12947         
12948         if(store){
12949             this.refresh();
12950         }
12951     },
12952     /**
12953      * onbeforeLoad - masks the loading area.
12954      *
12955      */
12956     onBeforeLoad : function(store,opts)
12957     {
12958          //Roo.log('onBeforeLoad');   
12959         if (!opts.add) {
12960             this.el.update("");
12961         }
12962         this.el.mask(this.mask ? this.mask : "Loading" ); 
12963     },
12964     onLoad : function ()
12965     {
12966         this.el.unmask();
12967     },
12968     
12969
12970     /**
12971      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12972      * @param {HTMLElement} node
12973      * @return {HTMLElement} The template node
12974      */
12975     findItemFromChild : function(node){
12976         var el = this.dataName  ?
12977             this.el.child('.roo-tpl-' + this.dataName,true) :
12978             this.el.dom; 
12979         
12980         if(!node || node.parentNode == el){
12981                     return node;
12982             }
12983             var p = node.parentNode;
12984             while(p && p != el){
12985             if(p.parentNode == el){
12986                 return p;
12987             }
12988             p = p.parentNode;
12989         }
12990             return null;
12991     },
12992
12993     /** @ignore */
12994     onClick : function(e){
12995         var item = this.findItemFromChild(e.getTarget());
12996         if(item){
12997             var index = this.indexOf(item);
12998             if(this.onItemClick(item, index, e) !== false){
12999                 this.fireEvent("click", this, index, item, e);
13000             }
13001         }else{
13002             this.clearSelections();
13003         }
13004     },
13005
13006     /** @ignore */
13007     onContextMenu : function(e){
13008         var item = this.findItemFromChild(e.getTarget());
13009         if(item){
13010             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13011         }
13012     },
13013
13014     /** @ignore */
13015     onDblClick : function(e){
13016         var item = this.findItemFromChild(e.getTarget());
13017         if(item){
13018             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13019         }
13020     },
13021
13022     onItemClick : function(item, index, e)
13023     {
13024         if(this.fireEvent("beforeclick", this, index, item, e) === false){
13025             return false;
13026         }
13027         if (this.toggleSelect) {
13028             var m = this.isSelected(item) ? 'unselect' : 'select';
13029             //Roo.log(m);
13030             var _t = this;
13031             _t[m](item, true, false);
13032             return true;
13033         }
13034         if(this.multiSelect || this.singleSelect){
13035             if(this.multiSelect && e.shiftKey && this.lastSelection){
13036                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13037             }else{
13038                 this.select(item, this.multiSelect && e.ctrlKey);
13039                 this.lastSelection = item;
13040             }
13041             
13042             if(!this.tickable){
13043                 e.preventDefault();
13044             }
13045             
13046         }
13047         return true;
13048     },
13049
13050     /**
13051      * Get the number of selected nodes.
13052      * @return {Number}
13053      */
13054     getSelectionCount : function(){
13055         return this.selections.length;
13056     },
13057
13058     /**
13059      * Get the currently selected nodes.
13060      * @return {Array} An array of HTMLElements
13061      */
13062     getSelectedNodes : function(){
13063         return this.selections;
13064     },
13065
13066     /**
13067      * Get the indexes of the selected nodes.
13068      * @return {Array}
13069      */
13070     getSelectedIndexes : function(){
13071         var indexes = [], s = this.selections;
13072         for(var i = 0, len = s.length; i < len; i++){
13073             indexes.push(s[i].nodeIndex);
13074         }
13075         return indexes;
13076     },
13077
13078     /**
13079      * Clear all selections
13080      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13081      */
13082     clearSelections : function(suppressEvent){
13083         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13084             this.cmp.elements = this.selections;
13085             this.cmp.removeClass(this.selectedClass);
13086             this.selections = [];
13087             if(!suppressEvent){
13088                 this.fireEvent("selectionchange", this, this.selections);
13089             }
13090         }
13091     },
13092
13093     /**
13094      * Returns true if the passed node is selected
13095      * @param {HTMLElement/Number} node The node or node index
13096      * @return {Boolean}
13097      */
13098     isSelected : function(node){
13099         var s = this.selections;
13100         if(s.length < 1){
13101             return false;
13102         }
13103         node = this.getNode(node);
13104         return s.indexOf(node) !== -1;
13105     },
13106
13107     /**
13108      * Selects nodes.
13109      * @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
13110      * @param {Boolean} keepExisting (optional) true to keep existing selections
13111      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13112      */
13113     select : function(nodeInfo, keepExisting, suppressEvent){
13114         if(nodeInfo instanceof Array){
13115             if(!keepExisting){
13116                 this.clearSelections(true);
13117             }
13118             for(var i = 0, len = nodeInfo.length; i < len; i++){
13119                 this.select(nodeInfo[i], true, true);
13120             }
13121             return;
13122         } 
13123         var node = this.getNode(nodeInfo);
13124         if(!node || this.isSelected(node)){
13125             return; // already selected.
13126         }
13127         if(!keepExisting){
13128             this.clearSelections(true);
13129         }
13130         
13131         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13132             Roo.fly(node).addClass(this.selectedClass);
13133             this.selections.push(node);
13134             if(!suppressEvent){
13135                 this.fireEvent("selectionchange", this, this.selections);
13136             }
13137         }
13138         
13139         
13140     },
13141       /**
13142      * Unselects nodes.
13143      * @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
13144      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13145      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13146      */
13147     unselect : function(nodeInfo, keepExisting, suppressEvent)
13148     {
13149         if(nodeInfo instanceof Array){
13150             Roo.each(this.selections, function(s) {
13151                 this.unselect(s, nodeInfo);
13152             }, this);
13153             return;
13154         }
13155         var node = this.getNode(nodeInfo);
13156         if(!node || !this.isSelected(node)){
13157             //Roo.log("not selected");
13158             return; // not selected.
13159         }
13160         // fireevent???
13161         var ns = [];
13162         Roo.each(this.selections, function(s) {
13163             if (s == node ) {
13164                 Roo.fly(node).removeClass(this.selectedClass);
13165
13166                 return;
13167             }
13168             ns.push(s);
13169         },this);
13170         
13171         this.selections= ns;
13172         this.fireEvent("selectionchange", this, this.selections);
13173     },
13174
13175     /**
13176      * Gets a template node.
13177      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13178      * @return {HTMLElement} The node or null if it wasn't found
13179      */
13180     getNode : function(nodeInfo){
13181         if(typeof nodeInfo == "string"){
13182             return document.getElementById(nodeInfo);
13183         }else if(typeof nodeInfo == "number"){
13184             return this.nodes[nodeInfo];
13185         }
13186         return nodeInfo;
13187     },
13188
13189     /**
13190      * Gets a range template nodes.
13191      * @param {Number} startIndex
13192      * @param {Number} endIndex
13193      * @return {Array} An array of nodes
13194      */
13195     getNodes : function(start, end){
13196         var ns = this.nodes;
13197         start = start || 0;
13198         end = typeof end == "undefined" ? ns.length - 1 : end;
13199         var nodes = [];
13200         if(start <= end){
13201             for(var i = start; i <= end; i++){
13202                 nodes.push(ns[i]);
13203             }
13204         } else{
13205             for(var i = start; i >= end; i--){
13206                 nodes.push(ns[i]);
13207             }
13208         }
13209         return nodes;
13210     },
13211
13212     /**
13213      * Finds the index of the passed node
13214      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13215      * @return {Number} The index of the node or -1
13216      */
13217     indexOf : function(node){
13218         node = this.getNode(node);
13219         if(typeof node.nodeIndex == "number"){
13220             return node.nodeIndex;
13221         }
13222         var ns = this.nodes;
13223         for(var i = 0, len = ns.length; i < len; i++){
13224             if(ns[i] == node){
13225                 return i;
13226             }
13227         }
13228         return -1;
13229     }
13230 });
13231 /*
13232  * - LGPL
13233  *
13234  * based on jquery fullcalendar
13235  * 
13236  */
13237
13238 Roo.bootstrap = Roo.bootstrap || {};
13239 /**
13240  * @class Roo.bootstrap.Calendar
13241  * @extends Roo.bootstrap.Component
13242  * Bootstrap Calendar class
13243  * @cfg {Boolean} loadMask (true|false) default false
13244  * @cfg {Object} header generate the user specific header of the calendar, default false
13245
13246  * @constructor
13247  * Create a new Container
13248  * @param {Object} config The config object
13249  */
13250
13251
13252
13253 Roo.bootstrap.Calendar = function(config){
13254     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13255      this.addEvents({
13256         /**
13257              * @event select
13258              * Fires when a date is selected
13259              * @param {DatePicker} this
13260              * @param {Date} date The selected date
13261              */
13262         'select': true,
13263         /**
13264              * @event monthchange
13265              * Fires when the displayed month changes 
13266              * @param {DatePicker} this
13267              * @param {Date} date The selected month
13268              */
13269         'monthchange': true,
13270         /**
13271              * @event evententer
13272              * Fires when mouse over an event
13273              * @param {Calendar} this
13274              * @param {event} Event
13275              */
13276         'evententer': true,
13277         /**
13278              * @event eventleave
13279              * Fires when the mouse leaves an
13280              * @param {Calendar} this
13281              * @param {event}
13282              */
13283         'eventleave': true,
13284         /**
13285              * @event eventclick
13286              * Fires when the mouse click an
13287              * @param {Calendar} this
13288              * @param {event}
13289              */
13290         'eventclick': true
13291         
13292     });
13293
13294 };
13295
13296 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13297     
13298      /**
13299      * @cfg {Number} startDay
13300      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13301      */
13302     startDay : 0,
13303     
13304     loadMask : false,
13305     
13306     header : false,
13307       
13308     getAutoCreate : function(){
13309         
13310         
13311         var fc_button = function(name, corner, style, content ) {
13312             return Roo.apply({},{
13313                 tag : 'span',
13314                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13315                          (corner.length ?
13316                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13317                             ''
13318                         ),
13319                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13320                 unselectable: 'on'
13321             });
13322         };
13323         
13324         var header = {};
13325         
13326         if(!this.header){
13327             header = {
13328                 tag : 'table',
13329                 cls : 'fc-header',
13330                 style : 'width:100%',
13331                 cn : [
13332                     {
13333                         tag: 'tr',
13334                         cn : [
13335                             {
13336                                 tag : 'td',
13337                                 cls : 'fc-header-left',
13338                                 cn : [
13339                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13340                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13341                                     { tag: 'span', cls: 'fc-header-space' },
13342                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13343
13344
13345                                 ]
13346                             },
13347
13348                             {
13349                                 tag : 'td',
13350                                 cls : 'fc-header-center',
13351                                 cn : [
13352                                     {
13353                                         tag: 'span',
13354                                         cls: 'fc-header-title',
13355                                         cn : {
13356                                             tag: 'H2',
13357                                             html : 'month / year'
13358                                         }
13359                                     }
13360
13361                                 ]
13362                             },
13363                             {
13364                                 tag : 'td',
13365                                 cls : 'fc-header-right',
13366                                 cn : [
13367                               /*      fc_button('month', 'left', '', 'month' ),
13368                                     fc_button('week', '', '', 'week' ),
13369                                     fc_button('day', 'right', '', 'day' )
13370                                 */    
13371
13372                                 ]
13373                             }
13374
13375                         ]
13376                     }
13377                 ]
13378             };
13379         }
13380         
13381         header = this.header;
13382         
13383        
13384         var cal_heads = function() {
13385             var ret = [];
13386             // fixme - handle this.
13387             
13388             for (var i =0; i < Date.dayNames.length; i++) {
13389                 var d = Date.dayNames[i];
13390                 ret.push({
13391                     tag: 'th',
13392                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13393                     html : d.substring(0,3)
13394                 });
13395                 
13396             }
13397             ret[0].cls += ' fc-first';
13398             ret[6].cls += ' fc-last';
13399             return ret;
13400         };
13401         var cal_cell = function(n) {
13402             return  {
13403                 tag: 'td',
13404                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13405                 cn : [
13406                     {
13407                         cn : [
13408                             {
13409                                 cls: 'fc-day-number',
13410                                 html: 'D'
13411                             },
13412                             {
13413                                 cls: 'fc-day-content',
13414                              
13415                                 cn : [
13416                                      {
13417                                         style: 'position: relative;' // height: 17px;
13418                                     }
13419                                 ]
13420                             }
13421                             
13422                             
13423                         ]
13424                     }
13425                 ]
13426                 
13427             }
13428         };
13429         var cal_rows = function() {
13430             
13431             var ret = [];
13432             for (var r = 0; r < 6; r++) {
13433                 var row= {
13434                     tag : 'tr',
13435                     cls : 'fc-week',
13436                     cn : []
13437                 };
13438                 
13439                 for (var i =0; i < Date.dayNames.length; i++) {
13440                     var d = Date.dayNames[i];
13441                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13442
13443                 }
13444                 row.cn[0].cls+=' fc-first';
13445                 row.cn[0].cn[0].style = 'min-height:90px';
13446                 row.cn[6].cls+=' fc-last';
13447                 ret.push(row);
13448                 
13449             }
13450             ret[0].cls += ' fc-first';
13451             ret[4].cls += ' fc-prev-last';
13452             ret[5].cls += ' fc-last';
13453             return ret;
13454             
13455         };
13456         
13457         var cal_table = {
13458             tag: 'table',
13459             cls: 'fc-border-separate',
13460             style : 'width:100%',
13461             cellspacing  : 0,
13462             cn : [
13463                 { 
13464                     tag: 'thead',
13465                     cn : [
13466                         { 
13467                             tag: 'tr',
13468                             cls : 'fc-first fc-last',
13469                             cn : cal_heads()
13470                         }
13471                     ]
13472                 },
13473                 { 
13474                     tag: 'tbody',
13475                     cn : cal_rows()
13476                 }
13477                   
13478             ]
13479         };
13480          
13481          var cfg = {
13482             cls : 'fc fc-ltr',
13483             cn : [
13484                 header,
13485                 {
13486                     cls : 'fc-content',
13487                     style : "position: relative;",
13488                     cn : [
13489                         {
13490                             cls : 'fc-view fc-view-month fc-grid',
13491                             style : 'position: relative',
13492                             unselectable : 'on',
13493                             cn : [
13494                                 {
13495                                     cls : 'fc-event-container',
13496                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13497                                 },
13498                                 cal_table
13499                             ]
13500                         }
13501                     ]
13502     
13503                 }
13504            ] 
13505             
13506         };
13507         
13508          
13509         
13510         return cfg;
13511     },
13512     
13513     
13514     initEvents : function()
13515     {
13516         if(!this.store){
13517             throw "can not find store for calendar";
13518         }
13519         
13520         var mark = {
13521             tag: "div",
13522             cls:"x-dlg-mask",
13523             style: "text-align:center",
13524             cn: [
13525                 {
13526                     tag: "div",
13527                     style: "background-color:white;width:50%;margin:250 auto",
13528                     cn: [
13529                         {
13530                             tag: "img",
13531                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13532                         },
13533                         {
13534                             tag: "span",
13535                             html: "Loading"
13536                         }
13537                         
13538                     ]
13539                 }
13540             ]
13541         }
13542         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13543         
13544         var size = this.el.select('.fc-content', true).first().getSize();
13545         this.maskEl.setSize(size.width, size.height);
13546         this.maskEl.enableDisplayMode("block");
13547         if(!this.loadMask){
13548             this.maskEl.hide();
13549         }
13550         
13551         this.store = Roo.factory(this.store, Roo.data);
13552         this.store.on('load', this.onLoad, this);
13553         this.store.on('beforeload', this.onBeforeLoad, this);
13554         
13555         this.resize();
13556         
13557         this.cells = this.el.select('.fc-day',true);
13558         //Roo.log(this.cells);
13559         this.textNodes = this.el.query('.fc-day-number');
13560         this.cells.addClassOnOver('fc-state-hover');
13561         
13562         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13563         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13564         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13565         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13566         
13567         this.on('monthchange', this.onMonthChange, this);
13568         
13569         this.update(new Date().clearTime());
13570     },
13571     
13572     resize : function() {
13573         var sz  = this.el.getSize();
13574         
13575         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13576         this.el.select('.fc-day-content div',true).setHeight(34);
13577     },
13578     
13579     
13580     // private
13581     showPrevMonth : function(e){
13582         this.update(this.activeDate.add("mo", -1));
13583     },
13584     showToday : function(e){
13585         this.update(new Date().clearTime());
13586     },
13587     // private
13588     showNextMonth : function(e){
13589         this.update(this.activeDate.add("mo", 1));
13590     },
13591
13592     // private
13593     showPrevYear : function(){
13594         this.update(this.activeDate.add("y", -1));
13595     },
13596
13597     // private
13598     showNextYear : function(){
13599         this.update(this.activeDate.add("y", 1));
13600     },
13601
13602     
13603    // private
13604     update : function(date)
13605     {
13606         var vd = this.activeDate;
13607         this.activeDate = date;
13608 //        if(vd && this.el){
13609 //            var t = date.getTime();
13610 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13611 //                Roo.log('using add remove');
13612 //                
13613 //                this.fireEvent('monthchange', this, date);
13614 //                
13615 //                this.cells.removeClass("fc-state-highlight");
13616 //                this.cells.each(function(c){
13617 //                   if(c.dateValue == t){
13618 //                       c.addClass("fc-state-highlight");
13619 //                       setTimeout(function(){
13620 //                            try{c.dom.firstChild.focus();}catch(e){}
13621 //                       }, 50);
13622 //                       return false;
13623 //                   }
13624 //                   return true;
13625 //                });
13626 //                return;
13627 //            }
13628 //        }
13629         
13630         var days = date.getDaysInMonth();
13631         
13632         var firstOfMonth = date.getFirstDateOfMonth();
13633         var startingPos = firstOfMonth.getDay()-this.startDay;
13634         
13635         if(startingPos < this.startDay){
13636             startingPos += 7;
13637         }
13638         
13639         var pm = date.add(Date.MONTH, -1);
13640         var prevStart = pm.getDaysInMonth()-startingPos;
13641 //        
13642         this.cells = this.el.select('.fc-day',true);
13643         this.textNodes = this.el.query('.fc-day-number');
13644         this.cells.addClassOnOver('fc-state-hover');
13645         
13646         var cells = this.cells.elements;
13647         var textEls = this.textNodes;
13648         
13649         Roo.each(cells, function(cell){
13650             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13651         });
13652         
13653         days += startingPos;
13654
13655         // convert everything to numbers so it's fast
13656         var day = 86400000;
13657         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13658         //Roo.log(d);
13659         //Roo.log(pm);
13660         //Roo.log(prevStart);
13661         
13662         var today = new Date().clearTime().getTime();
13663         var sel = date.clearTime().getTime();
13664         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13665         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13666         var ddMatch = this.disabledDatesRE;
13667         var ddText = this.disabledDatesText;
13668         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13669         var ddaysText = this.disabledDaysText;
13670         var format = this.format;
13671         
13672         var setCellClass = function(cal, cell){
13673             cell.row = 0;
13674             cell.events = [];
13675             cell.more = [];
13676             //Roo.log('set Cell Class');
13677             cell.title = "";
13678             var t = d.getTime();
13679             
13680             //Roo.log(d);
13681             
13682             cell.dateValue = t;
13683             if(t == today){
13684                 cell.className += " fc-today";
13685                 cell.className += " fc-state-highlight";
13686                 cell.title = cal.todayText;
13687             }
13688             if(t == sel){
13689                 // disable highlight in other month..
13690                 //cell.className += " fc-state-highlight";
13691                 
13692             }
13693             // disabling
13694             if(t < min) {
13695                 cell.className = " fc-state-disabled";
13696                 cell.title = cal.minText;
13697                 return;
13698             }
13699             if(t > max) {
13700                 cell.className = " fc-state-disabled";
13701                 cell.title = cal.maxText;
13702                 return;
13703             }
13704             if(ddays){
13705                 if(ddays.indexOf(d.getDay()) != -1){
13706                     cell.title = ddaysText;
13707                     cell.className = " fc-state-disabled";
13708                 }
13709             }
13710             if(ddMatch && format){
13711                 var fvalue = d.dateFormat(format);
13712                 if(ddMatch.test(fvalue)){
13713                     cell.title = ddText.replace("%0", fvalue);
13714                     cell.className = " fc-state-disabled";
13715                 }
13716             }
13717             
13718             if (!cell.initialClassName) {
13719                 cell.initialClassName = cell.dom.className;
13720             }
13721             
13722             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13723         };
13724
13725         var i = 0;
13726         
13727         for(; i < startingPos; i++) {
13728             textEls[i].innerHTML = (++prevStart);
13729             d.setDate(d.getDate()+1);
13730             
13731             cells[i].className = "fc-past fc-other-month";
13732             setCellClass(this, cells[i]);
13733         }
13734         
13735         var intDay = 0;
13736         
13737         for(; i < days; i++){
13738             intDay = i - startingPos + 1;
13739             textEls[i].innerHTML = (intDay);
13740             d.setDate(d.getDate()+1);
13741             
13742             cells[i].className = ''; // "x-date-active";
13743             setCellClass(this, cells[i]);
13744         }
13745         var extraDays = 0;
13746         
13747         for(; i < 42; i++) {
13748             textEls[i].innerHTML = (++extraDays);
13749             d.setDate(d.getDate()+1);
13750             
13751             cells[i].className = "fc-future fc-other-month";
13752             setCellClass(this, cells[i]);
13753         }
13754         
13755         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13756         
13757         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13758         
13759         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13760         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13761         
13762         if(totalRows != 6){
13763             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13764             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13765         }
13766         
13767         this.fireEvent('monthchange', this, date);
13768         
13769         
13770         /*
13771         if(!this.internalRender){
13772             var main = this.el.dom.firstChild;
13773             var w = main.offsetWidth;
13774             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13775             Roo.fly(main).setWidth(w);
13776             this.internalRender = true;
13777             // opera does not respect the auto grow header center column
13778             // then, after it gets a width opera refuses to recalculate
13779             // without a second pass
13780             if(Roo.isOpera && !this.secondPass){
13781                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13782                 this.secondPass = true;
13783                 this.update.defer(10, this, [date]);
13784             }
13785         }
13786         */
13787         
13788     },
13789     
13790     findCell : function(dt) {
13791         dt = dt.clearTime().getTime();
13792         var ret = false;
13793         this.cells.each(function(c){
13794             //Roo.log("check " +c.dateValue + '?=' + dt);
13795             if(c.dateValue == dt){
13796                 ret = c;
13797                 return false;
13798             }
13799             return true;
13800         });
13801         
13802         return ret;
13803     },
13804     
13805     findCells : function(ev) {
13806         var s = ev.start.clone().clearTime().getTime();
13807        // Roo.log(s);
13808         var e= ev.end.clone().clearTime().getTime();
13809        // Roo.log(e);
13810         var ret = [];
13811         this.cells.each(function(c){
13812              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13813             
13814             if(c.dateValue > e){
13815                 return ;
13816             }
13817             if(c.dateValue < s){
13818                 return ;
13819             }
13820             ret.push(c);
13821         });
13822         
13823         return ret;    
13824     },
13825     
13826 //    findBestRow: function(cells)
13827 //    {
13828 //        var ret = 0;
13829 //        
13830 //        for (var i =0 ; i < cells.length;i++) {
13831 //            ret  = Math.max(cells[i].rows || 0,ret);
13832 //        }
13833 //        return ret;
13834 //        
13835 //    },
13836     
13837     
13838     addItem : function(ev)
13839     {
13840         // look for vertical location slot in
13841         var cells = this.findCells(ev);
13842         
13843 //        ev.row = this.findBestRow(cells);
13844         
13845         // work out the location.
13846         
13847         var crow = false;
13848         var rows = [];
13849         for(var i =0; i < cells.length; i++) {
13850             
13851             cells[i].row = cells[0].row;
13852             
13853             if(i == 0){
13854                 cells[i].row = cells[i].row + 1;
13855             }
13856             
13857             if (!crow) {
13858                 crow = {
13859                     start : cells[i],
13860                     end :  cells[i]
13861                 };
13862                 continue;
13863             }
13864             if (crow.start.getY() == cells[i].getY()) {
13865                 // on same row.
13866                 crow.end = cells[i];
13867                 continue;
13868             }
13869             // different row.
13870             rows.push(crow);
13871             crow = {
13872                 start: cells[i],
13873                 end : cells[i]
13874             };
13875             
13876         }
13877         
13878         rows.push(crow);
13879         ev.els = [];
13880         ev.rows = rows;
13881         ev.cells = cells;
13882         
13883         cells[0].events.push(ev);
13884         
13885         this.calevents.push(ev);
13886     },
13887     
13888     clearEvents: function() {
13889         
13890         if(!this.calevents){
13891             return;
13892         }
13893         
13894         Roo.each(this.cells.elements, function(c){
13895             c.row = 0;
13896             c.events = [];
13897             c.more = [];
13898         });
13899         
13900         Roo.each(this.calevents, function(e) {
13901             Roo.each(e.els, function(el) {
13902                 el.un('mouseenter' ,this.onEventEnter, this);
13903                 el.un('mouseleave' ,this.onEventLeave, this);
13904                 el.remove();
13905             },this);
13906         },this);
13907         
13908         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13909             e.remove();
13910         });
13911         
13912     },
13913     
13914     renderEvents: function()
13915     {   
13916         var _this = this;
13917         
13918         this.cells.each(function(c) {
13919             
13920             if(c.row < 5){
13921                 return;
13922             }
13923             
13924             var ev = c.events;
13925             
13926             var r = 4;
13927             if(c.row != c.events.length){
13928                 r = 4 - (4 - (c.row - c.events.length));
13929             }
13930             
13931             c.events = ev.slice(0, r);
13932             c.more = ev.slice(r);
13933             
13934             if(c.more.length && c.more.length == 1){
13935                 c.events.push(c.more.pop());
13936             }
13937             
13938             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13939             
13940         });
13941             
13942         this.cells.each(function(c) {
13943             
13944             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13945             
13946             
13947             for (var e = 0; e < c.events.length; e++){
13948                 var ev = c.events[e];
13949                 var rows = ev.rows;
13950                 
13951                 for(var i = 0; i < rows.length; i++) {
13952                 
13953                     // how many rows should it span..
13954
13955                     var  cfg = {
13956                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13957                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13958
13959                         unselectable : "on",
13960                         cn : [
13961                             {
13962                                 cls: 'fc-event-inner',
13963                                 cn : [
13964     //                                {
13965     //                                  tag:'span',
13966     //                                  cls: 'fc-event-time',
13967     //                                  html : cells.length > 1 ? '' : ev.time
13968     //                                },
13969                                     {
13970                                       tag:'span',
13971                                       cls: 'fc-event-title',
13972                                       html : String.format('{0}', ev.title)
13973                                     }
13974
13975
13976                                 ]
13977                             },
13978                             {
13979                                 cls: 'ui-resizable-handle ui-resizable-e',
13980                                 html : '&nbsp;&nbsp;&nbsp'
13981                             }
13982
13983                         ]
13984                     };
13985
13986                     if (i == 0) {
13987                         cfg.cls += ' fc-event-start';
13988                     }
13989                     if ((i+1) == rows.length) {
13990                         cfg.cls += ' fc-event-end';
13991                     }
13992
13993                     var ctr = _this.el.select('.fc-event-container',true).first();
13994                     var cg = ctr.createChild(cfg);
13995
13996                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13997                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13998
13999                     var r = (c.more.length) ? 1 : 0;
14000                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
14001                     cg.setWidth(ebox.right - sbox.x -2);
14002
14003                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14004                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14005                     cg.on('click', _this.onEventClick, _this, ev);
14006
14007                     ev.els.push(cg);
14008                     
14009                 }
14010                 
14011             }
14012             
14013             
14014             if(c.more.length){
14015                 var  cfg = {
14016                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14017                     style : 'position: absolute',
14018                     unselectable : "on",
14019                     cn : [
14020                         {
14021                             cls: 'fc-event-inner',
14022                             cn : [
14023                                 {
14024                                   tag:'span',
14025                                   cls: 'fc-event-title',
14026                                   html : 'More'
14027                                 }
14028
14029
14030                             ]
14031                         },
14032                         {
14033                             cls: 'ui-resizable-handle ui-resizable-e',
14034                             html : '&nbsp;&nbsp;&nbsp'
14035                         }
14036
14037                     ]
14038                 };
14039
14040                 var ctr = _this.el.select('.fc-event-container',true).first();
14041                 var cg = ctr.createChild(cfg);
14042
14043                 var sbox = c.select('.fc-day-content',true).first().getBox();
14044                 var ebox = c.select('.fc-day-content',true).first().getBox();
14045                 //Roo.log(cg);
14046                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
14047                 cg.setWidth(ebox.right - sbox.x -2);
14048
14049                 cg.on('click', _this.onMoreEventClick, _this, c.more);
14050                 
14051             }
14052             
14053         });
14054         
14055         
14056         
14057     },
14058     
14059     onEventEnter: function (e, el,event,d) {
14060         this.fireEvent('evententer', this, el, event);
14061     },
14062     
14063     onEventLeave: function (e, el,event,d) {
14064         this.fireEvent('eventleave', this, el, event);
14065     },
14066     
14067     onEventClick: function (e, el,event,d) {
14068         this.fireEvent('eventclick', this, el, event);
14069     },
14070     
14071     onMonthChange: function () {
14072         this.store.load();
14073     },
14074     
14075     onMoreEventClick: function(e, el, more)
14076     {
14077         var _this = this;
14078         
14079         this.calpopover.placement = 'right';
14080         this.calpopover.setTitle('More');
14081         
14082         this.calpopover.setContent('');
14083         
14084         var ctr = this.calpopover.el.select('.popover-content', true).first();
14085         
14086         Roo.each(more, function(m){
14087             var cfg = {
14088                 cls : 'fc-event-hori fc-event-draggable',
14089                 html : m.title
14090             }
14091             var cg = ctr.createChild(cfg);
14092             
14093             cg.on('click', _this.onEventClick, _this, m);
14094         });
14095         
14096         this.calpopover.show(el);
14097         
14098         
14099     },
14100     
14101     onLoad: function () 
14102     {   
14103         this.calevents = [];
14104         var cal = this;
14105         
14106         if(this.store.getCount() > 0){
14107             this.store.data.each(function(d){
14108                cal.addItem({
14109                     id : d.data.id,
14110                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14111                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14112                     time : d.data.start_time,
14113                     title : d.data.title,
14114                     description : d.data.description,
14115                     venue : d.data.venue
14116                 });
14117             });
14118         }
14119         
14120         this.renderEvents();
14121         
14122         if(this.calevents.length && this.loadMask){
14123             this.maskEl.hide();
14124         }
14125     },
14126     
14127     onBeforeLoad: function()
14128     {
14129         this.clearEvents();
14130         if(this.loadMask){
14131             this.maskEl.show();
14132         }
14133     }
14134 });
14135
14136  
14137  /*
14138  * - LGPL
14139  *
14140  * element
14141  * 
14142  */
14143
14144 /**
14145  * @class Roo.bootstrap.Popover
14146  * @extends Roo.bootstrap.Component
14147  * Bootstrap Popover class
14148  * @cfg {String} html contents of the popover   (or false to use children..)
14149  * @cfg {String} title of popover (or false to hide)
14150  * @cfg {String} placement how it is placed
14151  * @cfg {String} trigger click || hover (or false to trigger manually)
14152  * @cfg {String} over what (parent or false to trigger manually.)
14153  * @cfg {Number} delay - delay before showing
14154  
14155  * @constructor
14156  * Create a new Popover
14157  * @param {Object} config The config object
14158  */
14159
14160 Roo.bootstrap.Popover = function(config){
14161     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14162 };
14163
14164 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14165     
14166     title: 'Fill in a title',
14167     html: false,
14168     
14169     placement : 'right',
14170     trigger : 'hover', // hover
14171     
14172     delay : 0,
14173     
14174     over: 'parent',
14175     
14176     can_build_overlaid : false,
14177     
14178     getChildContainer : function()
14179     {
14180         return this.el.select('.popover-content',true).first();
14181     },
14182     
14183     getAutoCreate : function(){
14184          Roo.log('make popover?');
14185         var cfg = {
14186            cls : 'popover roo-dynamic',
14187            style: 'display:block',
14188            cn : [
14189                 {
14190                     cls : 'arrow'
14191                 },
14192                 {
14193                     cls : 'popover-inner',
14194                     cn : [
14195                         {
14196                             tag: 'h3',
14197                             cls: 'popover-title',
14198                             html : this.title
14199                         },
14200                         {
14201                             cls : 'popover-content',
14202                             html : this.html
14203                         }
14204                     ]
14205                     
14206                 }
14207            ]
14208         };
14209         
14210         return cfg;
14211     },
14212     setTitle: function(str)
14213     {
14214         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14215     },
14216     setContent: function(str)
14217     {
14218         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14219     },
14220     // as it get's added to the bottom of the page.
14221     onRender : function(ct, position)
14222     {
14223         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14224         if(!this.el){
14225             var cfg = Roo.apply({},  this.getAutoCreate());
14226             cfg.id = Roo.id();
14227             
14228             if (this.cls) {
14229                 cfg.cls += ' ' + this.cls;
14230             }
14231             if (this.style) {
14232                 cfg.style = this.style;
14233             }
14234             Roo.log("adding to ")
14235             this.el = Roo.get(document.body).createChild(cfg, position);
14236             Roo.log(this.el);
14237         }
14238         this.initEvents();
14239     },
14240     
14241     initEvents : function()
14242     {
14243         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14244         this.el.enableDisplayMode('block');
14245         this.el.hide();
14246         if (this.over === false) {
14247             return; 
14248         }
14249         if (this.triggers === false) {
14250             return;
14251         }
14252         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14253         var triggers = this.trigger ? this.trigger.split(' ') : [];
14254         Roo.each(triggers, function(trigger) {
14255         
14256             if (trigger == 'click') {
14257                 on_el.on('click', this.toggle, this);
14258             } else if (trigger != 'manual') {
14259                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14260                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14261       
14262                 on_el.on(eventIn  ,this.enter, this);
14263                 on_el.on(eventOut, this.leave, this);
14264             }
14265         }, this);
14266         
14267     },
14268     
14269     
14270     // private
14271     timeout : null,
14272     hoverState : null,
14273     
14274     toggle : function () {
14275         this.hoverState == 'in' ? this.leave() : this.enter();
14276     },
14277     
14278     enter : function () {
14279        
14280     
14281         clearTimeout(this.timeout);
14282     
14283         this.hoverState = 'in';
14284     
14285         if (!this.delay || !this.delay.show) {
14286             this.show();
14287             return;
14288         }
14289         var _t = this;
14290         this.timeout = setTimeout(function () {
14291             if (_t.hoverState == 'in') {
14292                 _t.show();
14293             }
14294         }, this.delay.show)
14295     },
14296     leave : function() {
14297         clearTimeout(this.timeout);
14298     
14299         this.hoverState = 'out';
14300     
14301         if (!this.delay || !this.delay.hide) {
14302             this.hide();
14303             return;
14304         }
14305         var _t = this;
14306         this.timeout = setTimeout(function () {
14307             if (_t.hoverState == 'out') {
14308                 _t.hide();
14309             }
14310         }, this.delay.hide)
14311     },
14312     
14313     show : function (on_el)
14314     {
14315         if (!on_el) {
14316             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14317         }
14318         // set content.
14319         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14320         if (this.html !== false) {
14321             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14322         }
14323         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14324         if (!this.title.length) {
14325             this.el.select('.popover-title',true).hide();
14326         }
14327         
14328         var placement = typeof this.placement == 'function' ?
14329             this.placement.call(this, this.el, on_el) :
14330             this.placement;
14331             
14332         var autoToken = /\s?auto?\s?/i;
14333         var autoPlace = autoToken.test(placement);
14334         if (autoPlace) {
14335             placement = placement.replace(autoToken, '') || 'top';
14336         }
14337         
14338         //this.el.detach()
14339         //this.el.setXY([0,0]);
14340         this.el.show();
14341         this.el.dom.style.display='block';
14342         this.el.addClass(placement);
14343         
14344         //this.el.appendTo(on_el);
14345         
14346         var p = this.getPosition();
14347         var box = this.el.getBox();
14348         
14349         if (autoPlace) {
14350             // fixme..
14351         }
14352         var align = Roo.bootstrap.Popover.alignment[placement];
14353         this.el.alignTo(on_el, align[0],align[1]);
14354         //var arrow = this.el.select('.arrow',true).first();
14355         //arrow.set(align[2], 
14356         
14357         this.el.addClass('in');
14358         this.hoverState = null;
14359         
14360         if (this.el.hasClass('fade')) {
14361             // fade it?
14362         }
14363         
14364     },
14365     hide : function()
14366     {
14367         this.el.setXY([0,0]);
14368         this.el.removeClass('in');
14369         this.el.hide();
14370         
14371     }
14372     
14373 });
14374
14375 Roo.bootstrap.Popover.alignment = {
14376     'left' : ['r-l', [-10,0], 'right'],
14377     'right' : ['l-r', [10,0], 'left'],
14378     'bottom' : ['t-b', [0,10], 'top'],
14379     'top' : [ 'b-t', [0,-10], 'bottom']
14380 };
14381
14382  /*
14383  * - LGPL
14384  *
14385  * Progress
14386  * 
14387  */
14388
14389 /**
14390  * @class Roo.bootstrap.Progress
14391  * @extends Roo.bootstrap.Component
14392  * Bootstrap Progress class
14393  * @cfg {Boolean} striped striped of the progress bar
14394  * @cfg {Boolean} active animated of the progress bar
14395  * 
14396  * 
14397  * @constructor
14398  * Create a new Progress
14399  * @param {Object} config The config object
14400  */
14401
14402 Roo.bootstrap.Progress = function(config){
14403     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14404 };
14405
14406 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14407     
14408     striped : false,
14409     active: false,
14410     
14411     getAutoCreate : function(){
14412         var cfg = {
14413             tag: 'div',
14414             cls: 'progress'
14415         };
14416         
14417         
14418         if(this.striped){
14419             cfg.cls += ' progress-striped';
14420         }
14421       
14422         if(this.active){
14423             cfg.cls += ' active';
14424         }
14425         
14426         
14427         return cfg;
14428     }
14429    
14430 });
14431
14432  
14433
14434  /*
14435  * - LGPL
14436  *
14437  * ProgressBar
14438  * 
14439  */
14440
14441 /**
14442  * @class Roo.bootstrap.ProgressBar
14443  * @extends Roo.bootstrap.Component
14444  * Bootstrap ProgressBar class
14445  * @cfg {Number} aria_valuenow aria-value now
14446  * @cfg {Number} aria_valuemin aria-value min
14447  * @cfg {Number} aria_valuemax aria-value max
14448  * @cfg {String} label label for the progress bar
14449  * @cfg {String} panel (success | info | warning | danger )
14450  * @cfg {String} role role of the progress bar
14451  * @cfg {String} sr_only text
14452  * 
14453  * 
14454  * @constructor
14455  * Create a new ProgressBar
14456  * @param {Object} config The config object
14457  */
14458
14459 Roo.bootstrap.ProgressBar = function(config){
14460     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14461 };
14462
14463 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14464     
14465     aria_valuenow : 0,
14466     aria_valuemin : 0,
14467     aria_valuemax : 100,
14468     label : false,
14469     panel : false,
14470     role : false,
14471     sr_only: false,
14472     
14473     getAutoCreate : function()
14474     {
14475         
14476         var cfg = {
14477             tag: 'div',
14478             cls: 'progress-bar',
14479             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14480         };
14481         
14482         if(this.sr_only){
14483             cfg.cn = {
14484                 tag: 'span',
14485                 cls: 'sr-only',
14486                 html: this.sr_only
14487             }
14488         }
14489         
14490         if(this.role){
14491             cfg.role = this.role;
14492         }
14493         
14494         if(this.aria_valuenow){
14495             cfg['aria-valuenow'] = this.aria_valuenow;
14496         }
14497         
14498         if(this.aria_valuemin){
14499             cfg['aria-valuemin'] = this.aria_valuemin;
14500         }
14501         
14502         if(this.aria_valuemax){
14503             cfg['aria-valuemax'] = this.aria_valuemax;
14504         }
14505         
14506         if(this.label && !this.sr_only){
14507             cfg.html = this.label;
14508         }
14509         
14510         if(this.panel){
14511             cfg.cls += ' progress-bar-' + this.panel;
14512         }
14513         
14514         return cfg;
14515     },
14516     
14517     update : function(aria_valuenow)
14518     {
14519         this.aria_valuenow = aria_valuenow;
14520         
14521         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14522     }
14523    
14524 });
14525
14526  
14527
14528  /*
14529  * - LGPL
14530  *
14531  * column
14532  * 
14533  */
14534
14535 /**
14536  * @class Roo.bootstrap.TabGroup
14537  * @extends Roo.bootstrap.Column
14538  * Bootstrap Column class
14539  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14540  * @cfg {Boolean} carousel true to make the group behave like a carousel
14541  * 
14542  * @constructor
14543  * Create a new TabGroup
14544  * @param {Object} config The config object
14545  */
14546
14547 Roo.bootstrap.TabGroup = function(config){
14548     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14549     if (!this.navId) {
14550         this.navId = Roo.id();
14551     }
14552     this.tabs = [];
14553     Roo.bootstrap.TabGroup.register(this);
14554     
14555 };
14556
14557 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14558     
14559     carousel : false,
14560     transition : false,
14561      
14562     getAutoCreate : function()
14563     {
14564         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14565         
14566         cfg.cls += ' tab-content';
14567         
14568         if (this.carousel) {
14569             cfg.cls += ' carousel slide';
14570             cfg.cn = [{
14571                cls : 'carousel-inner'
14572             }]
14573         }
14574         
14575         
14576         return cfg;
14577     },
14578     getChildContainer : function()
14579     {
14580         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14581     },
14582     
14583     /**
14584     * register a Navigation item
14585     * @param {Roo.bootstrap.NavItem} the navitem to add
14586     */
14587     register : function(item)
14588     {
14589         this.tabs.push( item);
14590         item.navId = this.navId; // not really needed..
14591     
14592     },
14593     
14594     getActivePanel : function()
14595     {
14596         var r = false;
14597         Roo.each(this.tabs, function(t) {
14598             if (t.active) {
14599                 r = t;
14600                 return false;
14601             }
14602             return null;
14603         });
14604         return r;
14605         
14606     },
14607     getPanelByName : function(n)
14608     {
14609         var r = false;
14610         Roo.each(this.tabs, function(t) {
14611             if (t.tabId == n) {
14612                 r = t;
14613                 return false;
14614             }
14615             return null;
14616         });
14617         return r;
14618     },
14619     indexOfPanel : function(p)
14620     {
14621         var r = false;
14622         Roo.each(this.tabs, function(t,i) {
14623             if (t.tabId == p.tabId) {
14624                 r = i;
14625                 return false;
14626             }
14627             return null;
14628         });
14629         return r;
14630     },
14631     /**
14632      * show a specific panel
14633      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14634      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14635      */
14636     showPanel : function (pan)
14637     {
14638         
14639         if (typeof(pan) == 'number') {
14640             pan = this.tabs[pan];
14641         }
14642         if (typeof(pan) == 'string') {
14643             pan = this.getPanelByName(pan);
14644         }
14645         if (pan.tabId == this.getActivePanel().tabId) {
14646             return true;
14647         }
14648         var cur = this.getActivePanel();
14649         
14650         if (false === cur.fireEvent('beforedeactivate')) {
14651             return false;
14652         }
14653         
14654         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14655             
14656             this.transition = true;
14657             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14658             var lr = dir == 'next' ? 'left' : 'right';
14659             pan.el.addClass(dir); // or prev
14660             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14661             cur.el.addClass(lr); // or right
14662             pan.el.addClass(lr);
14663             
14664             var _this = this;
14665             cur.el.on('transitionend', function() {
14666                 Roo.log("trans end?");
14667                 
14668                 pan.el.removeClass([lr,dir]);
14669                 pan.setActive(true);
14670                 
14671                 cur.el.removeClass([lr]);
14672                 cur.setActive(false);
14673                 
14674                 _this.transition = false;
14675                 
14676             }, this, { single:  true } );
14677             return true;
14678         }
14679         
14680         cur.setActive(false);
14681         pan.setActive(true);
14682         return true;
14683         
14684     },
14685     showPanelNext : function()
14686     {
14687         var i = this.indexOfPanel(this.getActivePanel());
14688         if (i > this.tabs.length) {
14689             return;
14690         }
14691         this.showPanel(this.tabs[i+1]);
14692     },
14693     showPanelPrev : function()
14694     {
14695         var i = this.indexOfPanel(this.getActivePanel());
14696         if (i  < 1) {
14697             return;
14698         }
14699         this.showPanel(this.tabs[i-1]);
14700     }
14701     
14702     
14703   
14704 });
14705
14706  
14707
14708  
14709  
14710 Roo.apply(Roo.bootstrap.TabGroup, {
14711     
14712     groups: {},
14713      /**
14714     * register a Navigation Group
14715     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14716     */
14717     register : function(navgrp)
14718     {
14719         this.groups[navgrp.navId] = navgrp;
14720         
14721     },
14722     /**
14723     * fetch a Navigation Group based on the navigation ID
14724     * if one does not exist , it will get created.
14725     * @param {string} the navgroup to add
14726     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14727     */
14728     get: function(navId) {
14729         if (typeof(this.groups[navId]) == 'undefined') {
14730             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14731         }
14732         return this.groups[navId] ;
14733     }
14734     
14735     
14736     
14737 });
14738
14739  /*
14740  * - LGPL
14741  *
14742  * TabPanel
14743  * 
14744  */
14745
14746 /**
14747  * @class Roo.bootstrap.TabPanel
14748  * @extends Roo.bootstrap.Component
14749  * Bootstrap TabPanel class
14750  * @cfg {Boolean} active panel active
14751  * @cfg {String} html panel content
14752  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14753  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14754  * 
14755  * 
14756  * @constructor
14757  * Create a new TabPanel
14758  * @param {Object} config The config object
14759  */
14760
14761 Roo.bootstrap.TabPanel = function(config){
14762     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14763     this.addEvents({
14764         /**
14765              * @event changed
14766              * Fires when the active status changes
14767              * @param {Roo.bootstrap.TabPanel} this
14768              * @param {Boolean} state the new state
14769             
14770          */
14771         'changed': true,
14772         /**
14773              * @event beforedeactivate
14774              * Fires before a tab is de-activated - can be used to do validation on a form.
14775              * @param {Roo.bootstrap.TabPanel} this
14776              * @return {Boolean} false if there is an error
14777             
14778          */
14779         'beforedeactivate': true
14780      });
14781     
14782     this.tabId = this.tabId || Roo.id();
14783   
14784 };
14785
14786 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14787     
14788     active: false,
14789     html: false,
14790     tabId: false,
14791     navId : false,
14792     
14793     getAutoCreate : function(){
14794         var cfg = {
14795             tag: 'div',
14796             // item is needed for carousel - not sure if it has any effect otherwise
14797             cls: 'tab-pane item',
14798             html: this.html || ''
14799         };
14800         
14801         if(this.active){
14802             cfg.cls += ' active';
14803         }
14804         
14805         if(this.tabId){
14806             cfg.tabId = this.tabId;
14807         }
14808         
14809         
14810         return cfg;
14811     },
14812     
14813     initEvents:  function()
14814     {
14815         Roo.log('-------- init events on tab panel ---------');
14816         
14817         var p = this.parent();
14818         this.navId = this.navId || p.navId;
14819         
14820         if (typeof(this.navId) != 'undefined') {
14821             // not really needed.. but just in case.. parent should be a NavGroup.
14822             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14823             Roo.log(['register', tg, this]);
14824             tg.register(this);
14825         }
14826     },
14827     
14828     
14829     onRender : function(ct, position)
14830     {
14831        // Roo.log("Call onRender: " + this.xtype);
14832         
14833         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14834         
14835         
14836         
14837         
14838         
14839     },
14840     
14841     setActive: function(state)
14842     {
14843         Roo.log("panel - set active " + this.tabId + "=" + state);
14844         
14845         this.active = state;
14846         if (!state) {
14847             this.el.removeClass('active');
14848             
14849         } else  if (!this.el.hasClass('active')) {
14850             this.el.addClass('active');
14851         }
14852         this.fireEvent('changed', this, state);
14853     }
14854     
14855     
14856 });
14857  
14858
14859  
14860
14861  /*
14862  * - LGPL
14863  *
14864  * DateField
14865  * 
14866  */
14867
14868 /**
14869  * @class Roo.bootstrap.DateField
14870  * @extends Roo.bootstrap.Input
14871  * Bootstrap DateField class
14872  * @cfg {Number} weekStart default 0
14873  * @cfg {String} viewMode default empty, (months|years)
14874  * @cfg {String} minViewMode default empty, (months|years)
14875  * @cfg {Number} startDate default -Infinity
14876  * @cfg {Number} endDate default Infinity
14877  * @cfg {Boolean} todayHighlight default false
14878  * @cfg {Boolean} todayBtn default false
14879  * @cfg {Boolean} calendarWeeks default false
14880  * @cfg {Object} daysOfWeekDisabled default empty
14881  * @cfg {Boolean} singleMode default false (true | false)
14882  * 
14883  * @cfg {Boolean} keyboardNavigation default true
14884  * @cfg {String} language default en
14885  * 
14886  * @constructor
14887  * Create a new DateField
14888  * @param {Object} config The config object
14889  */
14890
14891 Roo.bootstrap.DateField = function(config){
14892     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14893      this.addEvents({
14894             /**
14895              * @event show
14896              * Fires when this field show.
14897              * @param {Roo.bootstrap.DateField} this
14898              * @param {Mixed} date The date value
14899              */
14900             show : true,
14901             /**
14902              * @event show
14903              * Fires when this field hide.
14904              * @param {Roo.bootstrap.DateField} this
14905              * @param {Mixed} date The date value
14906              */
14907             hide : true,
14908             /**
14909              * @event select
14910              * Fires when select a date.
14911              * @param {Roo.bootstrap.DateField} this
14912              * @param {Mixed} date The date value
14913              */
14914             select : true
14915         });
14916 };
14917
14918 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14919     
14920     /**
14921      * @cfg {String} format
14922      * The default date format string which can be overriden for localization support.  The format must be
14923      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14924      */
14925     format : "m/d/y",
14926     /**
14927      * @cfg {String} altFormats
14928      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14929      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14930      */
14931     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14932     
14933     weekStart : 0,
14934     
14935     viewMode : '',
14936     
14937     minViewMode : '',
14938     
14939     todayHighlight : false,
14940     
14941     todayBtn: false,
14942     
14943     language: 'en',
14944     
14945     keyboardNavigation: true,
14946     
14947     calendarWeeks: false,
14948     
14949     startDate: -Infinity,
14950     
14951     endDate: Infinity,
14952     
14953     daysOfWeekDisabled: [],
14954     
14955     _events: [],
14956     
14957     singleMode : false,
14958     
14959     UTCDate: function()
14960     {
14961         return new Date(Date.UTC.apply(Date, arguments));
14962     },
14963     
14964     UTCToday: function()
14965     {
14966         var today = new Date();
14967         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14968     },
14969     
14970     getDate: function() {
14971             var d = this.getUTCDate();
14972             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14973     },
14974     
14975     getUTCDate: function() {
14976             return this.date;
14977     },
14978     
14979     setDate: function(d) {
14980             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14981     },
14982     
14983     setUTCDate: function(d) {
14984             this.date = d;
14985             this.setValue(this.formatDate(this.date));
14986     },
14987         
14988     onRender: function(ct, position)
14989     {
14990         
14991         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14992         
14993         this.language = this.language || 'en';
14994         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14995         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14996         
14997         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14998         this.format = this.format || 'm/d/y';
14999         this.isInline = false;
15000         this.isInput = true;
15001         this.component = this.el.select('.add-on', true).first() || false;
15002         this.component = (this.component && this.component.length === 0) ? false : this.component;
15003         this.hasInput = this.component && this.inputEL().length;
15004         
15005         if (typeof(this.minViewMode === 'string')) {
15006             switch (this.minViewMode) {
15007                 case 'months':
15008                     this.minViewMode = 1;
15009                     break;
15010                 case 'years':
15011                     this.minViewMode = 2;
15012                     break;
15013                 default:
15014                     this.minViewMode = 0;
15015                     break;
15016             }
15017         }
15018         
15019         if (typeof(this.viewMode === 'string')) {
15020             switch (this.viewMode) {
15021                 case 'months':
15022                     this.viewMode = 1;
15023                     break;
15024                 case 'years':
15025                     this.viewMode = 2;
15026                     break;
15027                 default:
15028                     this.viewMode = 0;
15029                     break;
15030             }
15031         }
15032                 
15033         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15034         
15035 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15036         
15037         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15038         
15039         this.picker().on('mousedown', this.onMousedown, this);
15040         this.picker().on('click', this.onClick, this);
15041         
15042         this.picker().addClass('datepicker-dropdown');
15043         
15044         this.startViewMode = this.viewMode;
15045         
15046         if(this.singleMode){
15047             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15048                 v.setVisibilityMode(Roo.Element.DISPLAY)
15049                 v.hide();
15050             });
15051             
15052             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15053                 v.setStyle('width', '189px');
15054             });
15055         }
15056         
15057         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15058             if(!this.calendarWeeks){
15059                 v.remove();
15060                 return;
15061             }
15062             
15063             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15064             v.attr('colspan', function(i, val){
15065                 return parseInt(val) + 1;
15066             });
15067         })
15068                         
15069         
15070         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15071         
15072         this.setStartDate(this.startDate);
15073         this.setEndDate(this.endDate);
15074         
15075         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15076         
15077         this.fillDow();
15078         this.fillMonths();
15079         this.update();
15080         this.showMode();
15081         
15082         if(this.isInline) {
15083             this.show();
15084         }
15085     },
15086     
15087     picker : function()
15088     {
15089         return this.pickerEl;
15090 //        return this.el.select('.datepicker', true).first();
15091     },
15092     
15093     fillDow: function()
15094     {
15095         var dowCnt = this.weekStart;
15096         
15097         var dow = {
15098             tag: 'tr',
15099             cn: [
15100                 
15101             ]
15102         };
15103         
15104         if(this.calendarWeeks){
15105             dow.cn.push({
15106                 tag: 'th',
15107                 cls: 'cw',
15108                 html: '&nbsp;'
15109             })
15110         }
15111         
15112         while (dowCnt < this.weekStart + 7) {
15113             dow.cn.push({
15114                 tag: 'th',
15115                 cls: 'dow',
15116                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15117             });
15118         }
15119         
15120         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15121     },
15122     
15123     fillMonths: function()
15124     {    
15125         var i = 0;
15126         var months = this.picker().select('>.datepicker-months td', true).first();
15127         
15128         months.dom.innerHTML = '';
15129         
15130         while (i < 12) {
15131             var month = {
15132                 tag: 'span',
15133                 cls: 'month',
15134                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15135             }
15136             
15137             months.createChild(month);
15138         }
15139         
15140     },
15141     
15142     update: function()
15143     {
15144         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;
15145         
15146         if (this.date < this.startDate) {
15147             this.viewDate = new Date(this.startDate);
15148         } else if (this.date > this.endDate) {
15149             this.viewDate = new Date(this.endDate);
15150         } else {
15151             this.viewDate = new Date(this.date);
15152         }
15153         
15154         this.fill();
15155     },
15156     
15157     fill: function() 
15158     {
15159         var d = new Date(this.viewDate),
15160                 year = d.getUTCFullYear(),
15161                 month = d.getUTCMonth(),
15162                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15163                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15164                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15165                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15166                 currentDate = this.date && this.date.valueOf(),
15167                 today = this.UTCToday();
15168         
15169         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15170         
15171 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15172         
15173 //        this.picker.select('>tfoot th.today').
15174 //                                              .text(dates[this.language].today)
15175 //                                              .toggle(this.todayBtn !== false);
15176     
15177         this.updateNavArrows();
15178         this.fillMonths();
15179                                                 
15180         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15181         
15182         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15183          
15184         prevMonth.setUTCDate(day);
15185         
15186         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15187         
15188         var nextMonth = new Date(prevMonth);
15189         
15190         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15191         
15192         nextMonth = nextMonth.valueOf();
15193         
15194         var fillMonths = false;
15195         
15196         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15197         
15198         while(prevMonth.valueOf() < nextMonth) {
15199             var clsName = '';
15200             
15201             if (prevMonth.getUTCDay() === this.weekStart) {
15202                 if(fillMonths){
15203                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15204                 }
15205                     
15206                 fillMonths = {
15207                     tag: 'tr',
15208                     cn: []
15209                 };
15210                 
15211                 if(this.calendarWeeks){
15212                     // ISO 8601: First week contains first thursday.
15213                     // ISO also states week starts on Monday, but we can be more abstract here.
15214                     var
15215                     // Start of current week: based on weekstart/current date
15216                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15217                     // Thursday of this week
15218                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15219                     // First Thursday of year, year from thursday
15220                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15221                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15222                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15223                     
15224                     fillMonths.cn.push({
15225                         tag: 'td',
15226                         cls: 'cw',
15227                         html: calWeek
15228                     });
15229                 }
15230             }
15231             
15232             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15233                 clsName += ' old';
15234             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15235                 clsName += ' new';
15236             }
15237             if (this.todayHighlight &&
15238                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15239                 prevMonth.getUTCMonth() == today.getMonth() &&
15240                 prevMonth.getUTCDate() == today.getDate()) {
15241                 clsName += ' today';
15242             }
15243             
15244             if (currentDate && prevMonth.valueOf() === currentDate) {
15245                 clsName += ' active';
15246             }
15247             
15248             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15249                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15250                     clsName += ' disabled';
15251             }
15252             
15253             fillMonths.cn.push({
15254                 tag: 'td',
15255                 cls: 'day ' + clsName,
15256                 html: prevMonth.getDate()
15257             })
15258             
15259             prevMonth.setDate(prevMonth.getDate()+1);
15260         }
15261           
15262         var currentYear = this.date && this.date.getUTCFullYear();
15263         var currentMonth = this.date && this.date.getUTCMonth();
15264         
15265         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15266         
15267         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15268             v.removeClass('active');
15269             
15270             if(currentYear === year && k === currentMonth){
15271                 v.addClass('active');
15272             }
15273             
15274             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15275                 v.addClass('disabled');
15276             }
15277             
15278         });
15279         
15280         
15281         year = parseInt(year/10, 10) * 10;
15282         
15283         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15284         
15285         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15286         
15287         year -= 1;
15288         for (var i = -1; i < 11; i++) {
15289             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15290                 tag: 'span',
15291                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15292                 html: year
15293             })
15294             
15295             year += 1;
15296         }
15297     },
15298     
15299     showMode: function(dir) 
15300     {
15301         if (dir) {
15302             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15303         }
15304         
15305         Roo.each(this.picker().select('>div',true).elements, function(v){
15306             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15307             v.hide();
15308         });
15309         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15310     },
15311     
15312     place: function()
15313     {
15314         if(this.isInline) return;
15315         
15316         this.picker().removeClass(['bottom', 'top']);
15317         
15318         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15319             /*
15320              * place to the top of element!
15321              *
15322              */
15323             
15324             this.picker().addClass('top');
15325             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15326             
15327             return;
15328         }
15329         
15330         this.picker().addClass('bottom');
15331         
15332         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15333     },
15334     
15335     parseDate : function(value)
15336     {
15337         if(!value || value instanceof Date){
15338             return value;
15339         }
15340         var v = Date.parseDate(value, this.format);
15341         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15342             v = Date.parseDate(value, 'Y-m-d');
15343         }
15344         if(!v && this.altFormats){
15345             if(!this.altFormatsArray){
15346                 this.altFormatsArray = this.altFormats.split("|");
15347             }
15348             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15349                 v = Date.parseDate(value, this.altFormatsArray[i]);
15350             }
15351         }
15352         return v;
15353     },
15354     
15355     formatDate : function(date, fmt)
15356     {   
15357         return (!date || !(date instanceof Date)) ?
15358         date : date.dateFormat(fmt || this.format);
15359     },
15360     
15361     onFocus : function()
15362     {
15363         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15364         this.show();
15365     },
15366     
15367     onBlur : function()
15368     {
15369         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15370         
15371         var d = this.inputEl().getValue();
15372         
15373         this.setValue(d);
15374                 
15375         this.hide();
15376     },
15377     
15378     show : function()
15379     {
15380         this.picker().show();
15381         this.update();
15382         this.place();
15383         
15384         this.fireEvent('show', this, this.date);
15385     },
15386     
15387     hide : function()
15388     {
15389         if(this.isInline) return;
15390         this.picker().hide();
15391         this.viewMode = this.startViewMode;
15392         this.showMode();
15393         
15394         this.fireEvent('hide', this, this.date);
15395         
15396     },
15397     
15398     onMousedown: function(e)
15399     {
15400         e.stopPropagation();
15401         e.preventDefault();
15402     },
15403     
15404     keyup: function(e)
15405     {
15406         Roo.bootstrap.DateField.superclass.keyup.call(this);
15407         this.update();
15408     },
15409
15410     setValue: function(v)
15411     {
15412         
15413         // v can be a string or a date..
15414         
15415         
15416         var d = new Date(this.parseDate(v) ).clearTime();
15417         
15418         if(isNaN(d.getTime())){
15419             this.date = this.viewDate = '';
15420             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15421             return;
15422         }
15423         
15424         v = this.formatDate(d);
15425         
15426         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15427         
15428         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15429      
15430         this.update();
15431
15432         this.fireEvent('select', this, this.date);
15433         
15434     },
15435     
15436     getValue: function()
15437     {
15438         return this.formatDate(this.date);
15439     },
15440     
15441     fireKey: function(e)
15442     {
15443         if (!this.picker().isVisible()){
15444             if (e.keyCode == 27) // allow escape to hide and re-show picker
15445                 this.show();
15446             return;
15447         }
15448         
15449         var dateChanged = false,
15450         dir, day, month,
15451         newDate, newViewDate;
15452         
15453         switch(e.keyCode){
15454             case 27: // escape
15455                 this.hide();
15456                 e.preventDefault();
15457                 break;
15458             case 37: // left
15459             case 39: // right
15460                 if (!this.keyboardNavigation) break;
15461                 dir = e.keyCode == 37 ? -1 : 1;
15462                 
15463                 if (e.ctrlKey){
15464                     newDate = this.moveYear(this.date, dir);
15465                     newViewDate = this.moveYear(this.viewDate, dir);
15466                 } else if (e.shiftKey){
15467                     newDate = this.moveMonth(this.date, dir);
15468                     newViewDate = this.moveMonth(this.viewDate, dir);
15469                 } else {
15470                     newDate = new Date(this.date);
15471                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15472                     newViewDate = new Date(this.viewDate);
15473                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15474                 }
15475                 if (this.dateWithinRange(newDate)){
15476                     this.date = newDate;
15477                     this.viewDate = newViewDate;
15478                     this.setValue(this.formatDate(this.date));
15479 //                    this.update();
15480                     e.preventDefault();
15481                     dateChanged = true;
15482                 }
15483                 break;
15484             case 38: // up
15485             case 40: // down
15486                 if (!this.keyboardNavigation) break;
15487                 dir = e.keyCode == 38 ? -1 : 1;
15488                 if (e.ctrlKey){
15489                     newDate = this.moveYear(this.date, dir);
15490                     newViewDate = this.moveYear(this.viewDate, dir);
15491                 } else if (e.shiftKey){
15492                     newDate = this.moveMonth(this.date, dir);
15493                     newViewDate = this.moveMonth(this.viewDate, dir);
15494                 } else {
15495                     newDate = new Date(this.date);
15496                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15497                     newViewDate = new Date(this.viewDate);
15498                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15499                 }
15500                 if (this.dateWithinRange(newDate)){
15501                     this.date = newDate;
15502                     this.viewDate = newViewDate;
15503                     this.setValue(this.formatDate(this.date));
15504 //                    this.update();
15505                     e.preventDefault();
15506                     dateChanged = true;
15507                 }
15508                 break;
15509             case 13: // enter
15510                 this.setValue(this.formatDate(this.date));
15511                 this.hide();
15512                 e.preventDefault();
15513                 break;
15514             case 9: // tab
15515                 this.setValue(this.formatDate(this.date));
15516                 this.hide();
15517                 break;
15518             case 16: // shift
15519             case 17: // ctrl
15520             case 18: // alt
15521                 break;
15522             default :
15523                 this.hide();
15524                 
15525         }
15526     },
15527     
15528     
15529     onClick: function(e) 
15530     {
15531         e.stopPropagation();
15532         e.preventDefault();
15533         
15534         var target = e.getTarget();
15535         
15536         if(target.nodeName.toLowerCase() === 'i'){
15537             target = Roo.get(target).dom.parentNode;
15538         }
15539         
15540         var nodeName = target.nodeName;
15541         var className = target.className;
15542         var html = target.innerHTML;
15543         //Roo.log(nodeName);
15544         
15545         switch(nodeName.toLowerCase()) {
15546             case 'th':
15547                 switch(className) {
15548                     case 'switch':
15549                         this.showMode(1);
15550                         break;
15551                     case 'prev':
15552                     case 'next':
15553                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15554                         switch(this.viewMode){
15555                                 case 0:
15556                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15557                                         break;
15558                                 case 1:
15559                                 case 2:
15560                                         this.viewDate = this.moveYear(this.viewDate, dir);
15561                                         break;
15562                         }
15563                         this.fill();
15564                         break;
15565                     case 'today':
15566                         var date = new Date();
15567                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15568 //                        this.fill()
15569                         this.setValue(this.formatDate(this.date));
15570                         
15571                         this.hide();
15572                         break;
15573                 }
15574                 break;
15575             case 'span':
15576                 if (className.indexOf('disabled') < 0) {
15577                     this.viewDate.setUTCDate(1);
15578                     if (className.indexOf('month') > -1) {
15579                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15580                     } else {
15581                         var year = parseInt(html, 10) || 0;
15582                         this.viewDate.setUTCFullYear(year);
15583                         
15584                     }
15585                     
15586                     if(this.singleMode){
15587                         this.setValue(this.formatDate(this.viewDate));
15588                         this.hide();
15589                         return;
15590                     }
15591                     
15592                     this.showMode(-1);
15593                     this.fill();
15594                 }
15595                 break;
15596                 
15597             case 'td':
15598                 //Roo.log(className);
15599                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15600                     var day = parseInt(html, 10) || 1;
15601                     var year = this.viewDate.getUTCFullYear(),
15602                         month = this.viewDate.getUTCMonth();
15603
15604                     if (className.indexOf('old') > -1) {
15605                         if(month === 0 ){
15606                             month = 11;
15607                             year -= 1;
15608                         }else{
15609                             month -= 1;
15610                         }
15611                     } else if (className.indexOf('new') > -1) {
15612                         if (month == 11) {
15613                             month = 0;
15614                             year += 1;
15615                         } else {
15616                             month += 1;
15617                         }
15618                     }
15619                     //Roo.log([year,month,day]);
15620                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15621                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15622 //                    this.fill();
15623                     //Roo.log(this.formatDate(this.date));
15624                     this.setValue(this.formatDate(this.date));
15625                     this.hide();
15626                 }
15627                 break;
15628         }
15629     },
15630     
15631     setStartDate: function(startDate)
15632     {
15633         this.startDate = startDate || -Infinity;
15634         if (this.startDate !== -Infinity) {
15635             this.startDate = this.parseDate(this.startDate);
15636         }
15637         this.update();
15638         this.updateNavArrows();
15639     },
15640
15641     setEndDate: function(endDate)
15642     {
15643         this.endDate = endDate || Infinity;
15644         if (this.endDate !== Infinity) {
15645             this.endDate = this.parseDate(this.endDate);
15646         }
15647         this.update();
15648         this.updateNavArrows();
15649     },
15650     
15651     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15652     {
15653         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15654         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15655             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15656         }
15657         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15658             return parseInt(d, 10);
15659         });
15660         this.update();
15661         this.updateNavArrows();
15662     },
15663     
15664     updateNavArrows: function() 
15665     {
15666         if(this.singleMode){
15667             return;
15668         }
15669         
15670         var d = new Date(this.viewDate),
15671         year = d.getUTCFullYear(),
15672         month = d.getUTCMonth();
15673         
15674         Roo.each(this.picker().select('.prev', true).elements, function(v){
15675             v.show();
15676             switch (this.viewMode) {
15677                 case 0:
15678
15679                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15680                         v.hide();
15681                     }
15682                     break;
15683                 case 1:
15684                 case 2:
15685                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15686                         v.hide();
15687                     }
15688                     break;
15689             }
15690         });
15691         
15692         Roo.each(this.picker().select('.next', true).elements, function(v){
15693             v.show();
15694             switch (this.viewMode) {
15695                 case 0:
15696
15697                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15698                         v.hide();
15699                     }
15700                     break;
15701                 case 1:
15702                 case 2:
15703                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15704                         v.hide();
15705                     }
15706                     break;
15707             }
15708         })
15709     },
15710     
15711     moveMonth: function(date, dir)
15712     {
15713         if (!dir) return date;
15714         var new_date = new Date(date.valueOf()),
15715         day = new_date.getUTCDate(),
15716         month = new_date.getUTCMonth(),
15717         mag = Math.abs(dir),
15718         new_month, test;
15719         dir = dir > 0 ? 1 : -1;
15720         if (mag == 1){
15721             test = dir == -1
15722             // If going back one month, make sure month is not current month
15723             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15724             ? function(){
15725                 return new_date.getUTCMonth() == month;
15726             }
15727             // If going forward one month, make sure month is as expected
15728             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15729             : function(){
15730                 return new_date.getUTCMonth() != new_month;
15731             };
15732             new_month = month + dir;
15733             new_date.setUTCMonth(new_month);
15734             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15735             if (new_month < 0 || new_month > 11)
15736                 new_month = (new_month + 12) % 12;
15737         } else {
15738             // For magnitudes >1, move one month at a time...
15739             for (var i=0; i<mag; i++)
15740                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15741                 new_date = this.moveMonth(new_date, dir);
15742             // ...then reset the day, keeping it in the new month
15743             new_month = new_date.getUTCMonth();
15744             new_date.setUTCDate(day);
15745             test = function(){
15746                 return new_month != new_date.getUTCMonth();
15747             };
15748         }
15749         // Common date-resetting loop -- if date is beyond end of month, make it
15750         // end of month
15751         while (test()){
15752             new_date.setUTCDate(--day);
15753             new_date.setUTCMonth(new_month);
15754         }
15755         return new_date;
15756     },
15757
15758     moveYear: function(date, dir)
15759     {
15760         return this.moveMonth(date, dir*12);
15761     },
15762
15763     dateWithinRange: function(date)
15764     {
15765         return date >= this.startDate && date <= this.endDate;
15766     },
15767
15768     
15769     remove: function() 
15770     {
15771         this.picker().remove();
15772     }
15773    
15774 });
15775
15776 Roo.apply(Roo.bootstrap.DateField,  {
15777     
15778     head : {
15779         tag: 'thead',
15780         cn: [
15781         {
15782             tag: 'tr',
15783             cn: [
15784             {
15785                 tag: 'th',
15786                 cls: 'prev',
15787                 html: '<i class="fa fa-arrow-left"/>'
15788             },
15789             {
15790                 tag: 'th',
15791                 cls: 'switch',
15792                 colspan: '5'
15793             },
15794             {
15795                 tag: 'th',
15796                 cls: 'next',
15797                 html: '<i class="fa fa-arrow-right"/>'
15798             }
15799
15800             ]
15801         }
15802         ]
15803     },
15804     
15805     content : {
15806         tag: 'tbody',
15807         cn: [
15808         {
15809             tag: 'tr',
15810             cn: [
15811             {
15812                 tag: 'td',
15813                 colspan: '7'
15814             }
15815             ]
15816         }
15817         ]
15818     },
15819     
15820     footer : {
15821         tag: 'tfoot',
15822         cn: [
15823         {
15824             tag: 'tr',
15825             cn: [
15826             {
15827                 tag: 'th',
15828                 colspan: '7',
15829                 cls: 'today'
15830             }
15831                     
15832             ]
15833         }
15834         ]
15835     },
15836     
15837     dates:{
15838         en: {
15839             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15840             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15841             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15842             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15843             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15844             today: "Today"
15845         }
15846     },
15847     
15848     modes: [
15849     {
15850         clsName: 'days',
15851         navFnc: 'Month',
15852         navStep: 1
15853     },
15854     {
15855         clsName: 'months',
15856         navFnc: 'FullYear',
15857         navStep: 1
15858     },
15859     {
15860         clsName: 'years',
15861         navFnc: 'FullYear',
15862         navStep: 10
15863     }]
15864 });
15865
15866 Roo.apply(Roo.bootstrap.DateField,  {
15867   
15868     template : {
15869         tag: 'div',
15870         cls: 'datepicker dropdown-menu roo-dynamic',
15871         cn: [
15872         {
15873             tag: 'div',
15874             cls: 'datepicker-days',
15875             cn: [
15876             {
15877                 tag: 'table',
15878                 cls: 'table-condensed',
15879                 cn:[
15880                 Roo.bootstrap.DateField.head,
15881                 {
15882                     tag: 'tbody'
15883                 },
15884                 Roo.bootstrap.DateField.footer
15885                 ]
15886             }
15887             ]
15888         },
15889         {
15890             tag: 'div',
15891             cls: 'datepicker-months',
15892             cn: [
15893             {
15894                 tag: 'table',
15895                 cls: 'table-condensed',
15896                 cn:[
15897                 Roo.bootstrap.DateField.head,
15898                 Roo.bootstrap.DateField.content,
15899                 Roo.bootstrap.DateField.footer
15900                 ]
15901             }
15902             ]
15903         },
15904         {
15905             tag: 'div',
15906             cls: 'datepicker-years',
15907             cn: [
15908             {
15909                 tag: 'table',
15910                 cls: 'table-condensed',
15911                 cn:[
15912                 Roo.bootstrap.DateField.head,
15913                 Roo.bootstrap.DateField.content,
15914                 Roo.bootstrap.DateField.footer
15915                 ]
15916             }
15917             ]
15918         }
15919         ]
15920     }
15921 });
15922
15923  
15924
15925  /*
15926  * - LGPL
15927  *
15928  * TimeField
15929  * 
15930  */
15931
15932 /**
15933  * @class Roo.bootstrap.TimeField
15934  * @extends Roo.bootstrap.Input
15935  * Bootstrap DateField class
15936  * 
15937  * 
15938  * @constructor
15939  * Create a new TimeField
15940  * @param {Object} config The config object
15941  */
15942
15943 Roo.bootstrap.TimeField = function(config){
15944     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15945     this.addEvents({
15946             /**
15947              * @event show
15948              * Fires when this field show.
15949              * @param {Roo.bootstrap.DateField} thisthis
15950              * @param {Mixed} date The date value
15951              */
15952             show : true,
15953             /**
15954              * @event show
15955              * Fires when this field hide.
15956              * @param {Roo.bootstrap.DateField} this
15957              * @param {Mixed} date The date value
15958              */
15959             hide : true,
15960             /**
15961              * @event select
15962              * Fires when select a date.
15963              * @param {Roo.bootstrap.DateField} this
15964              * @param {Mixed} date The date value
15965              */
15966             select : true
15967         });
15968 };
15969
15970 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15971     
15972     /**
15973      * @cfg {String} format
15974      * The default time format string which can be overriden for localization support.  The format must be
15975      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15976      */
15977     format : "H:i",
15978        
15979     onRender: function(ct, position)
15980     {
15981         
15982         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15983                 
15984         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15985         
15986         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15987         
15988         this.pop = this.picker().select('>.datepicker-time',true).first();
15989         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15990         
15991         this.picker().on('mousedown', this.onMousedown, this);
15992         this.picker().on('click', this.onClick, this);
15993         
15994         this.picker().addClass('datepicker-dropdown');
15995     
15996         this.fillTime();
15997         this.update();
15998             
15999         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16000         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16001         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16002         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16003         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16004         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16005
16006     },
16007     
16008     fireKey: function(e){
16009         if (!this.picker().isVisible()){
16010             if (e.keyCode == 27) { // allow escape to hide and re-show picker
16011                 this.show();
16012             }
16013             return;
16014         }
16015
16016         e.preventDefault();
16017         
16018         switch(e.keyCode){
16019             case 27: // escape
16020                 this.hide();
16021                 break;
16022             case 37: // left
16023             case 39: // right
16024                 this.onTogglePeriod();
16025                 break;
16026             case 38: // up
16027                 this.onIncrementMinutes();
16028                 break;
16029             case 40: // down
16030                 this.onDecrementMinutes();
16031                 break;
16032             case 13: // enter
16033             case 9: // tab
16034                 this.setTime();
16035                 break;
16036         }
16037     },
16038     
16039     onClick: function(e) {
16040         e.stopPropagation();
16041         e.preventDefault();
16042     },
16043     
16044     picker : function()
16045     {
16046         return this.el.select('.datepicker', true).first();
16047     },
16048     
16049     fillTime: function()
16050     {    
16051         var time = this.pop.select('tbody', true).first();
16052         
16053         time.dom.innerHTML = '';
16054         
16055         time.createChild({
16056             tag: 'tr',
16057             cn: [
16058                 {
16059                     tag: 'td',
16060                     cn: [
16061                         {
16062                             tag: 'a',
16063                             href: '#',
16064                             cls: 'btn',
16065                             cn: [
16066                                 {
16067                                     tag: 'span',
16068                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
16069                                 }
16070                             ]
16071                         } 
16072                     ]
16073                 },
16074                 {
16075                     tag: 'td',
16076                     cls: 'separator'
16077                 },
16078                 {
16079                     tag: 'td',
16080                     cn: [
16081                         {
16082                             tag: 'a',
16083                             href: '#',
16084                             cls: 'btn',
16085                             cn: [
16086                                 {
16087                                     tag: 'span',
16088                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
16089                                 }
16090                             ]
16091                         }
16092                     ]
16093                 },
16094                 {
16095                     tag: 'td',
16096                     cls: 'separator'
16097                 }
16098             ]
16099         });
16100         
16101         time.createChild({
16102             tag: 'tr',
16103             cn: [
16104                 {
16105                     tag: 'td',
16106                     cn: [
16107                         {
16108                             tag: 'span',
16109                             cls: 'timepicker-hour',
16110                             html: '00'
16111                         }  
16112                     ]
16113                 },
16114                 {
16115                     tag: 'td',
16116                     cls: 'separator',
16117                     html: ':'
16118                 },
16119                 {
16120                     tag: 'td',
16121                     cn: [
16122                         {
16123                             tag: 'span',
16124                             cls: 'timepicker-minute',
16125                             html: '00'
16126                         }  
16127                     ]
16128                 },
16129                 {
16130                     tag: 'td',
16131                     cls: 'separator'
16132                 },
16133                 {
16134                     tag: 'td',
16135                     cn: [
16136                         {
16137                             tag: 'button',
16138                             type: 'button',
16139                             cls: 'btn btn-primary period',
16140                             html: 'AM'
16141                             
16142                         }
16143                     ]
16144                 }
16145             ]
16146         });
16147         
16148         time.createChild({
16149             tag: 'tr',
16150             cn: [
16151                 {
16152                     tag: 'td',
16153                     cn: [
16154                         {
16155                             tag: 'a',
16156                             href: '#',
16157                             cls: 'btn',
16158                             cn: [
16159                                 {
16160                                     tag: 'span',
16161                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16162                                 }
16163                             ]
16164                         }
16165                     ]
16166                 },
16167                 {
16168                     tag: 'td',
16169                     cls: 'separator'
16170                 },
16171                 {
16172                     tag: 'td',
16173                     cn: [
16174                         {
16175                             tag: 'a',
16176                             href: '#',
16177                             cls: 'btn',
16178                             cn: [
16179                                 {
16180                                     tag: 'span',
16181                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16182                                 }
16183                             ]
16184                         }
16185                     ]
16186                 },
16187                 {
16188                     tag: 'td',
16189                     cls: 'separator'
16190                 }
16191             ]
16192         });
16193         
16194     },
16195     
16196     update: function()
16197     {
16198         
16199         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16200         
16201         this.fill();
16202     },
16203     
16204     fill: function() 
16205     {
16206         var hours = this.time.getHours();
16207         var minutes = this.time.getMinutes();
16208         var period = 'AM';
16209         
16210         if(hours > 11){
16211             period = 'PM';
16212         }
16213         
16214         if(hours == 0){
16215             hours = 12;
16216         }
16217         
16218         
16219         if(hours > 12){
16220             hours = hours - 12;
16221         }
16222         
16223         if(hours < 10){
16224             hours = '0' + hours;
16225         }
16226         
16227         if(minutes < 10){
16228             minutes = '0' + minutes;
16229         }
16230         
16231         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16232         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16233         this.pop.select('button', true).first().dom.innerHTML = period;
16234         
16235     },
16236     
16237     place: function()
16238     {   
16239         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16240         
16241         var cls = ['bottom'];
16242         
16243         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16244             cls.pop();
16245             cls.push('top');
16246         }
16247         
16248         cls.push('right');
16249         
16250         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16251             cls.pop();
16252             cls.push('left');
16253         }
16254         
16255         this.picker().addClass(cls.join('-'));
16256         
16257         var _this = this;
16258         
16259         Roo.each(cls, function(c){
16260             if(c == 'bottom'){
16261                 _this.picker().setTop(_this.inputEl().getHeight());
16262                 return;
16263             }
16264             if(c == 'top'){
16265                 _this.picker().setTop(0 - _this.picker().getHeight());
16266                 return;
16267             }
16268             
16269             if(c == 'left'){
16270                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16271                 return;
16272             }
16273             if(c == 'right'){
16274                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16275                 return;
16276             }
16277         });
16278         
16279     },
16280   
16281     onFocus : function()
16282     {
16283         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16284         this.show();
16285     },
16286     
16287     onBlur : function()
16288     {
16289         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16290         this.hide();
16291     },
16292     
16293     show : function()
16294     {
16295         this.picker().show();
16296         this.pop.show();
16297         this.update();
16298         this.place();
16299         
16300         this.fireEvent('show', this, this.date);
16301     },
16302     
16303     hide : function()
16304     {
16305         this.picker().hide();
16306         this.pop.hide();
16307         
16308         this.fireEvent('hide', this, this.date);
16309     },
16310     
16311     setTime : function()
16312     {
16313         this.hide();
16314         this.setValue(this.time.format(this.format));
16315         
16316         this.fireEvent('select', this, this.date);
16317         
16318         
16319     },
16320     
16321     onMousedown: function(e){
16322         e.stopPropagation();
16323         e.preventDefault();
16324     },
16325     
16326     onIncrementHours: function()
16327     {
16328         Roo.log('onIncrementHours');
16329         this.time = this.time.add(Date.HOUR, 1);
16330         this.update();
16331         
16332     },
16333     
16334     onDecrementHours: function()
16335     {
16336         Roo.log('onDecrementHours');
16337         this.time = this.time.add(Date.HOUR, -1);
16338         this.update();
16339     },
16340     
16341     onIncrementMinutes: function()
16342     {
16343         Roo.log('onIncrementMinutes');
16344         this.time = this.time.add(Date.MINUTE, 1);
16345         this.update();
16346     },
16347     
16348     onDecrementMinutes: function()
16349     {
16350         Roo.log('onDecrementMinutes');
16351         this.time = this.time.add(Date.MINUTE, -1);
16352         this.update();
16353     },
16354     
16355     onTogglePeriod: function()
16356     {
16357         Roo.log('onTogglePeriod');
16358         this.time = this.time.add(Date.HOUR, 12);
16359         this.update();
16360     }
16361     
16362    
16363 });
16364
16365 Roo.apply(Roo.bootstrap.TimeField,  {
16366     
16367     content : {
16368         tag: 'tbody',
16369         cn: [
16370             {
16371                 tag: 'tr',
16372                 cn: [
16373                 {
16374                     tag: 'td',
16375                     colspan: '7'
16376                 }
16377                 ]
16378             }
16379         ]
16380     },
16381     
16382     footer : {
16383         tag: 'tfoot',
16384         cn: [
16385             {
16386                 tag: 'tr',
16387                 cn: [
16388                 {
16389                     tag: 'th',
16390                     colspan: '7',
16391                     cls: '',
16392                     cn: [
16393                         {
16394                             tag: 'button',
16395                             cls: 'btn btn-info ok',
16396                             html: 'OK'
16397                         }
16398                     ]
16399                 }
16400
16401                 ]
16402             }
16403         ]
16404     }
16405 });
16406
16407 Roo.apply(Roo.bootstrap.TimeField,  {
16408   
16409     template : {
16410         tag: 'div',
16411         cls: 'datepicker dropdown-menu',
16412         cn: [
16413             {
16414                 tag: 'div',
16415                 cls: 'datepicker-time',
16416                 cn: [
16417                 {
16418                     tag: 'table',
16419                     cls: 'table-condensed',
16420                     cn:[
16421                     Roo.bootstrap.TimeField.content,
16422                     Roo.bootstrap.TimeField.footer
16423                     ]
16424                 }
16425                 ]
16426             }
16427         ]
16428     }
16429 });
16430
16431  
16432
16433  /*
16434  * - LGPL
16435  *
16436  * MonthField
16437  * 
16438  */
16439
16440 /**
16441  * @class Roo.bootstrap.MonthField
16442  * @extends Roo.bootstrap.Input
16443  * Bootstrap MonthField class
16444  * 
16445  * @cfg {String} language default en
16446  * 
16447  * @constructor
16448  * Create a new MonthField
16449  * @param {Object} config The config object
16450  */
16451
16452 Roo.bootstrap.MonthField = function(config){
16453     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16454     
16455     this.addEvents({
16456         /**
16457          * @event show
16458          * Fires when this field show.
16459          * @param {Roo.bootstrap.MonthField} this
16460          * @param {Mixed} date The date value
16461          */
16462         show : true,
16463         /**
16464          * @event show
16465          * Fires when this field hide.
16466          * @param {Roo.bootstrap.MonthField} this
16467          * @param {Mixed} date The date value
16468          */
16469         hide : true,
16470         /**
16471          * @event select
16472          * Fires when select a date.
16473          * @param {Roo.bootstrap.MonthField} this
16474          * @param {String} oldvalue The old value
16475          * @param {String} newvalue The new value
16476          */
16477         select : true
16478     });
16479 };
16480
16481 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16482     
16483     onRender: function(ct, position)
16484     {
16485         
16486         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16487         
16488         this.language = this.language || 'en';
16489         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16490         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16491         
16492         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16493         this.isInline = false;
16494         this.isInput = true;
16495         this.component = this.el.select('.add-on', true).first() || false;
16496         this.component = (this.component && this.component.length === 0) ? false : this.component;
16497         this.hasInput = this.component && this.inputEL().length;
16498         
16499         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16500         
16501         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16502         
16503         this.picker().on('mousedown', this.onMousedown, this);
16504         this.picker().on('click', this.onClick, this);
16505         
16506         this.picker().addClass('datepicker-dropdown');
16507         
16508         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16509             v.setStyle('width', '189px');
16510         });
16511         
16512         this.fillMonths();
16513         
16514         this.update();
16515         
16516         if(this.isInline) {
16517             this.show();
16518         }
16519         
16520     },
16521     
16522     setValue: function(v, suppressEvent)
16523     {   
16524         var o = this.getValue();
16525         
16526         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16527         
16528         this.update();
16529
16530         if(suppressEvent !== true){
16531             this.fireEvent('select', this, o, v);
16532         }
16533         
16534     },
16535     
16536     getValue: function()
16537     {
16538         return this.value;
16539     },
16540     
16541     onClick: function(e) 
16542     {
16543         e.stopPropagation();
16544         e.preventDefault();
16545         
16546         var target = e.getTarget();
16547         
16548         if(target.nodeName.toLowerCase() === 'i'){
16549             target = Roo.get(target).dom.parentNode;
16550         }
16551         
16552         var nodeName = target.nodeName;
16553         var className = target.className;
16554         var html = target.innerHTML;
16555         
16556         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16557             return;
16558         }
16559         
16560         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16561         
16562         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16563         
16564         this.hide();
16565                         
16566     },
16567     
16568     picker : function()
16569     {
16570         return this.pickerEl;
16571     },
16572     
16573     fillMonths: function()
16574     {    
16575         var i = 0;
16576         var months = this.picker().select('>.datepicker-months td', true).first();
16577         
16578         months.dom.innerHTML = '';
16579         
16580         while (i < 12) {
16581             var month = {
16582                 tag: 'span',
16583                 cls: 'month',
16584                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16585             }
16586             
16587             months.createChild(month);
16588         }
16589         
16590     },
16591     
16592     update: function()
16593     {
16594         var _this = this;
16595         
16596         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16597             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16598         }
16599         
16600         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16601             e.removeClass('active');
16602             
16603             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16604                 e.addClass('active');
16605             }
16606         })
16607     },
16608     
16609     place: function()
16610     {
16611         if(this.isInline) return;
16612         
16613         this.picker().removeClass(['bottom', 'top']);
16614         
16615         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16616             /*
16617              * place to the top of element!
16618              *
16619              */
16620             
16621             this.picker().addClass('top');
16622             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16623             
16624             return;
16625         }
16626         
16627         this.picker().addClass('bottom');
16628         
16629         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16630     },
16631     
16632     onFocus : function()
16633     {
16634         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16635         this.show();
16636     },
16637     
16638     onBlur : function()
16639     {
16640         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16641         
16642         var d = this.inputEl().getValue();
16643         
16644         this.setValue(d);
16645                 
16646         this.hide();
16647     },
16648     
16649     show : function()
16650     {
16651         this.picker().show();
16652         this.picker().select('>.datepicker-months', true).first().show();
16653         this.update();
16654         this.place();
16655         
16656         this.fireEvent('show', this, this.date);
16657     },
16658     
16659     hide : function()
16660     {
16661         if(this.isInline) return;
16662         this.picker().hide();
16663         this.fireEvent('hide', this, this.date);
16664         
16665     },
16666     
16667     onMousedown: function(e)
16668     {
16669         e.stopPropagation();
16670         e.preventDefault();
16671     },
16672     
16673     keyup: function(e)
16674     {
16675         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16676         this.update();
16677     },
16678
16679     fireKey: function(e)
16680     {
16681         if (!this.picker().isVisible()){
16682             if (e.keyCode == 27) // allow escape to hide and re-show picker
16683                 this.show();
16684             return;
16685         }
16686         
16687         var dir;
16688         
16689         switch(e.keyCode){
16690             case 27: // escape
16691                 this.hide();
16692                 e.preventDefault();
16693                 break;
16694             case 37: // left
16695             case 39: // right
16696                 dir = e.keyCode == 37 ? -1 : 1;
16697                 
16698                 this.vIndex = this.vIndex + dir;
16699                 
16700                 if(this.vIndex < 0){
16701                     this.vIndex = 0;
16702                 }
16703                 
16704                 if(this.vIndex > 11){
16705                     this.vIndex = 11;
16706                 }
16707                 
16708                 if(isNaN(this.vIndex)){
16709                     this.vIndex = 0;
16710                 }
16711                 
16712                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16713                 
16714                 break;
16715             case 38: // up
16716             case 40: // down
16717                 
16718                 dir = e.keyCode == 38 ? -1 : 1;
16719                 
16720                 this.vIndex = this.vIndex + dir * 4;
16721                 
16722                 if(this.vIndex < 0){
16723                     this.vIndex = 0;
16724                 }
16725                 
16726                 if(this.vIndex > 11){
16727                     this.vIndex = 11;
16728                 }
16729                 
16730                 if(isNaN(this.vIndex)){
16731                     this.vIndex = 0;
16732                 }
16733                 
16734                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16735                 break;
16736                 
16737             case 13: // enter
16738                 
16739                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16740                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16741                 }
16742                 
16743                 this.hide();
16744                 e.preventDefault();
16745                 break;
16746             case 9: // tab
16747                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16748                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16749                 }
16750                 this.hide();
16751                 break;
16752             case 16: // shift
16753             case 17: // ctrl
16754             case 18: // alt
16755                 break;
16756             default :
16757                 this.hide();
16758                 
16759         }
16760     },
16761     
16762     remove: function() 
16763     {
16764         this.picker().remove();
16765     }
16766    
16767 });
16768
16769 Roo.apply(Roo.bootstrap.MonthField,  {
16770     
16771     content : {
16772         tag: 'tbody',
16773         cn: [
16774         {
16775             tag: 'tr',
16776             cn: [
16777             {
16778                 tag: 'td',
16779                 colspan: '7'
16780             }
16781             ]
16782         }
16783         ]
16784     },
16785     
16786     dates:{
16787         en: {
16788             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16789             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16790         }
16791     }
16792 });
16793
16794 Roo.apply(Roo.bootstrap.MonthField,  {
16795   
16796     template : {
16797         tag: 'div',
16798         cls: 'datepicker dropdown-menu roo-dynamic',
16799         cn: [
16800             {
16801                 tag: 'div',
16802                 cls: 'datepicker-months',
16803                 cn: [
16804                 {
16805                     tag: 'table',
16806                     cls: 'table-condensed',
16807                     cn:[
16808                         Roo.bootstrap.DateField.content
16809                     ]
16810                 }
16811                 ]
16812             }
16813         ]
16814     }
16815 });
16816
16817  
16818
16819  
16820  /*
16821  * - LGPL
16822  *
16823  * CheckBox
16824  * 
16825  */
16826
16827 /**
16828  * @class Roo.bootstrap.CheckBox
16829  * @extends Roo.bootstrap.Input
16830  * Bootstrap CheckBox class
16831  * 
16832  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16833  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16834  * @cfg {String} boxLabel The text that appears beside the checkbox
16835  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16836  * @cfg {Boolean} checked initnal the element
16837  * @cfg {Boolean} inline inline the element (default false)
16838  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16839  * 
16840  * @constructor
16841  * Create a new CheckBox
16842  * @param {Object} config The config object
16843  */
16844
16845 Roo.bootstrap.CheckBox = function(config){
16846     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16847    
16848     this.addEvents({
16849         /**
16850         * @event check
16851         * Fires when the element is checked or unchecked.
16852         * @param {Roo.bootstrap.CheckBox} this This input
16853         * @param {Boolean} checked The new checked value
16854         */
16855        check : true
16856     });
16857     
16858 };
16859
16860 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16861   
16862     inputType: 'checkbox',
16863     inputValue: 1,
16864     valueOff: 0,
16865     boxLabel: false,
16866     checked: false,
16867     weight : false,
16868     inline: false,
16869     
16870     getAutoCreate : function()
16871     {
16872         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16873         
16874         var id = Roo.id();
16875         
16876         var cfg = {};
16877         
16878         cfg.cls = 'form-group ' + this.inputType; //input-group
16879         
16880         if(this.inline){
16881             cfg.cls += ' ' + this.inputType + '-inline';
16882         }
16883         
16884         var input =  {
16885             tag: 'input',
16886             id : id,
16887             type : this.inputType,
16888             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16889             cls : 'roo-' + this.inputType, //'form-box',
16890             placeholder : this.placeholder || ''
16891             
16892         };
16893         
16894         if (this.weight) { // Validity check?
16895             cfg.cls += " " + this.inputType + "-" + this.weight;
16896         }
16897         
16898         if (this.disabled) {
16899             input.disabled=true;
16900         }
16901         
16902         if(this.checked){
16903             input.checked = this.checked;
16904         }
16905         
16906         if (this.name) {
16907             input.name = this.name;
16908         }
16909         
16910         if (this.size) {
16911             input.cls += ' input-' + this.size;
16912         }
16913         
16914         var settings=this;
16915         
16916         ['xs','sm','md','lg'].map(function(size){
16917             if (settings[size]) {
16918                 cfg.cls += ' col-' + size + '-' + settings[size];
16919             }
16920         });
16921         
16922         var inputblock = input;
16923          
16924         if (this.before || this.after) {
16925             
16926             inputblock = {
16927                 cls : 'input-group',
16928                 cn :  [] 
16929             };
16930             
16931             if (this.before) {
16932                 inputblock.cn.push({
16933                     tag :'span',
16934                     cls : 'input-group-addon',
16935                     html : this.before
16936                 });
16937             }
16938             
16939             inputblock.cn.push(input);
16940             
16941             if (this.after) {
16942                 inputblock.cn.push({
16943                     tag :'span',
16944                     cls : 'input-group-addon',
16945                     html : this.after
16946                 });
16947             }
16948             
16949         }
16950         
16951         if (align ==='left' && this.fieldLabel.length) {
16952                 Roo.log("left and has label");
16953                 cfg.cn = [
16954                     
16955                     {
16956                         tag: 'label',
16957                         'for' :  id,
16958                         cls : 'control-label col-md-' + this.labelWidth,
16959                         html : this.fieldLabel
16960                         
16961                     },
16962                     {
16963                         cls : "col-md-" + (12 - this.labelWidth), 
16964                         cn: [
16965                             inputblock
16966                         ]
16967                     }
16968                     
16969                 ];
16970         } else if ( this.fieldLabel.length) {
16971                 Roo.log(" label");
16972                 cfg.cn = [
16973                    
16974                     {
16975                         tag: this.boxLabel ? 'span' : 'label',
16976                         'for': id,
16977                         cls: 'control-label box-input-label',
16978                         //cls : 'input-group-addon',
16979                         html : this.fieldLabel
16980                         
16981                     },
16982                     
16983                     inputblock
16984                     
16985                 ];
16986
16987         } else {
16988             
16989                 Roo.log(" no label && no align");
16990                 cfg.cn = [  inputblock ] ;
16991                 
16992                 
16993         }
16994         if(this.boxLabel){
16995              var boxLabelCfg = {
16996                 tag: 'label',
16997                 //'for': id, // box label is handled by onclick - so no for...
16998                 cls: 'box-label',
16999                 html: this.boxLabel
17000             }
17001             
17002             if(this.tooltip){
17003                 boxLabelCfg.tooltip = this.tooltip;
17004             }
17005              
17006             cfg.cn.push(boxLabelCfg);
17007         }
17008         
17009         
17010        
17011         return cfg;
17012         
17013     },
17014     
17015     /**
17016      * return the real input element.
17017      */
17018     inputEl: function ()
17019     {
17020         return this.el.select('input.roo-' + this.inputType,true).first();
17021     },
17022     
17023     labelEl: function()
17024     {
17025         return this.el.select('label.control-label',true).first();
17026     },
17027     /* depricated... */
17028     
17029     label: function()
17030     {
17031         return this.labelEl();
17032     },
17033     
17034     initEvents : function()
17035     {
17036 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17037         
17038         this.inputEl().on('click', this.onClick,  this);
17039         
17040         if (this.boxLabel) { 
17041             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
17042         }
17043         
17044         this.startValue = this.getValue();
17045         
17046         if(this.groupId){
17047             Roo.bootstrap.CheckBox.register(this);
17048         }
17049     },
17050     
17051     onClick : function()
17052     {   
17053         this.setChecked(!this.checked);
17054     },
17055     
17056     setChecked : function(state,suppressEvent)
17057     {
17058         this.startValue = this.getValue();
17059         
17060         if(this.inputType == 'radio'){
17061             
17062             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17063                 e.dom.checked = false;
17064             });
17065             
17066             this.inputEl().dom.checked = true;
17067             
17068             this.inputEl().dom.value = this.inputValue;
17069             
17070             if(suppressEvent !== true){
17071                 this.fireEvent('check', this, true);
17072             }
17073             
17074             this.validate();
17075             
17076             return;
17077         }
17078         
17079         this.checked = state;
17080         
17081         this.inputEl().dom.checked = state;
17082         
17083         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17084         
17085         if(suppressEvent !== true){
17086             this.fireEvent('check', this, state);
17087         }
17088         
17089         this.validate();
17090     },
17091     
17092     getValue : function()
17093     {
17094         if(this.inputType == 'radio'){
17095             return this.getGroupValue();
17096         }
17097         
17098         return this.inputEl().getValue();
17099         
17100     },
17101     
17102     getGroupValue : function()
17103     {
17104         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17105             return '';
17106         }
17107         
17108         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17109     },
17110     
17111     setValue : function(v,suppressEvent)
17112     {
17113         if(this.inputType == 'radio'){
17114             this.setGroupValue(v, suppressEvent);
17115             return;
17116         }
17117         
17118         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17119         
17120         this.validate();
17121     },
17122     
17123     setGroupValue : function(v, suppressEvent)
17124     {
17125         this.startValue = this.getValue();
17126         
17127         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17128             e.dom.checked = false;
17129             
17130             if(e.dom.value == v){
17131                 e.dom.checked = true;
17132             }
17133         });
17134         
17135         if(suppressEvent !== true){
17136             this.fireEvent('check', this, true);
17137         }
17138
17139         this.validate();
17140         
17141         return;
17142     },
17143     
17144     validate : function()
17145     {
17146         if(
17147                 this.disabled || 
17148                 (this.inputType == 'radio' && this.validateRadio()) ||
17149                 (this.inputType == 'checkbox' && this.validateCheckbox())
17150         ){
17151             this.markValid();
17152             return true;
17153         }
17154         
17155         this.markInvalid();
17156         return false;
17157     },
17158     
17159     validateRadio : function()
17160     {
17161         var valid = false;
17162         
17163         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17164             if(!e.dom.checked){
17165                 return;
17166             }
17167             
17168             valid = true;
17169             
17170             return false;
17171         });
17172         
17173         return valid;
17174     },
17175     
17176     validateCheckbox : function()
17177     {
17178         if(!this.groupId){
17179             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17180         }
17181         
17182         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17183         
17184         if(!group){
17185             return false;
17186         }
17187         
17188         var r = false;
17189         
17190         for(var i in group){
17191             if(r){
17192                 break;
17193             }
17194             
17195             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17196         }
17197         
17198         return r;
17199     },
17200     
17201     /**
17202      * Mark this field as valid
17203      */
17204     markValid : function()
17205     {
17206         if(this.allowBlank){
17207             return;
17208         }
17209         
17210         var _this = this;
17211         
17212         this.fireEvent('valid', this);
17213         
17214         if(this.inputType == 'radio'){
17215             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17216                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17217                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17218             });
17219             
17220             return;
17221         }
17222         
17223         if(!this.groupId){
17224             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17225             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17226             return;
17227         }
17228         
17229         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17230             
17231         if(!group){
17232             return;
17233         }
17234         
17235         for(var i in group){
17236             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17237             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17238         }
17239     },
17240     
17241      /**
17242      * Mark this field as invalid
17243      * @param {String} msg The validation message
17244      */
17245     markInvalid : function(msg)
17246     {
17247         if(this.allowBlank){
17248             return;
17249         }
17250         
17251         var _this = this;
17252         
17253         this.fireEvent('invalid', this, msg);
17254         
17255         if(this.inputType == 'radio'){
17256             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17257                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17258                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17259             });
17260             
17261             return;
17262         }
17263         
17264         if(!this.groupId){
17265             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17266             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17267             return;
17268         }
17269         
17270         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17271             
17272         if(!group){
17273             return;
17274         }
17275         
17276         for(var i in group){
17277             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17278             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17279         }
17280         
17281     }
17282     
17283 });
17284
17285 Roo.apply(Roo.bootstrap.CheckBox, {
17286     
17287     groups: {},
17288     
17289      /**
17290     * register a CheckBox Group
17291     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17292     */
17293     register : function(checkbox)
17294     {
17295         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17296             this.groups[checkbox.groupId] = {};
17297         }
17298         
17299         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17300             return;
17301         }
17302         
17303         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17304         
17305     },
17306     /**
17307     * fetch a CheckBox Group based on the group ID
17308     * @param {string} the group ID
17309     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17310     */
17311     get: function(groupId) {
17312         if (typeof(this.groups[groupId]) == 'undefined') {
17313             return false;
17314         }
17315         
17316         return this.groups[groupId] ;
17317     }
17318     
17319     
17320 });
17321 /*
17322  * - LGPL
17323  *
17324  * Radio
17325  *
17326  *
17327  * not inline
17328  *<div class="radio">
17329   <label>
17330     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17331     Option one is this and that&mdash;be sure to include why it's great
17332   </label>
17333 </div>
17334  *
17335  *
17336  *inline
17337  *<span>
17338  *<label class="radio-inline">fieldLabel</label>
17339  *<label class="radio-inline">
17340   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17341 </label>
17342 <span>
17343  * 
17344  * 
17345  */
17346
17347 /**
17348  * @class Roo.bootstrap.Radio
17349  * @extends Roo.bootstrap.CheckBox
17350  * Bootstrap Radio class
17351
17352  * @constructor
17353  * Create a new Radio
17354  * @param {Object} config The config object
17355  */
17356
17357 Roo.bootstrap.Radio = function(config){
17358     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17359    
17360 };
17361
17362 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17363     
17364     inputType: 'radio',
17365     inputValue: '',
17366     valueOff: '',
17367     
17368     getAutoCreate : function()
17369     {
17370         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17371         align = align || 'left'; // default...
17372         
17373         
17374         
17375         var id = Roo.id();
17376         
17377         var cfg = {
17378                 tag : this.inline ? 'span' : 'div',
17379                 cls : '',
17380                 cn : []
17381         };
17382         
17383         var inline = this.inline ? ' radio-inline' : '';
17384         
17385         var lbl = {
17386                 tag: 'label' ,
17387                 // does not need for, as we wrap the input with it..
17388                 'for' : id,
17389                 cls : 'control-label box-label' + inline,
17390                 cn : []
17391         };
17392         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17393         
17394         var fieldLabel = {
17395             tag: 'label' ,
17396             //cls : 'control-label' + inline,
17397             html : this.fieldLabel,
17398             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17399         };
17400         
17401  
17402         
17403         
17404         var input =  {
17405             tag: 'input',
17406             id : id,
17407             type : this.inputType,
17408             //value : (!this.checked) ? this.valueOff : this.inputValue,
17409             value : this.inputValue,
17410             cls : 'roo-radio',
17411             placeholder : this.placeholder || '' // ?? needed????
17412             
17413         };
17414         if (this.weight) { // Validity check?
17415             input.cls += " radio-" + this.weight;
17416         }
17417         if (this.disabled) {
17418             input.disabled=true;
17419         }
17420         
17421         if(this.checked){
17422             input.checked = this.checked;
17423         }
17424         
17425         if (this.name) {
17426             input.name = this.name;
17427         }
17428         
17429         if (this.size) {
17430             input.cls += ' input-' + this.size;
17431         }
17432         
17433         //?? can span's inline have a width??
17434         
17435         var settings=this;
17436         ['xs','sm','md','lg'].map(function(size){
17437             if (settings[size]) {
17438                 cfg.cls += ' col-' + size + '-' + settings[size];
17439             }
17440         });
17441         
17442         var inputblock = input;
17443         
17444         if (this.before || this.after) {
17445             
17446             inputblock = {
17447                 cls : 'input-group',
17448                 tag : 'span',
17449                 cn :  [] 
17450             };
17451             if (this.before) {
17452                 inputblock.cn.push({
17453                     tag :'span',
17454                     cls : 'input-group-addon',
17455                     html : this.before
17456                 });
17457             }
17458             inputblock.cn.push(input);
17459             if (this.after) {
17460                 inputblock.cn.push({
17461                     tag :'span',
17462                     cls : 'input-group-addon',
17463                     html : this.after
17464                 });
17465             }
17466             
17467         };
17468         
17469         
17470         if (this.fieldLabel && this.fieldLabel.length) {
17471             cfg.cn.push(fieldLabel);
17472         }
17473        
17474         // normal bootstrap puts the input inside the label.
17475         // however with our styled version - it has to go after the input.
17476        
17477         //lbl.cn.push(inputblock);
17478         
17479         var lblwrap =  {
17480             tag: 'span',
17481             cls: 'radio' + inline,
17482             cn: [
17483                 inputblock,
17484                 lbl
17485             ]
17486         };
17487         
17488         cfg.cn.push( lblwrap);
17489         
17490         if(this.boxLabel){
17491             lbl.cn.push({
17492                 tag: 'span',
17493                 html: this.boxLabel
17494             })
17495         }
17496          
17497         
17498         return cfg;
17499         
17500     },
17501     
17502     initEvents : function()
17503     {
17504 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17505         
17506         this.inputEl().on('click', this.onClick,  this);
17507         if (this.boxLabel) {
17508             Roo.log('find label')
17509             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17510         }
17511         
17512     },
17513     
17514     inputEl: function ()
17515     {
17516         return this.el.select('input.roo-radio',true).first();
17517     },
17518     onClick : function()
17519     {   
17520         Roo.log("click");
17521         this.setChecked(true);
17522     },
17523     
17524     setChecked : function(state,suppressEvent)
17525     {
17526         if(state){
17527             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17528                 v.dom.checked = false;
17529             });
17530         }
17531         Roo.log(this.inputEl().dom);
17532         this.checked = state;
17533         this.inputEl().dom.checked = state;
17534         
17535         if(suppressEvent !== true){
17536             this.fireEvent('check', this, state);
17537         }
17538         
17539         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17540         
17541     },
17542     
17543     getGroupValue : function()
17544     {
17545         var value = '';
17546         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17547             if(v.dom.checked == true){
17548                 value = v.dom.value;
17549             }
17550         });
17551         
17552         return value;
17553     },
17554     
17555     /**
17556      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17557      * @return {Mixed} value The field value
17558      */
17559     getValue : function(){
17560         return this.getGroupValue();
17561     }
17562     
17563 });
17564
17565  
17566 //<script type="text/javascript">
17567
17568 /*
17569  * Based  Ext JS Library 1.1.1
17570  * Copyright(c) 2006-2007, Ext JS, LLC.
17571  * LGPL
17572  *
17573  */
17574  
17575 /**
17576  * @class Roo.HtmlEditorCore
17577  * @extends Roo.Component
17578  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17579  *
17580  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17581  */
17582
17583 Roo.HtmlEditorCore = function(config){
17584     
17585     
17586     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17587     
17588     
17589     this.addEvents({
17590         /**
17591          * @event initialize
17592          * Fires when the editor is fully initialized (including the iframe)
17593          * @param {Roo.HtmlEditorCore} this
17594          */
17595         initialize: true,
17596         /**
17597          * @event activate
17598          * Fires when the editor is first receives the focus. Any insertion must wait
17599          * until after this event.
17600          * @param {Roo.HtmlEditorCore} this
17601          */
17602         activate: true,
17603          /**
17604          * @event beforesync
17605          * Fires before the textarea is updated with content from the editor iframe. Return false
17606          * to cancel the sync.
17607          * @param {Roo.HtmlEditorCore} this
17608          * @param {String} html
17609          */
17610         beforesync: true,
17611          /**
17612          * @event beforepush
17613          * Fires before the iframe editor is updated with content from the textarea. Return false
17614          * to cancel the push.
17615          * @param {Roo.HtmlEditorCore} this
17616          * @param {String} html
17617          */
17618         beforepush: true,
17619          /**
17620          * @event sync
17621          * Fires when the textarea is updated with content from the editor iframe.
17622          * @param {Roo.HtmlEditorCore} this
17623          * @param {String} html
17624          */
17625         sync: true,
17626          /**
17627          * @event push
17628          * Fires when the iframe editor is updated with content from the textarea.
17629          * @param {Roo.HtmlEditorCore} this
17630          * @param {String} html
17631          */
17632         push: true,
17633         
17634         /**
17635          * @event editorevent
17636          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17637          * @param {Roo.HtmlEditorCore} this
17638          */
17639         editorevent: true
17640         
17641     });
17642     
17643     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17644     
17645     // defaults : white / black...
17646     this.applyBlacklists();
17647     
17648     
17649     
17650 };
17651
17652
17653 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17654
17655
17656      /**
17657      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17658      */
17659     
17660     owner : false,
17661     
17662      /**
17663      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17664      *                        Roo.resizable.
17665      */
17666     resizable : false,
17667      /**
17668      * @cfg {Number} height (in pixels)
17669      */   
17670     height: 300,
17671    /**
17672      * @cfg {Number} width (in pixels)
17673      */   
17674     width: 500,
17675     
17676     /**
17677      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17678      * 
17679      */
17680     stylesheets: false,
17681     
17682     // id of frame..
17683     frameId: false,
17684     
17685     // private properties
17686     validationEvent : false,
17687     deferHeight: true,
17688     initialized : false,
17689     activated : false,
17690     sourceEditMode : false,
17691     onFocus : Roo.emptyFn,
17692     iframePad:3,
17693     hideMode:'offsets',
17694     
17695     clearUp: true,
17696     
17697     // blacklist + whitelisted elements..
17698     black: false,
17699     white: false,
17700      
17701     
17702
17703     /**
17704      * Protected method that will not generally be called directly. It
17705      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17706      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17707      */
17708     getDocMarkup : function(){
17709         // body styles..
17710         var st = '';
17711         
17712         // inherit styels from page...?? 
17713         if (this.stylesheets === false) {
17714             
17715             Roo.get(document.head).select('style').each(function(node) {
17716                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17717             });
17718             
17719             Roo.get(document.head).select('link').each(function(node) { 
17720                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17721             });
17722             
17723         } else if (!this.stylesheets.length) {
17724                 // simple..
17725                 st = '<style type="text/css">' +
17726                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17727                    '</style>';
17728         } else { 
17729             
17730         }
17731         
17732         st +=  '<style type="text/css">' +
17733             'IMG { cursor: pointer } ' +
17734         '</style>';
17735
17736         
17737         return '<html><head>' + st  +
17738             //<style type="text/css">' +
17739             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17740             //'</style>' +
17741             ' </head><body class="roo-htmleditor-body"></body></html>';
17742     },
17743
17744     // private
17745     onRender : function(ct, position)
17746     {
17747         var _t = this;
17748         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17749         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17750         
17751         
17752         this.el.dom.style.border = '0 none';
17753         this.el.dom.setAttribute('tabIndex', -1);
17754         this.el.addClass('x-hidden hide');
17755         
17756         
17757         
17758         if(Roo.isIE){ // fix IE 1px bogus margin
17759             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17760         }
17761        
17762         
17763         this.frameId = Roo.id();
17764         
17765          
17766         
17767         var iframe = this.owner.wrap.createChild({
17768             tag: 'iframe',
17769             cls: 'form-control', // bootstrap..
17770             id: this.frameId,
17771             name: this.frameId,
17772             frameBorder : 'no',
17773             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17774         }, this.el
17775         );
17776         
17777         
17778         this.iframe = iframe.dom;
17779
17780          this.assignDocWin();
17781         
17782         this.doc.designMode = 'on';
17783        
17784         this.doc.open();
17785         this.doc.write(this.getDocMarkup());
17786         this.doc.close();
17787
17788         
17789         var task = { // must defer to wait for browser to be ready
17790             run : function(){
17791                 //console.log("run task?" + this.doc.readyState);
17792                 this.assignDocWin();
17793                 if(this.doc.body || this.doc.readyState == 'complete'){
17794                     try {
17795                         this.doc.designMode="on";
17796                     } catch (e) {
17797                         return;
17798                     }
17799                     Roo.TaskMgr.stop(task);
17800                     this.initEditor.defer(10, this);
17801                 }
17802             },
17803             interval : 10,
17804             duration: 10000,
17805             scope: this
17806         };
17807         Roo.TaskMgr.start(task);
17808
17809     },
17810
17811     // private
17812     onResize : function(w, h)
17813     {
17814          Roo.log('resize: ' +w + ',' + h );
17815         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17816         if(!this.iframe){
17817             return;
17818         }
17819         if(typeof w == 'number'){
17820             
17821             this.iframe.style.width = w + 'px';
17822         }
17823         if(typeof h == 'number'){
17824             
17825             this.iframe.style.height = h + 'px';
17826             if(this.doc){
17827                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17828             }
17829         }
17830         
17831     },
17832
17833     /**
17834      * Toggles the editor between standard and source edit mode.
17835      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17836      */
17837     toggleSourceEdit : function(sourceEditMode){
17838         
17839         this.sourceEditMode = sourceEditMode === true;
17840         
17841         if(this.sourceEditMode){
17842  
17843             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17844             
17845         }else{
17846             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17847             //this.iframe.className = '';
17848             this.deferFocus();
17849         }
17850         //this.setSize(this.owner.wrap.getSize());
17851         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17852     },
17853
17854     
17855   
17856
17857     /**
17858      * Protected method that will not generally be called directly. If you need/want
17859      * custom HTML cleanup, this is the method you should override.
17860      * @param {String} html The HTML to be cleaned
17861      * return {String} The cleaned HTML
17862      */
17863     cleanHtml : function(html){
17864         html = String(html);
17865         if(html.length > 5){
17866             if(Roo.isSafari){ // strip safari nonsense
17867                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17868             }
17869         }
17870         if(html == '&nbsp;'){
17871             html = '';
17872         }
17873         return html;
17874     },
17875
17876     /**
17877      * HTML Editor -> Textarea
17878      * Protected method that will not generally be called directly. Syncs the contents
17879      * of the editor iframe with the textarea.
17880      */
17881     syncValue : function(){
17882         if(this.initialized){
17883             var bd = (this.doc.body || this.doc.documentElement);
17884             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17885             var html = bd.innerHTML;
17886             if(Roo.isSafari){
17887                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17888                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17889                 if(m && m[1]){
17890                     html = '<div style="'+m[0]+'">' + html + '</div>';
17891                 }
17892             }
17893             html = this.cleanHtml(html);
17894             // fix up the special chars.. normaly like back quotes in word...
17895             // however we do not want to do this with chinese..
17896             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17897                 var cc = b.charCodeAt();
17898                 if (
17899                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17900                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17901                     (cc >= 0xf900 && cc < 0xfb00 )
17902                 ) {
17903                         return b;
17904                 }
17905                 return "&#"+cc+";" 
17906             });
17907             if(this.owner.fireEvent('beforesync', this, html) !== false){
17908                 this.el.dom.value = html;
17909                 this.owner.fireEvent('sync', this, html);
17910             }
17911         }
17912     },
17913
17914     /**
17915      * Protected method that will not generally be called directly. Pushes the value of the textarea
17916      * into the iframe editor.
17917      */
17918     pushValue : function(){
17919         if(this.initialized){
17920             var v = this.el.dom.value.trim();
17921             
17922 //            if(v.length < 1){
17923 //                v = '&#160;';
17924 //            }
17925             
17926             if(this.owner.fireEvent('beforepush', this, v) !== false){
17927                 var d = (this.doc.body || this.doc.documentElement);
17928                 d.innerHTML = v;
17929                 this.cleanUpPaste();
17930                 this.el.dom.value = d.innerHTML;
17931                 this.owner.fireEvent('push', this, v);
17932             }
17933         }
17934     },
17935
17936     // private
17937     deferFocus : function(){
17938         this.focus.defer(10, this);
17939     },
17940
17941     // doc'ed in Field
17942     focus : function(){
17943         if(this.win && !this.sourceEditMode){
17944             this.win.focus();
17945         }else{
17946             this.el.focus();
17947         }
17948     },
17949     
17950     assignDocWin: function()
17951     {
17952         var iframe = this.iframe;
17953         
17954          if(Roo.isIE){
17955             this.doc = iframe.contentWindow.document;
17956             this.win = iframe.contentWindow;
17957         } else {
17958 //            if (!Roo.get(this.frameId)) {
17959 //                return;
17960 //            }
17961 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17962 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17963             
17964             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17965                 return;
17966             }
17967             
17968             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17969             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17970         }
17971     },
17972     
17973     // private
17974     initEditor : function(){
17975         //console.log("INIT EDITOR");
17976         this.assignDocWin();
17977         
17978         
17979         
17980         this.doc.designMode="on";
17981         this.doc.open();
17982         this.doc.write(this.getDocMarkup());
17983         this.doc.close();
17984         
17985         var dbody = (this.doc.body || this.doc.documentElement);
17986         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17987         // this copies styles from the containing element into thsi one..
17988         // not sure why we need all of this..
17989         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17990         
17991         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17992         //ss['background-attachment'] = 'fixed'; // w3c
17993         dbody.bgProperties = 'fixed'; // ie
17994         //Roo.DomHelper.applyStyles(dbody, ss);
17995         Roo.EventManager.on(this.doc, {
17996             //'mousedown': this.onEditorEvent,
17997             'mouseup': this.onEditorEvent,
17998             'dblclick': this.onEditorEvent,
17999             'click': this.onEditorEvent,
18000             'keyup': this.onEditorEvent,
18001             buffer:100,
18002             scope: this
18003         });
18004         if(Roo.isGecko){
18005             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18006         }
18007         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18008             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18009         }
18010         this.initialized = true;
18011
18012         this.owner.fireEvent('initialize', this);
18013         this.pushValue();
18014     },
18015
18016     // private
18017     onDestroy : function(){
18018         
18019         
18020         
18021         if(this.rendered){
18022             
18023             //for (var i =0; i < this.toolbars.length;i++) {
18024             //    // fixme - ask toolbars for heights?
18025             //    this.toolbars[i].onDestroy();
18026            // }
18027             
18028             //this.wrap.dom.innerHTML = '';
18029             //this.wrap.remove();
18030         }
18031     },
18032
18033     // private
18034     onFirstFocus : function(){
18035         
18036         this.assignDocWin();
18037         
18038         
18039         this.activated = true;
18040          
18041     
18042         if(Roo.isGecko){ // prevent silly gecko errors
18043             this.win.focus();
18044             var s = this.win.getSelection();
18045             if(!s.focusNode || s.focusNode.nodeType != 3){
18046                 var r = s.getRangeAt(0);
18047                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18048                 r.collapse(true);
18049                 this.deferFocus();
18050             }
18051             try{
18052                 this.execCmd('useCSS', true);
18053                 this.execCmd('styleWithCSS', false);
18054             }catch(e){}
18055         }
18056         this.owner.fireEvent('activate', this);
18057     },
18058
18059     // private
18060     adjustFont: function(btn){
18061         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18062         //if(Roo.isSafari){ // safari
18063         //    adjust *= 2;
18064        // }
18065         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18066         if(Roo.isSafari){ // safari
18067             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18068             v =  (v < 10) ? 10 : v;
18069             v =  (v > 48) ? 48 : v;
18070             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18071             
18072         }
18073         
18074         
18075         v = Math.max(1, v+adjust);
18076         
18077         this.execCmd('FontSize', v  );
18078     },
18079
18080     onEditorEvent : function(e){
18081         this.owner.fireEvent('editorevent', this, e);
18082       //  this.updateToolbar();
18083         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18084     },
18085
18086     insertTag : function(tg)
18087     {
18088         // could be a bit smarter... -> wrap the current selected tRoo..
18089         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18090             
18091             range = this.createRange(this.getSelection());
18092             var wrappingNode = this.doc.createElement(tg.toLowerCase());
18093             wrappingNode.appendChild(range.extractContents());
18094             range.insertNode(wrappingNode);
18095
18096             return;
18097             
18098             
18099             
18100         }
18101         this.execCmd("formatblock",   tg);
18102         
18103     },
18104     
18105     insertText : function(txt)
18106     {
18107         
18108         
18109         var range = this.createRange();
18110         range.deleteContents();
18111                //alert(Sender.getAttribute('label'));
18112                
18113         range.insertNode(this.doc.createTextNode(txt));
18114     } ,
18115     
18116      
18117
18118     /**
18119      * Executes a Midas editor command on the editor document and performs necessary focus and
18120      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18121      * @param {String} cmd The Midas command
18122      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18123      */
18124     relayCmd : function(cmd, value){
18125         this.win.focus();
18126         this.execCmd(cmd, value);
18127         this.owner.fireEvent('editorevent', this);
18128         //this.updateToolbar();
18129         this.owner.deferFocus();
18130     },
18131
18132     /**
18133      * Executes a Midas editor command directly on the editor document.
18134      * For visual commands, you should use {@link #relayCmd} instead.
18135      * <b>This should only be called after the editor is initialized.</b>
18136      * @param {String} cmd The Midas command
18137      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18138      */
18139     execCmd : function(cmd, value){
18140         this.doc.execCommand(cmd, false, value === undefined ? null : value);
18141         this.syncValue();
18142     },
18143  
18144  
18145    
18146     /**
18147      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18148      * to insert tRoo.
18149      * @param {String} text | dom node.. 
18150      */
18151     insertAtCursor : function(text)
18152     {
18153         
18154         
18155         
18156         if(!this.activated){
18157             return;
18158         }
18159         /*
18160         if(Roo.isIE){
18161             this.win.focus();
18162             var r = this.doc.selection.createRange();
18163             if(r){
18164                 r.collapse(true);
18165                 r.pasteHTML(text);
18166                 this.syncValue();
18167                 this.deferFocus();
18168             
18169             }
18170             return;
18171         }
18172         */
18173         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18174             this.win.focus();
18175             
18176             
18177             // from jquery ui (MIT licenced)
18178             var range, node;
18179             var win = this.win;
18180             
18181             if (win.getSelection && win.getSelection().getRangeAt) {
18182                 range = win.getSelection().getRangeAt(0);
18183                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18184                 range.insertNode(node);
18185             } else if (win.document.selection && win.document.selection.createRange) {
18186                 // no firefox support
18187                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18188                 win.document.selection.createRange().pasteHTML(txt);
18189             } else {
18190                 // no firefox support
18191                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18192                 this.execCmd('InsertHTML', txt);
18193             } 
18194             
18195             this.syncValue();
18196             
18197             this.deferFocus();
18198         }
18199     },
18200  // private
18201     mozKeyPress : function(e){
18202         if(e.ctrlKey){
18203             var c = e.getCharCode(), cmd;
18204           
18205             if(c > 0){
18206                 c = String.fromCharCode(c).toLowerCase();
18207                 switch(c){
18208                     case 'b':
18209                         cmd = 'bold';
18210                         break;
18211                     case 'i':
18212                         cmd = 'italic';
18213                         break;
18214                     
18215                     case 'u':
18216                         cmd = 'underline';
18217                         break;
18218                     
18219                     case 'v':
18220                         this.cleanUpPaste.defer(100, this);
18221                         return;
18222                         
18223                 }
18224                 if(cmd){
18225                     this.win.focus();
18226                     this.execCmd(cmd);
18227                     this.deferFocus();
18228                     e.preventDefault();
18229                 }
18230                 
18231             }
18232         }
18233     },
18234
18235     // private
18236     fixKeys : function(){ // load time branching for fastest keydown performance
18237         if(Roo.isIE){
18238             return function(e){
18239                 var k = e.getKey(), r;
18240                 if(k == e.TAB){
18241                     e.stopEvent();
18242                     r = this.doc.selection.createRange();
18243                     if(r){
18244                         r.collapse(true);
18245                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18246                         this.deferFocus();
18247                     }
18248                     return;
18249                 }
18250                 
18251                 if(k == e.ENTER){
18252                     r = this.doc.selection.createRange();
18253                     if(r){
18254                         var target = r.parentElement();
18255                         if(!target || target.tagName.toLowerCase() != 'li'){
18256                             e.stopEvent();
18257                             r.pasteHTML('<br />');
18258                             r.collapse(false);
18259                             r.select();
18260                         }
18261                     }
18262                 }
18263                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18264                     this.cleanUpPaste.defer(100, this);
18265                     return;
18266                 }
18267                 
18268                 
18269             };
18270         }else if(Roo.isOpera){
18271             return function(e){
18272                 var k = e.getKey();
18273                 if(k == e.TAB){
18274                     e.stopEvent();
18275                     this.win.focus();
18276                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18277                     this.deferFocus();
18278                 }
18279                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18280                     this.cleanUpPaste.defer(100, this);
18281                     return;
18282                 }
18283                 
18284             };
18285         }else if(Roo.isSafari){
18286             return function(e){
18287                 var k = e.getKey();
18288                 
18289                 if(k == e.TAB){
18290                     e.stopEvent();
18291                     this.execCmd('InsertText','\t');
18292                     this.deferFocus();
18293                     return;
18294                 }
18295                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18296                     this.cleanUpPaste.defer(100, this);
18297                     return;
18298                 }
18299                 
18300              };
18301         }
18302     }(),
18303     
18304     getAllAncestors: function()
18305     {
18306         var p = this.getSelectedNode();
18307         var a = [];
18308         if (!p) {
18309             a.push(p); // push blank onto stack..
18310             p = this.getParentElement();
18311         }
18312         
18313         
18314         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18315             a.push(p);
18316             p = p.parentNode;
18317         }
18318         a.push(this.doc.body);
18319         return a;
18320     },
18321     lastSel : false,
18322     lastSelNode : false,
18323     
18324     
18325     getSelection : function() 
18326     {
18327         this.assignDocWin();
18328         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18329     },
18330     
18331     getSelectedNode: function() 
18332     {
18333         // this may only work on Gecko!!!
18334         
18335         // should we cache this!!!!
18336         
18337         
18338         
18339          
18340         var range = this.createRange(this.getSelection()).cloneRange();
18341         
18342         if (Roo.isIE) {
18343             var parent = range.parentElement();
18344             while (true) {
18345                 var testRange = range.duplicate();
18346                 testRange.moveToElementText(parent);
18347                 if (testRange.inRange(range)) {
18348                     break;
18349                 }
18350                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18351                     break;
18352                 }
18353                 parent = parent.parentElement;
18354             }
18355             return parent;
18356         }
18357         
18358         // is ancestor a text element.
18359         var ac =  range.commonAncestorContainer;
18360         if (ac.nodeType == 3) {
18361             ac = ac.parentNode;
18362         }
18363         
18364         var ar = ac.childNodes;
18365          
18366         var nodes = [];
18367         var other_nodes = [];
18368         var has_other_nodes = false;
18369         for (var i=0;i<ar.length;i++) {
18370             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18371                 continue;
18372             }
18373             // fullly contained node.
18374             
18375             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18376                 nodes.push(ar[i]);
18377                 continue;
18378             }
18379             
18380             // probably selected..
18381             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18382                 other_nodes.push(ar[i]);
18383                 continue;
18384             }
18385             // outer..
18386             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18387                 continue;
18388             }
18389             
18390             
18391             has_other_nodes = true;
18392         }
18393         if (!nodes.length && other_nodes.length) {
18394             nodes= other_nodes;
18395         }
18396         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18397             return false;
18398         }
18399         
18400         return nodes[0];
18401     },
18402     createRange: function(sel)
18403     {
18404         // this has strange effects when using with 
18405         // top toolbar - not sure if it's a great idea.
18406         //this.editor.contentWindow.focus();
18407         if (typeof sel != "undefined") {
18408             try {
18409                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18410             } catch(e) {
18411                 return this.doc.createRange();
18412             }
18413         } else {
18414             return this.doc.createRange();
18415         }
18416     },
18417     getParentElement: function()
18418     {
18419         
18420         this.assignDocWin();
18421         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18422         
18423         var range = this.createRange(sel);
18424          
18425         try {
18426             var p = range.commonAncestorContainer;
18427             while (p.nodeType == 3) { // text node
18428                 p = p.parentNode;
18429             }
18430             return p;
18431         } catch (e) {
18432             return null;
18433         }
18434     
18435     },
18436     /***
18437      *
18438      * Range intersection.. the hard stuff...
18439      *  '-1' = before
18440      *  '0' = hits..
18441      *  '1' = after.
18442      *         [ -- selected range --- ]
18443      *   [fail]                        [fail]
18444      *
18445      *    basically..
18446      *      if end is before start or  hits it. fail.
18447      *      if start is after end or hits it fail.
18448      *
18449      *   if either hits (but other is outside. - then it's not 
18450      *   
18451      *    
18452      **/
18453     
18454     
18455     // @see http://www.thismuchiknow.co.uk/?p=64.
18456     rangeIntersectsNode : function(range, node)
18457     {
18458         var nodeRange = node.ownerDocument.createRange();
18459         try {
18460             nodeRange.selectNode(node);
18461         } catch (e) {
18462             nodeRange.selectNodeContents(node);
18463         }
18464     
18465         var rangeStartRange = range.cloneRange();
18466         rangeStartRange.collapse(true);
18467     
18468         var rangeEndRange = range.cloneRange();
18469         rangeEndRange.collapse(false);
18470     
18471         var nodeStartRange = nodeRange.cloneRange();
18472         nodeStartRange.collapse(true);
18473     
18474         var nodeEndRange = nodeRange.cloneRange();
18475         nodeEndRange.collapse(false);
18476     
18477         return rangeStartRange.compareBoundaryPoints(
18478                  Range.START_TO_START, nodeEndRange) == -1 &&
18479                rangeEndRange.compareBoundaryPoints(
18480                  Range.START_TO_START, nodeStartRange) == 1;
18481         
18482          
18483     },
18484     rangeCompareNode : function(range, node)
18485     {
18486         var nodeRange = node.ownerDocument.createRange();
18487         try {
18488             nodeRange.selectNode(node);
18489         } catch (e) {
18490             nodeRange.selectNodeContents(node);
18491         }
18492         
18493         
18494         range.collapse(true);
18495     
18496         nodeRange.collapse(true);
18497      
18498         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18499         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18500          
18501         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18502         
18503         var nodeIsBefore   =  ss == 1;
18504         var nodeIsAfter    = ee == -1;
18505         
18506         if (nodeIsBefore && nodeIsAfter)
18507             return 0; // outer
18508         if (!nodeIsBefore && nodeIsAfter)
18509             return 1; //right trailed.
18510         
18511         if (nodeIsBefore && !nodeIsAfter)
18512             return 2;  // left trailed.
18513         // fully contined.
18514         return 3;
18515     },
18516
18517     // private? - in a new class?
18518     cleanUpPaste :  function()
18519     {
18520         // cleans up the whole document..
18521         Roo.log('cleanuppaste');
18522         
18523         this.cleanUpChildren(this.doc.body);
18524         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18525         if (clean != this.doc.body.innerHTML) {
18526             this.doc.body.innerHTML = clean;
18527         }
18528         
18529     },
18530     
18531     cleanWordChars : function(input) {// change the chars to hex code
18532         var he = Roo.HtmlEditorCore;
18533         
18534         var output = input;
18535         Roo.each(he.swapCodes, function(sw) { 
18536             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18537             
18538             output = output.replace(swapper, sw[1]);
18539         });
18540         
18541         return output;
18542     },
18543     
18544     
18545     cleanUpChildren : function (n)
18546     {
18547         if (!n.childNodes.length) {
18548             return;
18549         }
18550         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18551            this.cleanUpChild(n.childNodes[i]);
18552         }
18553     },
18554     
18555     
18556         
18557     
18558     cleanUpChild : function (node)
18559     {
18560         var ed = this;
18561         //console.log(node);
18562         if (node.nodeName == "#text") {
18563             // clean up silly Windows -- stuff?
18564             return; 
18565         }
18566         if (node.nodeName == "#comment") {
18567             node.parentNode.removeChild(node);
18568             // clean up silly Windows -- stuff?
18569             return; 
18570         }
18571         var lcname = node.tagName.toLowerCase();
18572         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18573         // whitelist of tags..
18574         
18575         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18576             // remove node.
18577             node.parentNode.removeChild(node);
18578             return;
18579             
18580         }
18581         
18582         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18583         
18584         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18585         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18586         
18587         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18588         //    remove_keep_children = true;
18589         //}
18590         
18591         if (remove_keep_children) {
18592             this.cleanUpChildren(node);
18593             // inserts everything just before this node...
18594             while (node.childNodes.length) {
18595                 var cn = node.childNodes[0];
18596                 node.removeChild(cn);
18597                 node.parentNode.insertBefore(cn, node);
18598             }
18599             node.parentNode.removeChild(node);
18600             return;
18601         }
18602         
18603         if (!node.attributes || !node.attributes.length) {
18604             this.cleanUpChildren(node);
18605             return;
18606         }
18607         
18608         function cleanAttr(n,v)
18609         {
18610             
18611             if (v.match(/^\./) || v.match(/^\//)) {
18612                 return;
18613             }
18614             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18615                 return;
18616             }
18617             if (v.match(/^#/)) {
18618                 return;
18619             }
18620 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18621             node.removeAttribute(n);
18622             
18623         }
18624         
18625         var cwhite = this.cwhite;
18626         var cblack = this.cblack;
18627             
18628         function cleanStyle(n,v)
18629         {
18630             if (v.match(/expression/)) { //XSS?? should we even bother..
18631                 node.removeAttribute(n);
18632                 return;
18633             }
18634             
18635             var parts = v.split(/;/);
18636             var clean = [];
18637             
18638             Roo.each(parts, function(p) {
18639                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18640                 if (!p.length) {
18641                     return true;
18642                 }
18643                 var l = p.split(':').shift().replace(/\s+/g,'');
18644                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18645                 
18646                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18647 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18648                     //node.removeAttribute(n);
18649                     return true;
18650                 }
18651                 //Roo.log()
18652                 // only allow 'c whitelisted system attributes'
18653                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18654 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18655                     //node.removeAttribute(n);
18656                     return true;
18657                 }
18658                 
18659                 
18660                  
18661                 
18662                 clean.push(p);
18663                 return true;
18664             });
18665             if (clean.length) { 
18666                 node.setAttribute(n, clean.join(';'));
18667             } else {
18668                 node.removeAttribute(n);
18669             }
18670             
18671         }
18672         
18673         
18674         for (var i = node.attributes.length-1; i > -1 ; i--) {
18675             var a = node.attributes[i];
18676             //console.log(a);
18677             
18678             if (a.name.toLowerCase().substr(0,2)=='on')  {
18679                 node.removeAttribute(a.name);
18680                 continue;
18681             }
18682             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18683                 node.removeAttribute(a.name);
18684                 continue;
18685             }
18686             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18687                 cleanAttr(a.name,a.value); // fixme..
18688                 continue;
18689             }
18690             if (a.name == 'style') {
18691                 cleanStyle(a.name,a.value);
18692                 continue;
18693             }
18694             /// clean up MS crap..
18695             // tecnically this should be a list of valid class'es..
18696             
18697             
18698             if (a.name == 'class') {
18699                 if (a.value.match(/^Mso/)) {
18700                     node.className = '';
18701                 }
18702                 
18703                 if (a.value.match(/body/)) {
18704                     node.className = '';
18705                 }
18706                 continue;
18707             }
18708             
18709             // style cleanup!?
18710             // class cleanup?
18711             
18712         }
18713         
18714         
18715         this.cleanUpChildren(node);
18716         
18717         
18718     },
18719     /**
18720      * Clean up MS wordisms...
18721      */
18722     cleanWord : function(node)
18723     {
18724         var _t = this;
18725         var cleanWordChildren = function()
18726         {
18727             if (!node.childNodes.length) {
18728                 return;
18729             }
18730             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18731                _t.cleanWord(node.childNodes[i]);
18732             }
18733         }
18734         
18735         
18736         if (!node) {
18737             this.cleanWord(this.doc.body);
18738             return;
18739         }
18740         if (node.nodeName == "#text") {
18741             // clean up silly Windows -- stuff?
18742             return; 
18743         }
18744         if (node.nodeName == "#comment") {
18745             node.parentNode.removeChild(node);
18746             // clean up silly Windows -- stuff?
18747             return; 
18748         }
18749         
18750         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18751             node.parentNode.removeChild(node);
18752             return;
18753         }
18754         
18755         // remove - but keep children..
18756         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18757             while (node.childNodes.length) {
18758                 var cn = node.childNodes[0];
18759                 node.removeChild(cn);
18760                 node.parentNode.insertBefore(cn, node);
18761             }
18762             node.parentNode.removeChild(node);
18763             cleanWordChildren();
18764             return;
18765         }
18766         // clean styles
18767         if (node.className.length) {
18768             
18769             var cn = node.className.split(/\W+/);
18770             var cna = [];
18771             Roo.each(cn, function(cls) {
18772                 if (cls.match(/Mso[a-zA-Z]+/)) {
18773                     return;
18774                 }
18775                 cna.push(cls);
18776             });
18777             node.className = cna.length ? cna.join(' ') : '';
18778             if (!cna.length) {
18779                 node.removeAttribute("class");
18780             }
18781         }
18782         
18783         if (node.hasAttribute("lang")) {
18784             node.removeAttribute("lang");
18785         }
18786         
18787         if (node.hasAttribute("style")) {
18788             
18789             var styles = node.getAttribute("style").split(";");
18790             var nstyle = [];
18791             Roo.each(styles, function(s) {
18792                 if (!s.match(/:/)) {
18793                     return;
18794                 }
18795                 var kv = s.split(":");
18796                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18797                     return;
18798                 }
18799                 // what ever is left... we allow.
18800                 nstyle.push(s);
18801             });
18802             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18803             if (!nstyle.length) {
18804                 node.removeAttribute('style');
18805             }
18806         }
18807         
18808         cleanWordChildren();
18809         
18810         
18811     },
18812     domToHTML : function(currentElement, depth, nopadtext) {
18813         
18814         depth = depth || 0;
18815         nopadtext = nopadtext || false;
18816     
18817         if (!currentElement) {
18818             return this.domToHTML(this.doc.body);
18819         }
18820         
18821         //Roo.log(currentElement);
18822         var j;
18823         var allText = false;
18824         var nodeName = currentElement.nodeName;
18825         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18826         
18827         if  (nodeName == '#text') {
18828             
18829             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18830         }
18831         
18832         
18833         var ret = '';
18834         if (nodeName != 'BODY') {
18835              
18836             var i = 0;
18837             // Prints the node tagName, such as <A>, <IMG>, etc
18838             if (tagName) {
18839                 var attr = [];
18840                 for(i = 0; i < currentElement.attributes.length;i++) {
18841                     // quoting?
18842                     var aname = currentElement.attributes.item(i).name;
18843                     if (!currentElement.attributes.item(i).value.length) {
18844                         continue;
18845                     }
18846                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18847                 }
18848                 
18849                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18850             } 
18851             else {
18852                 
18853                 // eack
18854             }
18855         } else {
18856             tagName = false;
18857         }
18858         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18859             return ret;
18860         }
18861         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18862             nopadtext = true;
18863         }
18864         
18865         
18866         // Traverse the tree
18867         i = 0;
18868         var currentElementChild = currentElement.childNodes.item(i);
18869         var allText = true;
18870         var innerHTML  = '';
18871         lastnode = '';
18872         while (currentElementChild) {
18873             // Formatting code (indent the tree so it looks nice on the screen)
18874             var nopad = nopadtext;
18875             if (lastnode == 'SPAN') {
18876                 nopad  = true;
18877             }
18878             // text
18879             if  (currentElementChild.nodeName == '#text') {
18880                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18881                 toadd = nopadtext ? toadd : toadd.trim();
18882                 if (!nopad && toadd.length > 80) {
18883                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18884                 }
18885                 innerHTML  += toadd;
18886                 
18887                 i++;
18888                 currentElementChild = currentElement.childNodes.item(i);
18889                 lastNode = '';
18890                 continue;
18891             }
18892             allText = false;
18893             
18894             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18895                 
18896             // Recursively traverse the tree structure of the child node
18897             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18898             lastnode = currentElementChild.nodeName;
18899             i++;
18900             currentElementChild=currentElement.childNodes.item(i);
18901         }
18902         
18903         ret += innerHTML;
18904         
18905         if (!allText) {
18906                 // The remaining code is mostly for formatting the tree
18907             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18908         }
18909         
18910         
18911         if (tagName) {
18912             ret+= "</"+tagName+">";
18913         }
18914         return ret;
18915         
18916     },
18917         
18918     applyBlacklists : function()
18919     {
18920         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18921         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18922         
18923         this.white = [];
18924         this.black = [];
18925         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18926             if (b.indexOf(tag) > -1) {
18927                 return;
18928             }
18929             this.white.push(tag);
18930             
18931         }, this);
18932         
18933         Roo.each(w, function(tag) {
18934             if (b.indexOf(tag) > -1) {
18935                 return;
18936             }
18937             if (this.white.indexOf(tag) > -1) {
18938                 return;
18939             }
18940             this.white.push(tag);
18941             
18942         }, this);
18943         
18944         
18945         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18946             if (w.indexOf(tag) > -1) {
18947                 return;
18948             }
18949             this.black.push(tag);
18950             
18951         }, this);
18952         
18953         Roo.each(b, function(tag) {
18954             if (w.indexOf(tag) > -1) {
18955                 return;
18956             }
18957             if (this.black.indexOf(tag) > -1) {
18958                 return;
18959             }
18960             this.black.push(tag);
18961             
18962         }, this);
18963         
18964         
18965         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18966         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18967         
18968         this.cwhite = [];
18969         this.cblack = [];
18970         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18971             if (b.indexOf(tag) > -1) {
18972                 return;
18973             }
18974             this.cwhite.push(tag);
18975             
18976         }, this);
18977         
18978         Roo.each(w, function(tag) {
18979             if (b.indexOf(tag) > -1) {
18980                 return;
18981             }
18982             if (this.cwhite.indexOf(tag) > -1) {
18983                 return;
18984             }
18985             this.cwhite.push(tag);
18986             
18987         }, this);
18988         
18989         
18990         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18991             if (w.indexOf(tag) > -1) {
18992                 return;
18993             }
18994             this.cblack.push(tag);
18995             
18996         }, this);
18997         
18998         Roo.each(b, function(tag) {
18999             if (w.indexOf(tag) > -1) {
19000                 return;
19001             }
19002             if (this.cblack.indexOf(tag) > -1) {
19003                 return;
19004             }
19005             this.cblack.push(tag);
19006             
19007         }, this);
19008     },
19009     
19010     setStylesheets : function(stylesheets)
19011     {
19012         if(typeof(stylesheets) == 'string'){
19013             Roo.get(this.iframe.contentDocument.head).createChild({
19014                 tag : 'link',
19015                 rel : 'stylesheet',
19016                 type : 'text/css',
19017                 href : stylesheets
19018             });
19019             
19020             return;
19021         }
19022         var _this = this;
19023      
19024         Roo.each(stylesheets, function(s) {
19025             if(!s.length){
19026                 return;
19027             }
19028             
19029             Roo.get(_this.iframe.contentDocument.head).createChild({
19030                 tag : 'link',
19031                 rel : 'stylesheet',
19032                 type : 'text/css',
19033                 href : s
19034             });
19035         });
19036
19037         
19038     },
19039     
19040     removeStylesheets : function()
19041     {
19042         var _this = this;
19043         
19044         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19045             s.remove();
19046         });
19047     }
19048     
19049     // hide stuff that is not compatible
19050     /**
19051      * @event blur
19052      * @hide
19053      */
19054     /**
19055      * @event change
19056      * @hide
19057      */
19058     /**
19059      * @event focus
19060      * @hide
19061      */
19062     /**
19063      * @event specialkey
19064      * @hide
19065      */
19066     /**
19067      * @cfg {String} fieldClass @hide
19068      */
19069     /**
19070      * @cfg {String} focusClass @hide
19071      */
19072     /**
19073      * @cfg {String} autoCreate @hide
19074      */
19075     /**
19076      * @cfg {String} inputType @hide
19077      */
19078     /**
19079      * @cfg {String} invalidClass @hide
19080      */
19081     /**
19082      * @cfg {String} invalidText @hide
19083      */
19084     /**
19085      * @cfg {String} msgFx @hide
19086      */
19087     /**
19088      * @cfg {String} validateOnBlur @hide
19089      */
19090 });
19091
19092 Roo.HtmlEditorCore.white = [
19093         'area', 'br', 'img', 'input', 'hr', 'wbr',
19094         
19095        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
19096        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
19097        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
19098        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
19099        'table',   'ul',         'xmp', 
19100        
19101        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
19102       'thead',   'tr', 
19103      
19104       'dir', 'menu', 'ol', 'ul', 'dl',
19105        
19106       'embed',  'object'
19107 ];
19108
19109
19110 Roo.HtmlEditorCore.black = [
19111     //    'embed',  'object', // enable - backend responsiblity to clean thiese
19112         'applet', // 
19113         'base',   'basefont', 'bgsound', 'blink',  'body', 
19114         'frame',  'frameset', 'head',    'html',   'ilayer', 
19115         'iframe', 'layer',  'link',     'meta',    'object',   
19116         'script', 'style' ,'title',  'xml' // clean later..
19117 ];
19118 Roo.HtmlEditorCore.clean = [
19119     'script', 'style', 'title', 'xml'
19120 ];
19121 Roo.HtmlEditorCore.remove = [
19122     'font'
19123 ];
19124 // attributes..
19125
19126 Roo.HtmlEditorCore.ablack = [
19127     'on'
19128 ];
19129     
19130 Roo.HtmlEditorCore.aclean = [ 
19131     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
19132 ];
19133
19134 // protocols..
19135 Roo.HtmlEditorCore.pwhite= [
19136         'http',  'https',  'mailto'
19137 ];
19138
19139 // white listed style attributes.
19140 Roo.HtmlEditorCore.cwhite= [
19141       //  'text-align', /// default is to allow most things..
19142       
19143          
19144 //        'font-size'//??
19145 ];
19146
19147 // black listed style attributes.
19148 Roo.HtmlEditorCore.cblack= [
19149       //  'font-size' -- this can be set by the project 
19150 ];
19151
19152
19153 Roo.HtmlEditorCore.swapCodes   =[ 
19154     [    8211, "--" ], 
19155     [    8212, "--" ], 
19156     [    8216,  "'" ],  
19157     [    8217, "'" ],  
19158     [    8220, '"' ],  
19159     [    8221, '"' ],  
19160     [    8226, "*" ],  
19161     [    8230, "..." ]
19162 ]; 
19163
19164     /*
19165  * - LGPL
19166  *
19167  * HtmlEditor
19168  * 
19169  */
19170
19171 /**
19172  * @class Roo.bootstrap.HtmlEditor
19173  * @extends Roo.bootstrap.TextArea
19174  * Bootstrap HtmlEditor class
19175
19176  * @constructor
19177  * Create a new HtmlEditor
19178  * @param {Object} config The config object
19179  */
19180
19181 Roo.bootstrap.HtmlEditor = function(config){
19182     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19183     if (!this.toolbars) {
19184         this.toolbars = [];
19185     }
19186     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19187     this.addEvents({
19188             /**
19189              * @event initialize
19190              * Fires when the editor is fully initialized (including the iframe)
19191              * @param {HtmlEditor} this
19192              */
19193             initialize: true,
19194             /**
19195              * @event activate
19196              * Fires when the editor is first receives the focus. Any insertion must wait
19197              * until after this event.
19198              * @param {HtmlEditor} this
19199              */
19200             activate: true,
19201              /**
19202              * @event beforesync
19203              * Fires before the textarea is updated with content from the editor iframe. Return false
19204              * to cancel the sync.
19205              * @param {HtmlEditor} this
19206              * @param {String} html
19207              */
19208             beforesync: true,
19209              /**
19210              * @event beforepush
19211              * Fires before the iframe editor is updated with content from the textarea. Return false
19212              * to cancel the push.
19213              * @param {HtmlEditor} this
19214              * @param {String} html
19215              */
19216             beforepush: true,
19217              /**
19218              * @event sync
19219              * Fires when the textarea is updated with content from the editor iframe.
19220              * @param {HtmlEditor} this
19221              * @param {String} html
19222              */
19223             sync: true,
19224              /**
19225              * @event push
19226              * Fires when the iframe editor is updated with content from the textarea.
19227              * @param {HtmlEditor} this
19228              * @param {String} html
19229              */
19230             push: true,
19231              /**
19232              * @event editmodechange
19233              * Fires when the editor switches edit modes
19234              * @param {HtmlEditor} this
19235              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19236              */
19237             editmodechange: true,
19238             /**
19239              * @event editorevent
19240              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19241              * @param {HtmlEditor} this
19242              */
19243             editorevent: true,
19244             /**
19245              * @event firstfocus
19246              * Fires when on first focus - needed by toolbars..
19247              * @param {HtmlEditor} this
19248              */
19249             firstfocus: true,
19250             /**
19251              * @event autosave
19252              * Auto save the htmlEditor value as a file into Events
19253              * @param {HtmlEditor} this
19254              */
19255             autosave: true,
19256             /**
19257              * @event savedpreview
19258              * preview the saved version of htmlEditor
19259              * @param {HtmlEditor} this
19260              */
19261             savedpreview: true
19262         });
19263 };
19264
19265
19266 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19267     
19268     
19269       /**
19270      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19271      */
19272     toolbars : false,
19273    
19274      /**
19275      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19276      *                        Roo.resizable.
19277      */
19278     resizable : false,
19279      /**
19280      * @cfg {Number} height (in pixels)
19281      */   
19282     height: 300,
19283    /**
19284      * @cfg {Number} width (in pixels)
19285      */   
19286     width: false,
19287     
19288     /**
19289      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19290      * 
19291      */
19292     stylesheets: false,
19293     
19294     // id of frame..
19295     frameId: false,
19296     
19297     // private properties
19298     validationEvent : false,
19299     deferHeight: true,
19300     initialized : false,
19301     activated : false,
19302     
19303     onFocus : Roo.emptyFn,
19304     iframePad:3,
19305     hideMode:'offsets',
19306     
19307     
19308     tbContainer : false,
19309     
19310     toolbarContainer :function() {
19311         return this.wrap.select('.x-html-editor-tb',true).first();
19312     },
19313
19314     /**
19315      * Protected method that will not generally be called directly. It
19316      * is called when the editor creates its toolbar. Override this method if you need to
19317      * add custom toolbar buttons.
19318      * @param {HtmlEditor} editor
19319      */
19320     createToolbar : function(){
19321         
19322         Roo.log("create toolbars");
19323         
19324         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19325         this.toolbars[0].render(this.toolbarContainer());
19326         
19327         return;
19328         
19329 //        if (!editor.toolbars || !editor.toolbars.length) {
19330 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19331 //        }
19332 //        
19333 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19334 //            editor.toolbars[i] = Roo.factory(
19335 //                    typeof(editor.toolbars[i]) == 'string' ?
19336 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19337 //                Roo.bootstrap.HtmlEditor);
19338 //            editor.toolbars[i].init(editor);
19339 //        }
19340     },
19341
19342      
19343     // private
19344     onRender : function(ct, position)
19345     {
19346        // Roo.log("Call onRender: " + this.xtype);
19347         var _t = this;
19348         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19349       
19350         this.wrap = this.inputEl().wrap({
19351             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19352         });
19353         
19354         this.editorcore.onRender(ct, position);
19355          
19356         if (this.resizable) {
19357             this.resizeEl = new Roo.Resizable(this.wrap, {
19358                 pinned : true,
19359                 wrap: true,
19360                 dynamic : true,
19361                 minHeight : this.height,
19362                 height: this.height,
19363                 handles : this.resizable,
19364                 width: this.width,
19365                 listeners : {
19366                     resize : function(r, w, h) {
19367                         _t.onResize(w,h); // -something
19368                     }
19369                 }
19370             });
19371             
19372         }
19373         this.createToolbar(this);
19374        
19375         
19376         if(!this.width && this.resizable){
19377             this.setSize(this.wrap.getSize());
19378         }
19379         if (this.resizeEl) {
19380             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19381             // should trigger onReize..
19382         }
19383         
19384     },
19385
19386     // private
19387     onResize : function(w, h)
19388     {
19389         Roo.log('resize: ' +w + ',' + h );
19390         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19391         var ew = false;
19392         var eh = false;
19393         
19394         if(this.inputEl() ){
19395             if(typeof w == 'number'){
19396                 var aw = w - this.wrap.getFrameWidth('lr');
19397                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19398                 ew = aw;
19399             }
19400             if(typeof h == 'number'){
19401                  var tbh = -11;  // fixme it needs to tool bar size!
19402                 for (var i =0; i < this.toolbars.length;i++) {
19403                     // fixme - ask toolbars for heights?
19404                     tbh += this.toolbars[i].el.getHeight();
19405                     //if (this.toolbars[i].footer) {
19406                     //    tbh += this.toolbars[i].footer.el.getHeight();
19407                     //}
19408                 }
19409               
19410                 
19411                 
19412                 
19413                 
19414                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19415                 ah -= 5; // knock a few pixes off for look..
19416                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19417                 var eh = ah;
19418             }
19419         }
19420         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19421         this.editorcore.onResize(ew,eh);
19422         
19423     },
19424
19425     /**
19426      * Toggles the editor between standard and source edit mode.
19427      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19428      */
19429     toggleSourceEdit : function(sourceEditMode)
19430     {
19431         this.editorcore.toggleSourceEdit(sourceEditMode);
19432         
19433         if(this.editorcore.sourceEditMode){
19434             Roo.log('editor - showing textarea');
19435             
19436 //            Roo.log('in');
19437 //            Roo.log(this.syncValue());
19438             this.syncValue();
19439             this.inputEl().removeClass(['hide', 'x-hidden']);
19440             this.inputEl().dom.removeAttribute('tabIndex');
19441             this.inputEl().focus();
19442         }else{
19443             Roo.log('editor - hiding textarea');
19444 //            Roo.log('out')
19445 //            Roo.log(this.pushValue()); 
19446             this.pushValue();
19447             
19448             this.inputEl().addClass(['hide', 'x-hidden']);
19449             this.inputEl().dom.setAttribute('tabIndex', -1);
19450             //this.deferFocus();
19451         }
19452          
19453         if(this.resizable){
19454             this.setSize(this.wrap.getSize());
19455         }
19456         
19457         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19458     },
19459  
19460     // private (for BoxComponent)
19461     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19462
19463     // private (for BoxComponent)
19464     getResizeEl : function(){
19465         return this.wrap;
19466     },
19467
19468     // private (for BoxComponent)
19469     getPositionEl : function(){
19470         return this.wrap;
19471     },
19472
19473     // private
19474     initEvents : function(){
19475         this.originalValue = this.getValue();
19476     },
19477
19478 //    /**
19479 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19480 //     * @method
19481 //     */
19482 //    markInvalid : Roo.emptyFn,
19483 //    /**
19484 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19485 //     * @method
19486 //     */
19487 //    clearInvalid : Roo.emptyFn,
19488
19489     setValue : function(v){
19490         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19491         this.editorcore.pushValue();
19492     },
19493
19494      
19495     // private
19496     deferFocus : function(){
19497         this.focus.defer(10, this);
19498     },
19499
19500     // doc'ed in Field
19501     focus : function(){
19502         this.editorcore.focus();
19503         
19504     },
19505       
19506
19507     // private
19508     onDestroy : function(){
19509         
19510         
19511         
19512         if(this.rendered){
19513             
19514             for (var i =0; i < this.toolbars.length;i++) {
19515                 // fixme - ask toolbars for heights?
19516                 this.toolbars[i].onDestroy();
19517             }
19518             
19519             this.wrap.dom.innerHTML = '';
19520             this.wrap.remove();
19521         }
19522     },
19523
19524     // private
19525     onFirstFocus : function(){
19526         //Roo.log("onFirstFocus");
19527         this.editorcore.onFirstFocus();
19528          for (var i =0; i < this.toolbars.length;i++) {
19529             this.toolbars[i].onFirstFocus();
19530         }
19531         
19532     },
19533     
19534     // private
19535     syncValue : function()
19536     {   
19537         this.editorcore.syncValue();
19538     },
19539     
19540     pushValue : function()
19541     {   
19542         this.editorcore.pushValue();
19543     }
19544      
19545     
19546     // hide stuff that is not compatible
19547     /**
19548      * @event blur
19549      * @hide
19550      */
19551     /**
19552      * @event change
19553      * @hide
19554      */
19555     /**
19556      * @event focus
19557      * @hide
19558      */
19559     /**
19560      * @event specialkey
19561      * @hide
19562      */
19563     /**
19564      * @cfg {String} fieldClass @hide
19565      */
19566     /**
19567      * @cfg {String} focusClass @hide
19568      */
19569     /**
19570      * @cfg {String} autoCreate @hide
19571      */
19572     /**
19573      * @cfg {String} inputType @hide
19574      */
19575     /**
19576      * @cfg {String} invalidClass @hide
19577      */
19578     /**
19579      * @cfg {String} invalidText @hide
19580      */
19581     /**
19582      * @cfg {String} msgFx @hide
19583      */
19584     /**
19585      * @cfg {String} validateOnBlur @hide
19586      */
19587 });
19588  
19589     
19590    
19591    
19592    
19593       
19594 Roo.namespace('Roo.bootstrap.htmleditor');
19595 /**
19596  * @class Roo.bootstrap.HtmlEditorToolbar1
19597  * Basic Toolbar
19598  * 
19599  * Usage:
19600  *
19601  new Roo.bootstrap.HtmlEditor({
19602     ....
19603     toolbars : [
19604         new Roo.bootstrap.HtmlEditorToolbar1({
19605             disable : { fonts: 1 , format: 1, ..., ... , ...],
19606             btns : [ .... ]
19607         })
19608     }
19609      
19610  * 
19611  * @cfg {Object} disable List of elements to disable..
19612  * @cfg {Array} btns List of additional buttons.
19613  * 
19614  * 
19615  * NEEDS Extra CSS? 
19616  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19617  */
19618  
19619 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19620 {
19621     
19622     Roo.apply(this, config);
19623     
19624     // default disabled, based on 'good practice'..
19625     this.disable = this.disable || {};
19626     Roo.applyIf(this.disable, {
19627         fontSize : true,
19628         colors : true,
19629         specialElements : true
19630     });
19631     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19632     
19633     this.editor = config.editor;
19634     this.editorcore = config.editor.editorcore;
19635     
19636     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19637     
19638     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19639     // dont call parent... till later.
19640 }
19641 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19642      
19643     bar : true,
19644     
19645     editor : false,
19646     editorcore : false,
19647     
19648     
19649     formats : [
19650         "p" ,  
19651         "h1","h2","h3","h4","h5","h6", 
19652         "pre", "code", 
19653         "abbr", "acronym", "address", "cite", "samp", "var",
19654         'div','span'
19655     ],
19656     
19657     onRender : function(ct, position)
19658     {
19659        // Roo.log("Call onRender: " + this.xtype);
19660         
19661        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19662        Roo.log(this.el);
19663        this.el.dom.style.marginBottom = '0';
19664        var _this = this;
19665        var editorcore = this.editorcore;
19666        var editor= this.editor;
19667        
19668        var children = [];
19669        var btn = function(id,cmd , toggle, handler){
19670        
19671             var  event = toggle ? 'toggle' : 'click';
19672        
19673             var a = {
19674                 size : 'sm',
19675                 xtype: 'Button',
19676                 xns: Roo.bootstrap,
19677                 glyphicon : id,
19678                 cmd : id || cmd,
19679                 enableToggle:toggle !== false,
19680                 //html : 'submit'
19681                 pressed : toggle ? false : null,
19682                 listeners : {}
19683             }
19684             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19685                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19686             }
19687             children.push(a);
19688             return a;
19689        }
19690         
19691         var style = {
19692                 xtype: 'Button',
19693                 size : 'sm',
19694                 xns: Roo.bootstrap,
19695                 glyphicon : 'font',
19696                 //html : 'submit'
19697                 menu : {
19698                     xtype: 'Menu',
19699                     xns: Roo.bootstrap,
19700                     items:  []
19701                 }
19702         };
19703         Roo.each(this.formats, function(f) {
19704             style.menu.items.push({
19705                 xtype :'MenuItem',
19706                 xns: Roo.bootstrap,
19707                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19708                 tagname : f,
19709                 listeners : {
19710                     click : function()
19711                     {
19712                         editorcore.insertTag(this.tagname);
19713                         editor.focus();
19714                     }
19715                 }
19716                 
19717             });
19718         });
19719          children.push(style);   
19720             
19721             
19722         btn('bold',false,true);
19723         btn('italic',false,true);
19724         btn('align-left', 'justifyleft',true);
19725         btn('align-center', 'justifycenter',true);
19726         btn('align-right' , 'justifyright',true);
19727         btn('link', false, false, function(btn) {
19728             //Roo.log("create link?");
19729             var url = prompt(this.createLinkText, this.defaultLinkValue);
19730             if(url && url != 'http:/'+'/'){
19731                 this.editorcore.relayCmd('createlink', url);
19732             }
19733         }),
19734         btn('list','insertunorderedlist',true);
19735         btn('pencil', false,true, function(btn){
19736                 Roo.log(this);
19737                 
19738                 this.toggleSourceEdit(btn.pressed);
19739         });
19740         /*
19741         var cog = {
19742                 xtype: 'Button',
19743                 size : 'sm',
19744                 xns: Roo.bootstrap,
19745                 glyphicon : 'cog',
19746                 //html : 'submit'
19747                 menu : {
19748                     xtype: 'Menu',
19749                     xns: Roo.bootstrap,
19750                     items:  []
19751                 }
19752         };
19753         
19754         cog.menu.items.push({
19755             xtype :'MenuItem',
19756             xns: Roo.bootstrap,
19757             html : Clean styles,
19758             tagname : f,
19759             listeners : {
19760                 click : function()
19761                 {
19762                     editorcore.insertTag(this.tagname);
19763                     editor.focus();
19764                 }
19765             }
19766             
19767         });
19768        */
19769         
19770          
19771        this.xtype = 'NavSimplebar';
19772         
19773         for(var i=0;i< children.length;i++) {
19774             
19775             this.buttons.add(this.addxtypeChild(children[i]));
19776             
19777         }
19778         
19779         editor.on('editorevent', this.updateToolbar, this);
19780     },
19781     onBtnClick : function(id)
19782     {
19783        this.editorcore.relayCmd(id);
19784        this.editorcore.focus();
19785     },
19786     
19787     /**
19788      * Protected method that will not generally be called directly. It triggers
19789      * a toolbar update by reading the markup state of the current selection in the editor.
19790      */
19791     updateToolbar: function(){
19792
19793         if(!this.editorcore.activated){
19794             this.editor.onFirstFocus(); // is this neeed?
19795             return;
19796         }
19797
19798         var btns = this.buttons; 
19799         var doc = this.editorcore.doc;
19800         btns.get('bold').setActive(doc.queryCommandState('bold'));
19801         btns.get('italic').setActive(doc.queryCommandState('italic'));
19802         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19803         
19804         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19805         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19806         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19807         
19808         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19809         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19810          /*
19811         
19812         var ans = this.editorcore.getAllAncestors();
19813         if (this.formatCombo) {
19814             
19815             
19816             var store = this.formatCombo.store;
19817             this.formatCombo.setValue("");
19818             for (var i =0; i < ans.length;i++) {
19819                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19820                     // select it..
19821                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19822                     break;
19823                 }
19824             }
19825         }
19826         
19827         
19828         
19829         // hides menus... - so this cant be on a menu...
19830         Roo.bootstrap.MenuMgr.hideAll();
19831         */
19832         Roo.bootstrap.MenuMgr.hideAll();
19833         //this.editorsyncValue();
19834     },
19835     onFirstFocus: function() {
19836         this.buttons.each(function(item){
19837            item.enable();
19838         });
19839     },
19840     toggleSourceEdit : function(sourceEditMode){
19841         
19842           
19843         if(sourceEditMode){
19844             Roo.log("disabling buttons");
19845            this.buttons.each( function(item){
19846                 if(item.cmd != 'pencil'){
19847                     item.disable();
19848                 }
19849             });
19850           
19851         }else{
19852             Roo.log("enabling buttons");
19853             if(this.editorcore.initialized){
19854                 this.buttons.each( function(item){
19855                     item.enable();
19856                 });
19857             }
19858             
19859         }
19860         Roo.log("calling toggole on editor");
19861         // tell the editor that it's been pressed..
19862         this.editor.toggleSourceEdit(sourceEditMode);
19863        
19864     }
19865 });
19866
19867
19868
19869
19870
19871 /**
19872  * @class Roo.bootstrap.Table.AbstractSelectionModel
19873  * @extends Roo.util.Observable
19874  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19875  * implemented by descendant classes.  This class should not be directly instantiated.
19876  * @constructor
19877  */
19878 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19879     this.locked = false;
19880     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19881 };
19882
19883
19884 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19885     /** @ignore Called by the grid automatically. Do not call directly. */
19886     init : function(grid){
19887         this.grid = grid;
19888         this.initEvents();
19889     },
19890
19891     /**
19892      * Locks the selections.
19893      */
19894     lock : function(){
19895         this.locked = true;
19896     },
19897
19898     /**
19899      * Unlocks the selections.
19900      */
19901     unlock : function(){
19902         this.locked = false;
19903     },
19904
19905     /**
19906      * Returns true if the selections are locked.
19907      * @return {Boolean}
19908      */
19909     isLocked : function(){
19910         return this.locked;
19911     }
19912 });
19913 /**
19914  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19915  * @class Roo.bootstrap.Table.RowSelectionModel
19916  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19917  * It supports multiple selections and keyboard selection/navigation. 
19918  * @constructor
19919  * @param {Object} config
19920  */
19921
19922 Roo.bootstrap.Table.RowSelectionModel = function(config){
19923     Roo.apply(this, config);
19924     this.selections = new Roo.util.MixedCollection(false, function(o){
19925         return o.id;
19926     });
19927
19928     this.last = false;
19929     this.lastActive = false;
19930
19931     this.addEvents({
19932         /**
19933              * @event selectionchange
19934              * Fires when the selection changes
19935              * @param {SelectionModel} this
19936              */
19937             "selectionchange" : true,
19938         /**
19939              * @event afterselectionchange
19940              * Fires after the selection changes (eg. by key press or clicking)
19941              * @param {SelectionModel} this
19942              */
19943             "afterselectionchange" : true,
19944         /**
19945              * @event beforerowselect
19946              * Fires when a row is selected being selected, return false to cancel.
19947              * @param {SelectionModel} this
19948              * @param {Number} rowIndex The selected index
19949              * @param {Boolean} keepExisting False if other selections will be cleared
19950              */
19951             "beforerowselect" : true,
19952         /**
19953              * @event rowselect
19954              * Fires when a row is selected.
19955              * @param {SelectionModel} this
19956              * @param {Number} rowIndex The selected index
19957              * @param {Roo.data.Record} r The record
19958              */
19959             "rowselect" : true,
19960         /**
19961              * @event rowdeselect
19962              * Fires when a row is deselected.
19963              * @param {SelectionModel} this
19964              * @param {Number} rowIndex The selected index
19965              */
19966         "rowdeselect" : true
19967     });
19968     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19969     this.locked = false;
19970 };
19971
19972 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19973     /**
19974      * @cfg {Boolean} singleSelect
19975      * True to allow selection of only one row at a time (defaults to false)
19976      */
19977     singleSelect : false,
19978
19979     // private
19980     initEvents : function(){
19981
19982         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19983             this.grid.on("mousedown", this.handleMouseDown, this);
19984         }else{ // allow click to work like normal
19985             this.grid.on("rowclick", this.handleDragableRowClick, this);
19986         }
19987
19988         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19989             "up" : function(e){
19990                 if(!e.shiftKey){
19991                     this.selectPrevious(e.shiftKey);
19992                 }else if(this.last !== false && this.lastActive !== false){
19993                     var last = this.last;
19994                     this.selectRange(this.last,  this.lastActive-1);
19995                     this.grid.getView().focusRow(this.lastActive);
19996                     if(last !== false){
19997                         this.last = last;
19998                     }
19999                 }else{
20000                     this.selectFirstRow();
20001                 }
20002                 this.fireEvent("afterselectionchange", this);
20003             },
20004             "down" : function(e){
20005                 if(!e.shiftKey){
20006                     this.selectNext(e.shiftKey);
20007                 }else if(this.last !== false && this.lastActive !== false){
20008                     var last = this.last;
20009                     this.selectRange(this.last,  this.lastActive+1);
20010                     this.grid.getView().focusRow(this.lastActive);
20011                     if(last !== false){
20012                         this.last = last;
20013                     }
20014                 }else{
20015                     this.selectFirstRow();
20016                 }
20017                 this.fireEvent("afterselectionchange", this);
20018             },
20019             scope: this
20020         });
20021
20022         var view = this.grid.view;
20023         view.on("refresh", this.onRefresh, this);
20024         view.on("rowupdated", this.onRowUpdated, this);
20025         view.on("rowremoved", this.onRemove, this);
20026     },
20027
20028     // private
20029     onRefresh : function(){
20030         var ds = this.grid.dataSource, i, v = this.grid.view;
20031         var s = this.selections;
20032         s.each(function(r){
20033             if((i = ds.indexOfId(r.id)) != -1){
20034                 v.onRowSelect(i);
20035             }else{
20036                 s.remove(r);
20037             }
20038         });
20039     },
20040
20041     // private
20042     onRemove : function(v, index, r){
20043         this.selections.remove(r);
20044     },
20045
20046     // private
20047     onRowUpdated : function(v, index, r){
20048         if(this.isSelected(r)){
20049             v.onRowSelect(index);
20050         }
20051     },
20052
20053     /**
20054      * Select records.
20055      * @param {Array} records The records to select
20056      * @param {Boolean} keepExisting (optional) True to keep existing selections
20057      */
20058     selectRecords : function(records, keepExisting){
20059         if(!keepExisting){
20060             this.clearSelections();
20061         }
20062         var ds = this.grid.dataSource;
20063         for(var i = 0, len = records.length; i < len; i++){
20064             this.selectRow(ds.indexOf(records[i]), true);
20065         }
20066     },
20067
20068     /**
20069      * Gets the number of selected rows.
20070      * @return {Number}
20071      */
20072     getCount : function(){
20073         return this.selections.length;
20074     },
20075
20076     /**
20077      * Selects the first row in the grid.
20078      */
20079     selectFirstRow : function(){
20080         this.selectRow(0);
20081     },
20082
20083     /**
20084      * Select the last row.
20085      * @param {Boolean} keepExisting (optional) True to keep existing selections
20086      */
20087     selectLastRow : function(keepExisting){
20088         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20089     },
20090
20091     /**
20092      * Selects the row immediately following the last selected row.
20093      * @param {Boolean} keepExisting (optional) True to keep existing selections
20094      */
20095     selectNext : function(keepExisting){
20096         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20097             this.selectRow(this.last+1, keepExisting);
20098             this.grid.getView().focusRow(this.last);
20099         }
20100     },
20101
20102     /**
20103      * Selects the row that precedes the last selected row.
20104      * @param {Boolean} keepExisting (optional) True to keep existing selections
20105      */
20106     selectPrevious : function(keepExisting){
20107         if(this.last){
20108             this.selectRow(this.last-1, keepExisting);
20109             this.grid.getView().focusRow(this.last);
20110         }
20111     },
20112
20113     /**
20114      * Returns the selected records
20115      * @return {Array} Array of selected records
20116      */
20117     getSelections : function(){
20118         return [].concat(this.selections.items);
20119     },
20120
20121     /**
20122      * Returns the first selected record.
20123      * @return {Record}
20124      */
20125     getSelected : function(){
20126         return this.selections.itemAt(0);
20127     },
20128
20129
20130     /**
20131      * Clears all selections.
20132      */
20133     clearSelections : function(fast){
20134         if(this.locked) return;
20135         if(fast !== true){
20136             var ds = this.grid.dataSource;
20137             var s = this.selections;
20138             s.each(function(r){
20139                 this.deselectRow(ds.indexOfId(r.id));
20140             }, this);
20141             s.clear();
20142         }else{
20143             this.selections.clear();
20144         }
20145         this.last = false;
20146     },
20147
20148
20149     /**
20150      * Selects all rows.
20151      */
20152     selectAll : function(){
20153         if(this.locked) return;
20154         this.selections.clear();
20155         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20156             this.selectRow(i, true);
20157         }
20158     },
20159
20160     /**
20161      * Returns True if there is a selection.
20162      * @return {Boolean}
20163      */
20164     hasSelection : function(){
20165         return this.selections.length > 0;
20166     },
20167
20168     /**
20169      * Returns True if the specified row is selected.
20170      * @param {Number/Record} record The record or index of the record to check
20171      * @return {Boolean}
20172      */
20173     isSelected : function(index){
20174         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20175         return (r && this.selections.key(r.id) ? true : false);
20176     },
20177
20178     /**
20179      * Returns True if the specified record id is selected.
20180      * @param {String} id The id of record to check
20181      * @return {Boolean}
20182      */
20183     isIdSelected : function(id){
20184         return (this.selections.key(id) ? true : false);
20185     },
20186
20187     // private
20188     handleMouseDown : function(e, t){
20189         var view = this.grid.getView(), rowIndex;
20190         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20191             return;
20192         };
20193         if(e.shiftKey && this.last !== false){
20194             var last = this.last;
20195             this.selectRange(last, rowIndex, e.ctrlKey);
20196             this.last = last; // reset the last
20197             view.focusRow(rowIndex);
20198         }else{
20199             var isSelected = this.isSelected(rowIndex);
20200             if(e.button !== 0 && isSelected){
20201                 view.focusRow(rowIndex);
20202             }else if(e.ctrlKey && isSelected){
20203                 this.deselectRow(rowIndex);
20204             }else if(!isSelected){
20205                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20206                 view.focusRow(rowIndex);
20207             }
20208         }
20209         this.fireEvent("afterselectionchange", this);
20210     },
20211     // private
20212     handleDragableRowClick :  function(grid, rowIndex, e) 
20213     {
20214         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20215             this.selectRow(rowIndex, false);
20216             grid.view.focusRow(rowIndex);
20217              this.fireEvent("afterselectionchange", this);
20218         }
20219     },
20220     
20221     /**
20222      * Selects multiple rows.
20223      * @param {Array} rows Array of the indexes of the row to select
20224      * @param {Boolean} keepExisting (optional) True to keep existing selections
20225      */
20226     selectRows : function(rows, keepExisting){
20227         if(!keepExisting){
20228             this.clearSelections();
20229         }
20230         for(var i = 0, len = rows.length; i < len; i++){
20231             this.selectRow(rows[i], true);
20232         }
20233     },
20234
20235     /**
20236      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20237      * @param {Number} startRow The index of the first row in the range
20238      * @param {Number} endRow The index of the last row in the range
20239      * @param {Boolean} keepExisting (optional) True to retain existing selections
20240      */
20241     selectRange : function(startRow, endRow, keepExisting){
20242         if(this.locked) return;
20243         if(!keepExisting){
20244             this.clearSelections();
20245         }
20246         if(startRow <= endRow){
20247             for(var i = startRow; i <= endRow; i++){
20248                 this.selectRow(i, true);
20249             }
20250         }else{
20251             for(var i = startRow; i >= endRow; i--){
20252                 this.selectRow(i, true);
20253             }
20254         }
20255     },
20256
20257     /**
20258      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20259      * @param {Number} startRow The index of the first row in the range
20260      * @param {Number} endRow The index of the last row in the range
20261      */
20262     deselectRange : function(startRow, endRow, preventViewNotify){
20263         if(this.locked) return;
20264         for(var i = startRow; i <= endRow; i++){
20265             this.deselectRow(i, preventViewNotify);
20266         }
20267     },
20268
20269     /**
20270      * Selects a row.
20271      * @param {Number} row The index of the row to select
20272      * @param {Boolean} keepExisting (optional) True to keep existing selections
20273      */
20274     selectRow : function(index, keepExisting, preventViewNotify){
20275         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20276         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20277             if(!keepExisting || this.singleSelect){
20278                 this.clearSelections();
20279             }
20280             var r = this.grid.dataSource.getAt(index);
20281             this.selections.add(r);
20282             this.last = this.lastActive = index;
20283             if(!preventViewNotify){
20284                 this.grid.getView().onRowSelect(index);
20285             }
20286             this.fireEvent("rowselect", this, index, r);
20287             this.fireEvent("selectionchange", this);
20288         }
20289     },
20290
20291     /**
20292      * Deselects a row.
20293      * @param {Number} row The index of the row to deselect
20294      */
20295     deselectRow : function(index, preventViewNotify){
20296         if(this.locked) return;
20297         if(this.last == index){
20298             this.last = false;
20299         }
20300         if(this.lastActive == index){
20301             this.lastActive = false;
20302         }
20303         var r = this.grid.dataSource.getAt(index);
20304         this.selections.remove(r);
20305         if(!preventViewNotify){
20306             this.grid.getView().onRowDeselect(index);
20307         }
20308         this.fireEvent("rowdeselect", this, index);
20309         this.fireEvent("selectionchange", this);
20310     },
20311
20312     // private
20313     restoreLast : function(){
20314         if(this._last){
20315             this.last = this._last;
20316         }
20317     },
20318
20319     // private
20320     acceptsNav : function(row, col, cm){
20321         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20322     },
20323
20324     // private
20325     onEditorKey : function(field, e){
20326         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20327         if(k == e.TAB){
20328             e.stopEvent();
20329             ed.completeEdit();
20330             if(e.shiftKey){
20331                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20332             }else{
20333                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20334             }
20335         }else if(k == e.ENTER && !e.ctrlKey){
20336             e.stopEvent();
20337             ed.completeEdit();
20338             if(e.shiftKey){
20339                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20340             }else{
20341                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20342             }
20343         }else if(k == e.ESC){
20344             ed.cancelEdit();
20345         }
20346         if(newCell){
20347             g.startEditing(newCell[0], newCell[1]);
20348         }
20349     }
20350 });/*
20351  * Based on:
20352  * Ext JS Library 1.1.1
20353  * Copyright(c) 2006-2007, Ext JS, LLC.
20354  *
20355  * Originally Released Under LGPL - original licence link has changed is not relivant.
20356  *
20357  * Fork - LGPL
20358  * <script type="text/javascript">
20359  */
20360  
20361 /**
20362  * @class Roo.bootstrap.PagingToolbar
20363  * @extends Roo.Row
20364  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20365  * @constructor
20366  * Create a new PagingToolbar
20367  * @param {Object} config The config object
20368  */
20369 Roo.bootstrap.PagingToolbar = function(config)
20370 {
20371     // old args format still supported... - xtype is prefered..
20372         // created from xtype...
20373     var ds = config.dataSource;
20374     this.toolbarItems = [];
20375     if (config.items) {
20376         this.toolbarItems = config.items;
20377 //        config.items = [];
20378     }
20379     
20380     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20381     this.ds = ds;
20382     this.cursor = 0;
20383     if (ds) { 
20384         this.bind(ds);
20385     }
20386     
20387     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20388     
20389 };
20390
20391 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20392     /**
20393      * @cfg {Roo.data.Store} dataSource
20394      * The underlying data store providing the paged data
20395      */
20396     /**
20397      * @cfg {String/HTMLElement/Element} container
20398      * container The id or element that will contain the toolbar
20399      */
20400     /**
20401      * @cfg {Boolean} displayInfo
20402      * True to display the displayMsg (defaults to false)
20403      */
20404     /**
20405      * @cfg {Number} pageSize
20406      * The number of records to display per page (defaults to 20)
20407      */
20408     pageSize: 20,
20409     /**
20410      * @cfg {String} displayMsg
20411      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20412      */
20413     displayMsg : 'Displaying {0} - {1} of {2}',
20414     /**
20415      * @cfg {String} emptyMsg
20416      * The message to display when no records are found (defaults to "No data to display")
20417      */
20418     emptyMsg : 'No data to display',
20419     /**
20420      * Customizable piece of the default paging text (defaults to "Page")
20421      * @type String
20422      */
20423     beforePageText : "Page",
20424     /**
20425      * Customizable piece of the default paging text (defaults to "of %0")
20426      * @type String
20427      */
20428     afterPageText : "of {0}",
20429     /**
20430      * Customizable piece of the default paging text (defaults to "First Page")
20431      * @type String
20432      */
20433     firstText : "First Page",
20434     /**
20435      * Customizable piece of the default paging text (defaults to "Previous Page")
20436      * @type String
20437      */
20438     prevText : "Previous Page",
20439     /**
20440      * Customizable piece of the default paging text (defaults to "Next Page")
20441      * @type String
20442      */
20443     nextText : "Next Page",
20444     /**
20445      * Customizable piece of the default paging text (defaults to "Last Page")
20446      * @type String
20447      */
20448     lastText : "Last Page",
20449     /**
20450      * Customizable piece of the default paging text (defaults to "Refresh")
20451      * @type String
20452      */
20453     refreshText : "Refresh",
20454
20455     buttons : false,
20456     // private
20457     onRender : function(ct, position) 
20458     {
20459         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20460         this.navgroup.parentId = this.id;
20461         this.navgroup.onRender(this.el, null);
20462         // add the buttons to the navgroup
20463         
20464         if(this.displayInfo){
20465             Roo.log(this.el.select('ul.navbar-nav',true).first());
20466             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20467             this.displayEl = this.el.select('.x-paging-info', true).first();
20468 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20469 //            this.displayEl = navel.el.select('span',true).first();
20470         }
20471         
20472         var _this = this;
20473         
20474         if(this.buttons){
20475             Roo.each(_this.buttons, function(e){
20476                Roo.factory(e).onRender(_this.el, null);
20477             });
20478         }
20479             
20480         Roo.each(_this.toolbarItems, function(e) {
20481             _this.navgroup.addItem(e);
20482         });
20483         
20484         
20485         this.first = this.navgroup.addItem({
20486             tooltip: this.firstText,
20487             cls: "prev",
20488             icon : 'fa fa-backward',
20489             disabled: true,
20490             preventDefault: true,
20491             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20492         });
20493         
20494         this.prev =  this.navgroup.addItem({
20495             tooltip: this.prevText,
20496             cls: "prev",
20497             icon : 'fa fa-step-backward',
20498             disabled: true,
20499             preventDefault: true,
20500             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20501         });
20502     //this.addSeparator();
20503         
20504         
20505         var field = this.navgroup.addItem( {
20506             tagtype : 'span',
20507             cls : 'x-paging-position',
20508             
20509             html : this.beforePageText  +
20510                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20511                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20512          } ); //?? escaped?
20513         
20514         this.field = field.el.select('input', true).first();
20515         this.field.on("keydown", this.onPagingKeydown, this);
20516         this.field.on("focus", function(){this.dom.select();});
20517     
20518     
20519         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20520         //this.field.setHeight(18);
20521         //this.addSeparator();
20522         this.next = this.navgroup.addItem({
20523             tooltip: this.nextText,
20524             cls: "next",
20525             html : ' <i class="fa fa-step-forward">',
20526             disabled: true,
20527             preventDefault: true,
20528             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20529         });
20530         this.last = this.navgroup.addItem({
20531             tooltip: this.lastText,
20532             icon : 'fa fa-forward',
20533             cls: "next",
20534             disabled: true,
20535             preventDefault: true,
20536             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20537         });
20538     //this.addSeparator();
20539         this.loading = this.navgroup.addItem({
20540             tooltip: this.refreshText,
20541             icon: 'fa fa-refresh',
20542             preventDefault: true,
20543             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20544         });
20545
20546     },
20547
20548     // private
20549     updateInfo : function(){
20550         if(this.displayEl){
20551             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20552             var msg = count == 0 ?
20553                 this.emptyMsg :
20554                 String.format(
20555                     this.displayMsg,
20556                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20557                 );
20558             this.displayEl.update(msg);
20559         }
20560     },
20561
20562     // private
20563     onLoad : function(ds, r, o){
20564        this.cursor = o.params ? o.params.start : 0;
20565        var d = this.getPageData(),
20566             ap = d.activePage,
20567             ps = d.pages;
20568         
20569        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20570        this.field.dom.value = ap;
20571        this.first.setDisabled(ap == 1);
20572        this.prev.setDisabled(ap == 1);
20573        this.next.setDisabled(ap == ps);
20574        this.last.setDisabled(ap == ps);
20575        this.loading.enable();
20576        this.updateInfo();
20577     },
20578
20579     // private
20580     getPageData : function(){
20581         var total = this.ds.getTotalCount();
20582         return {
20583             total : total,
20584             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20585             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20586         };
20587     },
20588
20589     // private
20590     onLoadError : function(){
20591         this.loading.enable();
20592     },
20593
20594     // private
20595     onPagingKeydown : function(e){
20596         var k = e.getKey();
20597         var d = this.getPageData();
20598         if(k == e.RETURN){
20599             var v = this.field.dom.value, pageNum;
20600             if(!v || isNaN(pageNum = parseInt(v, 10))){
20601                 this.field.dom.value = d.activePage;
20602                 return;
20603             }
20604             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20605             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20606             e.stopEvent();
20607         }
20608         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))
20609         {
20610           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20611           this.field.dom.value = pageNum;
20612           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20613           e.stopEvent();
20614         }
20615         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20616         {
20617           var v = this.field.dom.value, pageNum; 
20618           var increment = (e.shiftKey) ? 10 : 1;
20619           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20620             increment *= -1;
20621           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20622             this.field.dom.value = d.activePage;
20623             return;
20624           }
20625           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20626           {
20627             this.field.dom.value = parseInt(v, 10) + increment;
20628             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20629             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20630           }
20631           e.stopEvent();
20632         }
20633     },
20634
20635     // private
20636     beforeLoad : function(){
20637         if(this.loading){
20638             this.loading.disable();
20639         }
20640     },
20641
20642     // private
20643     onClick : function(which){
20644         
20645         var ds = this.ds;
20646         if (!ds) {
20647             return;
20648         }
20649         
20650         switch(which){
20651             case "first":
20652                 ds.load({params:{start: 0, limit: this.pageSize}});
20653             break;
20654             case "prev":
20655                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20656             break;
20657             case "next":
20658                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20659             break;
20660             case "last":
20661                 var total = ds.getTotalCount();
20662                 var extra = total % this.pageSize;
20663                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20664                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20665             break;
20666             case "refresh":
20667                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20668             break;
20669         }
20670     },
20671
20672     /**
20673      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20674      * @param {Roo.data.Store} store The data store to unbind
20675      */
20676     unbind : function(ds){
20677         ds.un("beforeload", this.beforeLoad, this);
20678         ds.un("load", this.onLoad, this);
20679         ds.un("loadexception", this.onLoadError, this);
20680         ds.un("remove", this.updateInfo, this);
20681         ds.un("add", this.updateInfo, this);
20682         this.ds = undefined;
20683     },
20684
20685     /**
20686      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20687      * @param {Roo.data.Store} store The data store to bind
20688      */
20689     bind : function(ds){
20690         ds.on("beforeload", this.beforeLoad, this);
20691         ds.on("load", this.onLoad, this);
20692         ds.on("loadexception", this.onLoadError, this);
20693         ds.on("remove", this.updateInfo, this);
20694         ds.on("add", this.updateInfo, this);
20695         this.ds = ds;
20696     }
20697 });/*
20698  * - LGPL
20699  *
20700  * element
20701  * 
20702  */
20703
20704 /**
20705  * @class Roo.bootstrap.MessageBar
20706  * @extends Roo.bootstrap.Component
20707  * Bootstrap MessageBar class
20708  * @cfg {String} html contents of the MessageBar
20709  * @cfg {String} weight (info | success | warning | danger) default info
20710  * @cfg {String} beforeClass insert the bar before the given class
20711  * @cfg {Boolean} closable (true | false) default false
20712  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20713  * 
20714  * @constructor
20715  * Create a new Element
20716  * @param {Object} config The config object
20717  */
20718
20719 Roo.bootstrap.MessageBar = function(config){
20720     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20721 };
20722
20723 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20724     
20725     html: '',
20726     weight: 'info',
20727     closable: false,
20728     fixed: false,
20729     beforeClass: 'bootstrap-sticky-wrap',
20730     
20731     getAutoCreate : function(){
20732         
20733         var cfg = {
20734             tag: 'div',
20735             cls: 'alert alert-dismissable alert-' + this.weight,
20736             cn: [
20737                 {
20738                     tag: 'span',
20739                     cls: 'message',
20740                     html: this.html || ''
20741                 }
20742             ]
20743         }
20744         
20745         if(this.fixed){
20746             cfg.cls += ' alert-messages-fixed';
20747         }
20748         
20749         if(this.closable){
20750             cfg.cn.push({
20751                 tag: 'button',
20752                 cls: 'close',
20753                 html: 'x'
20754             });
20755         }
20756         
20757         return cfg;
20758     },
20759     
20760     onRender : function(ct, position)
20761     {
20762         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20763         
20764         if(!this.el){
20765             var cfg = Roo.apply({},  this.getAutoCreate());
20766             cfg.id = Roo.id();
20767             
20768             if (this.cls) {
20769                 cfg.cls += ' ' + this.cls;
20770             }
20771             if (this.style) {
20772                 cfg.style = this.style;
20773             }
20774             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20775             
20776             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20777         }
20778         
20779         this.el.select('>button.close').on('click', this.hide, this);
20780         
20781     },
20782     
20783     show : function()
20784     {
20785         if (!this.rendered) {
20786             this.render();
20787         }
20788         
20789         this.el.show();
20790         
20791         this.fireEvent('show', this);
20792         
20793     },
20794     
20795     hide : function()
20796     {
20797         if (!this.rendered) {
20798             this.render();
20799         }
20800         
20801         this.el.hide();
20802         
20803         this.fireEvent('hide', this);
20804     },
20805     
20806     update : function()
20807     {
20808 //        var e = this.el.dom.firstChild;
20809 //        
20810 //        if(this.closable){
20811 //            e = e.nextSibling;
20812 //        }
20813 //        
20814 //        e.data = this.html || '';
20815
20816         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20817     }
20818    
20819 });
20820
20821  
20822
20823      /*
20824  * - LGPL
20825  *
20826  * Graph
20827  * 
20828  */
20829
20830
20831 /**
20832  * @class Roo.bootstrap.Graph
20833  * @extends Roo.bootstrap.Component
20834  * Bootstrap Graph class
20835 > Prameters
20836  -sm {number} sm 4
20837  -md {number} md 5
20838  @cfg {String} graphtype  bar | vbar | pie
20839  @cfg {number} g_x coodinator | centre x (pie)
20840  @cfg {number} g_y coodinator | centre y (pie)
20841  @cfg {number} g_r radius (pie)
20842  @cfg {number} g_height height of the chart (respected by all elements in the set)
20843  @cfg {number} g_width width of the chart (respected by all elements in the set)
20844  @cfg {Object} title The title of the chart
20845     
20846  -{Array}  values
20847  -opts (object) options for the chart 
20848      o {
20849      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20850      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20851      o vgutter (number)
20852      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.
20853      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20854      o to
20855      o stretch (boolean)
20856      o }
20857  -opts (object) options for the pie
20858      o{
20859      o cut
20860      o startAngle (number)
20861      o endAngle (number)
20862      } 
20863  *
20864  * @constructor
20865  * Create a new Input
20866  * @param {Object} config The config object
20867  */
20868
20869 Roo.bootstrap.Graph = function(config){
20870     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20871     
20872     this.addEvents({
20873         // img events
20874         /**
20875          * @event click
20876          * The img click event for the img.
20877          * @param {Roo.EventObject} e
20878          */
20879         "click" : true
20880     });
20881 };
20882
20883 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20884     
20885     sm: 4,
20886     md: 5,
20887     graphtype: 'bar',
20888     g_height: 250,
20889     g_width: 400,
20890     g_x: 50,
20891     g_y: 50,
20892     g_r: 30,
20893     opts:{
20894         //g_colors: this.colors,
20895         g_type: 'soft',
20896         g_gutter: '20%'
20897
20898     },
20899     title : false,
20900
20901     getAutoCreate : function(){
20902         
20903         var cfg = {
20904             tag: 'div',
20905             html : null
20906         }
20907         
20908         
20909         return  cfg;
20910     },
20911
20912     onRender : function(ct,position){
20913         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20914         this.raphael = Raphael(this.el.dom);
20915         
20916                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20917                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20918                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20919                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20920                 /*
20921                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20922                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20923                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20924                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20925                 
20926                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20927                 r.barchart(330, 10, 300, 220, data1);
20928                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20929                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20930                 */
20931                 
20932                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20933                 // r.barchart(30, 30, 560, 250,  xdata, {
20934                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20935                 //     axis : "0 0 1 1",
20936                 //     axisxlabels :  xdata
20937                 //     //yvalues : cols,
20938                    
20939                 // });
20940 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20941 //        
20942 //        this.load(null,xdata,{
20943 //                axis : "0 0 1 1",
20944 //                axisxlabels :  xdata
20945 //                });
20946
20947     },
20948
20949     load : function(graphtype,xdata,opts){
20950         this.raphael.clear();
20951         if(!graphtype) {
20952             graphtype = this.graphtype;
20953         }
20954         if(!opts){
20955             opts = this.opts;
20956         }
20957         var r = this.raphael,
20958             fin = function () {
20959                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20960             },
20961             fout = function () {
20962                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20963             },
20964             pfin = function() {
20965                 this.sector.stop();
20966                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20967
20968                 if (this.label) {
20969                     this.label[0].stop();
20970                     this.label[0].attr({ r: 7.5 });
20971                     this.label[1].attr({ "font-weight": 800 });
20972                 }
20973             },
20974             pfout = function() {
20975                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20976
20977                 if (this.label) {
20978                     this.label[0].animate({ r: 5 }, 500, "bounce");
20979                     this.label[1].attr({ "font-weight": 400 });
20980                 }
20981             };
20982
20983         switch(graphtype){
20984             case 'bar':
20985                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20986                 break;
20987             case 'hbar':
20988                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20989                 break;
20990             case 'pie':
20991 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20992 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20993 //            
20994                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20995                 
20996                 break;
20997
20998         }
20999         
21000         if(this.title){
21001             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21002         }
21003         
21004     },
21005     
21006     setTitle: function(o)
21007     {
21008         this.title = o;
21009     },
21010     
21011     initEvents: function() {
21012         
21013         if(!this.href){
21014             this.el.on('click', this.onClick, this);
21015         }
21016     },
21017     
21018     onClick : function(e)
21019     {
21020         Roo.log('img onclick');
21021         this.fireEvent('click', this, e);
21022     }
21023    
21024 });
21025
21026  
21027 /*
21028  * - LGPL
21029  *
21030  * numberBox
21031  * 
21032  */
21033 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21034
21035 /**
21036  * @class Roo.bootstrap.dash.NumberBox
21037  * @extends Roo.bootstrap.Component
21038  * Bootstrap NumberBox class
21039  * @cfg {String} headline Box headline
21040  * @cfg {String} content Box content
21041  * @cfg {String} icon Box icon
21042  * @cfg {String} footer Footer text
21043  * @cfg {String} fhref Footer href
21044  * 
21045  * @constructor
21046  * Create a new NumberBox
21047  * @param {Object} config The config object
21048  */
21049
21050
21051 Roo.bootstrap.dash.NumberBox = function(config){
21052     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21053     
21054 };
21055
21056 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
21057     
21058     headline : '',
21059     content : '',
21060     icon : '',
21061     footer : '',
21062     fhref : '',
21063     ficon : '',
21064     
21065     getAutoCreate : function(){
21066         
21067         var cfg = {
21068             tag : 'div',
21069             cls : 'small-box ',
21070             cn : [
21071                 {
21072                     tag : 'div',
21073                     cls : 'inner',
21074                     cn :[
21075                         {
21076                             tag : 'h3',
21077                             cls : 'roo-headline',
21078                             html : this.headline
21079                         },
21080                         {
21081                             tag : 'p',
21082                             cls : 'roo-content',
21083                             html : this.content
21084                         }
21085                     ]
21086                 }
21087             ]
21088         }
21089         
21090         if(this.icon){
21091             cfg.cn.push({
21092                 tag : 'div',
21093                 cls : 'icon',
21094                 cn :[
21095                     {
21096                         tag : 'i',
21097                         cls : 'ion ' + this.icon
21098                     }
21099                 ]
21100             });
21101         }
21102         
21103         if(this.footer){
21104             var footer = {
21105                 tag : 'a',
21106                 cls : 'small-box-footer',
21107                 href : this.fhref || '#',
21108                 html : this.footer
21109             };
21110             
21111             cfg.cn.push(footer);
21112             
21113         }
21114         
21115         return  cfg;
21116     },
21117
21118     onRender : function(ct,position){
21119         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21120
21121
21122        
21123                 
21124     },
21125
21126     setHeadline: function (value)
21127     {
21128         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21129     },
21130     
21131     setFooter: function (value, href)
21132     {
21133         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21134         
21135         if(href){
21136             this.el.select('a.small-box-footer',true).first().attr('href', href);
21137         }
21138         
21139     },
21140
21141     setContent: function (value)
21142     {
21143         this.el.select('.roo-content',true).first().dom.innerHTML = value;
21144     },
21145
21146     initEvents: function() 
21147     {   
21148         
21149     }
21150     
21151 });
21152
21153  
21154 /*
21155  * - LGPL
21156  *
21157  * TabBox
21158  * 
21159  */
21160 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21161
21162 /**
21163  * @class Roo.bootstrap.dash.TabBox
21164  * @extends Roo.bootstrap.Component
21165  * Bootstrap TabBox class
21166  * @cfg {String} title Title of the TabBox
21167  * @cfg {String} icon Icon of the TabBox
21168  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21169  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21170  * 
21171  * @constructor
21172  * Create a new TabBox
21173  * @param {Object} config The config object
21174  */
21175
21176
21177 Roo.bootstrap.dash.TabBox = function(config){
21178     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21179     this.addEvents({
21180         // raw events
21181         /**
21182          * @event addpane
21183          * When a pane is added
21184          * @param {Roo.bootstrap.dash.TabPane} pane
21185          */
21186         "addpane" : true,
21187         /**
21188          * @event activatepane
21189          * When a pane is activated
21190          * @param {Roo.bootstrap.dash.TabPane} pane
21191          */
21192         "activatepane" : true
21193         
21194          
21195     });
21196     
21197     this.panes = [];
21198 };
21199
21200 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21201
21202     title : '',
21203     icon : false,
21204     showtabs : true,
21205     tabScrollable : false,
21206     
21207     getChildContainer : function()
21208     {
21209         return this.el.select('.tab-content', true).first();
21210     },
21211     
21212     getAutoCreate : function(){
21213         
21214         var header = {
21215             tag: 'li',
21216             cls: 'pull-left header',
21217             html: this.title,
21218             cn : []
21219         };
21220         
21221         if(this.icon){
21222             header.cn.push({
21223                 tag: 'i',
21224                 cls: 'fa ' + this.icon
21225             });
21226         }
21227         
21228         var h = {
21229             tag: 'ul',
21230             cls: 'nav nav-tabs pull-right',
21231             cn: [
21232                 header
21233             ]
21234         };
21235         
21236         if(this.tabScrollable){
21237             h = {
21238                 tag: 'div',
21239                 cls: 'tab-header',
21240                 cn: [
21241                     {
21242                         tag: 'ul',
21243                         cls: 'nav nav-tabs pull-right',
21244                         cn: [
21245                             header
21246                         ]
21247                     }
21248                 ]
21249             }
21250         }
21251         
21252         var cfg = {
21253             tag: 'div',
21254             cls: 'nav-tabs-custom',
21255             cn: [
21256                 h,
21257                 {
21258                     tag: 'div',
21259                     cls: 'tab-content no-padding',
21260                     cn: []
21261                 }
21262             ]
21263         }
21264
21265         return  cfg;
21266     },
21267     initEvents : function()
21268     {
21269         //Roo.log('add add pane handler');
21270         this.on('addpane', this.onAddPane, this);
21271     },
21272      /**
21273      * Updates the box title
21274      * @param {String} html to set the title to.
21275      */
21276     setTitle : function(value)
21277     {
21278         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21279     },
21280     onAddPane : function(pane)
21281     {
21282         this.panes.push(pane);
21283         //Roo.log('addpane');
21284         //Roo.log(pane);
21285         // tabs are rendere left to right..
21286         if(!this.showtabs){
21287             return;
21288         }
21289         
21290         var ctr = this.el.select('.nav-tabs', true).first();
21291          
21292          
21293         var existing = ctr.select('.nav-tab',true);
21294         var qty = existing.getCount();;
21295         
21296         
21297         var tab = ctr.createChild({
21298             tag : 'li',
21299             cls : 'nav-tab' + (qty ? '' : ' active'),
21300             cn : [
21301                 {
21302                     tag : 'a',
21303                     href:'#',
21304                     html : pane.title
21305                 }
21306             ]
21307         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21308         pane.tab = tab;
21309         
21310         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21311         if (!qty) {
21312             pane.el.addClass('active');
21313         }
21314         
21315                 
21316     },
21317     onTabClick : function(ev,un,ob,pane)
21318     {
21319         //Roo.log('tab - prev default');
21320         ev.preventDefault();
21321         
21322         
21323         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21324         pane.tab.addClass('active');
21325         //Roo.log(pane.title);
21326         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21327         // technically we should have a deactivate event.. but maybe add later.
21328         // and it should not de-activate the selected tab...
21329         this.fireEvent('activatepane', pane);
21330         pane.el.addClass('active');
21331         pane.fireEvent('activate');
21332         
21333         
21334     },
21335     
21336     getActivePane : function()
21337     {
21338         var r = false;
21339         Roo.each(this.panes, function(p) {
21340             if(p.el.hasClass('active')){
21341                 r = p;
21342                 return false;
21343             }
21344             
21345             return;
21346         });
21347         
21348         return r;
21349     }
21350     
21351     
21352 });
21353
21354  
21355 /*
21356  * - LGPL
21357  *
21358  * Tab pane
21359  * 
21360  */
21361 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21362 /**
21363  * @class Roo.bootstrap.TabPane
21364  * @extends Roo.bootstrap.Component
21365  * Bootstrap TabPane class
21366  * @cfg {Boolean} active (false | true) Default false
21367  * @cfg {String} title title of panel
21368
21369  * 
21370  * @constructor
21371  * Create a new TabPane
21372  * @param {Object} config The config object
21373  */
21374
21375 Roo.bootstrap.dash.TabPane = function(config){
21376     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21377     
21378     this.addEvents({
21379         // raw events
21380         /**
21381          * @event activate
21382          * When a pane is activated
21383          * @param {Roo.bootstrap.dash.TabPane} pane
21384          */
21385         "activate" : true
21386          
21387     });
21388 };
21389
21390 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21391     
21392     active : false,
21393     title : '',
21394     
21395     // the tabBox that this is attached to.
21396     tab : false,
21397      
21398     getAutoCreate : function() 
21399     {
21400         var cfg = {
21401             tag: 'div',
21402             cls: 'tab-pane'
21403         }
21404         
21405         if(this.active){
21406             cfg.cls += ' active';
21407         }
21408         
21409         return cfg;
21410     },
21411     initEvents  : function()
21412     {
21413         //Roo.log('trigger add pane handler');
21414         this.parent().fireEvent('addpane', this)
21415     },
21416     
21417      /**
21418      * Updates the tab title 
21419      * @param {String} html to set the title to.
21420      */
21421     setTitle: function(str)
21422     {
21423         if (!this.tab) {
21424             return;
21425         }
21426         this.title = str;
21427         this.tab.select('a', true).first().dom.innerHTML = str;
21428         
21429     }
21430     
21431     
21432     
21433 });
21434
21435  
21436
21437
21438  /*
21439  * - LGPL
21440  *
21441  * menu
21442  * 
21443  */
21444 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21445
21446 /**
21447  * @class Roo.bootstrap.menu.Menu
21448  * @extends Roo.bootstrap.Component
21449  * Bootstrap Menu class - container for Menu
21450  * @cfg {String} html Text of the menu
21451  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21452  * @cfg {String} icon Font awesome icon
21453  * @cfg {String} pos Menu align to (top | bottom) default bottom
21454  * 
21455  * 
21456  * @constructor
21457  * Create a new Menu
21458  * @param {Object} config The config object
21459  */
21460
21461
21462 Roo.bootstrap.menu.Menu = function(config){
21463     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21464     
21465     this.addEvents({
21466         /**
21467          * @event beforeshow
21468          * Fires before this menu is displayed
21469          * @param {Roo.bootstrap.menu.Menu} this
21470          */
21471         beforeshow : true,
21472         /**
21473          * @event beforehide
21474          * Fires before this menu is hidden
21475          * @param {Roo.bootstrap.menu.Menu} this
21476          */
21477         beforehide : true,
21478         /**
21479          * @event show
21480          * Fires after this menu is displayed
21481          * @param {Roo.bootstrap.menu.Menu} this
21482          */
21483         show : true,
21484         /**
21485          * @event hide
21486          * Fires after this menu is hidden
21487          * @param {Roo.bootstrap.menu.Menu} this
21488          */
21489         hide : true,
21490         /**
21491          * @event click
21492          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21493          * @param {Roo.bootstrap.menu.Menu} this
21494          * @param {Roo.EventObject} e
21495          */
21496         click : true
21497     });
21498     
21499 };
21500
21501 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21502     
21503     submenu : false,
21504     html : '',
21505     weight : 'default',
21506     icon : false,
21507     pos : 'bottom',
21508     
21509     
21510     getChildContainer : function() {
21511         if(this.isSubMenu){
21512             return this.el;
21513         }
21514         
21515         return this.el.select('ul.dropdown-menu', true).first();  
21516     },
21517     
21518     getAutoCreate : function()
21519     {
21520         var text = [
21521             {
21522                 tag : 'span',
21523                 cls : 'roo-menu-text',
21524                 html : this.html
21525             }
21526         ];
21527         
21528         if(this.icon){
21529             text.unshift({
21530                 tag : 'i',
21531                 cls : 'fa ' + this.icon
21532             })
21533         }
21534         
21535         
21536         var cfg = {
21537             tag : 'div',
21538             cls : 'btn-group',
21539             cn : [
21540                 {
21541                     tag : 'button',
21542                     cls : 'dropdown-button btn btn-' + this.weight,
21543                     cn : text
21544                 },
21545                 {
21546                     tag : 'button',
21547                     cls : 'dropdown-toggle btn btn-' + this.weight,
21548                     cn : [
21549                         {
21550                             tag : 'span',
21551                             cls : 'caret'
21552                         }
21553                     ]
21554                 },
21555                 {
21556                     tag : 'ul',
21557                     cls : 'dropdown-menu'
21558                 }
21559             ]
21560             
21561         };
21562         
21563         if(this.pos == 'top'){
21564             cfg.cls += ' dropup';
21565         }
21566         
21567         if(this.isSubMenu){
21568             cfg = {
21569                 tag : 'ul',
21570                 cls : 'dropdown-menu'
21571             }
21572         }
21573         
21574         return cfg;
21575     },
21576     
21577     onRender : function(ct, position)
21578     {
21579         this.isSubMenu = ct.hasClass('dropdown-submenu');
21580         
21581         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21582     },
21583     
21584     initEvents : function() 
21585     {
21586         if(this.isSubMenu){
21587             return;
21588         }
21589         
21590         this.hidden = true;
21591         
21592         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21593         this.triggerEl.on('click', this.onTriggerPress, this);
21594         
21595         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21596         this.buttonEl.on('click', this.onClick, this);
21597         
21598     },
21599     
21600     list : function()
21601     {
21602         if(this.isSubMenu){
21603             return this.el;
21604         }
21605         
21606         return this.el.select('ul.dropdown-menu', true).first();
21607     },
21608     
21609     onClick : function(e)
21610     {
21611         this.fireEvent("click", this, e);
21612     },
21613     
21614     onTriggerPress  : function(e)
21615     {   
21616         if (this.isVisible()) {
21617             this.hide();
21618         } else {
21619             this.show();
21620         }
21621     },
21622     
21623     isVisible : function(){
21624         return !this.hidden;
21625     },
21626     
21627     show : function()
21628     {
21629         this.fireEvent("beforeshow", this);
21630         
21631         this.hidden = false;
21632         this.el.addClass('open');
21633         
21634         Roo.get(document).on("mouseup", this.onMouseUp, this);
21635         
21636         this.fireEvent("show", this);
21637         
21638         
21639     },
21640     
21641     hide : function()
21642     {
21643         this.fireEvent("beforehide", this);
21644         
21645         this.hidden = true;
21646         this.el.removeClass('open');
21647         
21648         Roo.get(document).un("mouseup", this.onMouseUp);
21649         
21650         this.fireEvent("hide", this);
21651     },
21652     
21653     onMouseUp : function()
21654     {
21655         this.hide();
21656     }
21657     
21658 });
21659
21660  
21661  /*
21662  * - LGPL
21663  *
21664  * menu item
21665  * 
21666  */
21667 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21668
21669 /**
21670  * @class Roo.bootstrap.menu.Item
21671  * @extends Roo.bootstrap.Component
21672  * Bootstrap MenuItem class
21673  * @cfg {Boolean} submenu (true | false) default false
21674  * @cfg {String} html text of the item
21675  * @cfg {String} href the link
21676  * @cfg {Boolean} disable (true | false) default false
21677  * @cfg {Boolean} preventDefault (true | false) default true
21678  * @cfg {String} icon Font awesome icon
21679  * @cfg {String} pos Submenu align to (left | right) default right 
21680  * 
21681  * 
21682  * @constructor
21683  * Create a new Item
21684  * @param {Object} config The config object
21685  */
21686
21687
21688 Roo.bootstrap.menu.Item = function(config){
21689     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21690     this.addEvents({
21691         /**
21692          * @event mouseover
21693          * Fires when the mouse is hovering over this menu
21694          * @param {Roo.bootstrap.menu.Item} this
21695          * @param {Roo.EventObject} e
21696          */
21697         mouseover : true,
21698         /**
21699          * @event mouseout
21700          * Fires when the mouse exits this menu
21701          * @param {Roo.bootstrap.menu.Item} this
21702          * @param {Roo.EventObject} e
21703          */
21704         mouseout : true,
21705         // raw events
21706         /**
21707          * @event click
21708          * The raw click event for the entire grid.
21709          * @param {Roo.EventObject} e
21710          */
21711         click : true
21712     });
21713 };
21714
21715 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21716     
21717     submenu : false,
21718     href : '',
21719     html : '',
21720     preventDefault: true,
21721     disable : false,
21722     icon : false,
21723     pos : 'right',
21724     
21725     getAutoCreate : function()
21726     {
21727         var text = [
21728             {
21729                 tag : 'span',
21730                 cls : 'roo-menu-item-text',
21731                 html : this.html
21732             }
21733         ];
21734         
21735         if(this.icon){
21736             text.unshift({
21737                 tag : 'i',
21738                 cls : 'fa ' + this.icon
21739             })
21740         }
21741         
21742         var cfg = {
21743             tag : 'li',
21744             cn : [
21745                 {
21746                     tag : 'a',
21747                     href : this.href || '#',
21748                     cn : text
21749                 }
21750             ]
21751         };
21752         
21753         if(this.disable){
21754             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21755         }
21756         
21757         if(this.submenu){
21758             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21759             
21760             if(this.pos == 'left'){
21761                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21762             }
21763         }
21764         
21765         return cfg;
21766     },
21767     
21768     initEvents : function() 
21769     {
21770         this.el.on('mouseover', this.onMouseOver, this);
21771         this.el.on('mouseout', this.onMouseOut, this);
21772         
21773         this.el.select('a', true).first().on('click', this.onClick, this);
21774         
21775     },
21776     
21777     onClick : function(e)
21778     {
21779         if(this.preventDefault){
21780             e.preventDefault();
21781         }
21782         
21783         this.fireEvent("click", this, e);
21784     },
21785     
21786     onMouseOver : function(e)
21787     {
21788         if(this.submenu && this.pos == 'left'){
21789             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21790         }
21791         
21792         this.fireEvent("mouseover", this, e);
21793     },
21794     
21795     onMouseOut : function(e)
21796     {
21797         this.fireEvent("mouseout", this, e);
21798     }
21799 });
21800
21801  
21802
21803  /*
21804  * - LGPL
21805  *
21806  * menu separator
21807  * 
21808  */
21809 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21810
21811 /**
21812  * @class Roo.bootstrap.menu.Separator
21813  * @extends Roo.bootstrap.Component
21814  * Bootstrap Separator class
21815  * 
21816  * @constructor
21817  * Create a new Separator
21818  * @param {Object} config The config object
21819  */
21820
21821
21822 Roo.bootstrap.menu.Separator = function(config){
21823     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21824 };
21825
21826 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21827     
21828     getAutoCreate : function(){
21829         var cfg = {
21830             tag : 'li',
21831             cls: 'divider'
21832         };
21833         
21834         return cfg;
21835     }
21836    
21837 });
21838
21839  
21840
21841  /*
21842  * - LGPL
21843  *
21844  * Tooltip
21845  * 
21846  */
21847
21848 /**
21849  * @class Roo.bootstrap.Tooltip
21850  * Bootstrap Tooltip class
21851  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21852  * to determine which dom element triggers the tooltip.
21853  * 
21854  * It needs to add support for additional attributes like tooltip-position
21855  * 
21856  * @constructor
21857  * Create a new Toolti
21858  * @param {Object} config The config object
21859  */
21860
21861 Roo.bootstrap.Tooltip = function(config){
21862     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21863 };
21864
21865 Roo.apply(Roo.bootstrap.Tooltip, {
21866     /**
21867      * @function init initialize tooltip monitoring.
21868      * @static
21869      */
21870     currentEl : false,
21871     currentTip : false,
21872     currentRegion : false,
21873     
21874     //  init : delay?
21875     
21876     init : function()
21877     {
21878         Roo.get(document).on('mouseover', this.enter ,this);
21879         Roo.get(document).on('mouseout', this.leave, this);
21880          
21881         
21882         this.currentTip = new Roo.bootstrap.Tooltip();
21883     },
21884     
21885     enter : function(ev)
21886     {
21887         var dom = ev.getTarget();
21888         
21889         //Roo.log(['enter',dom]);
21890         var el = Roo.fly(dom);
21891         if (this.currentEl) {
21892             //Roo.log(dom);
21893             //Roo.log(this.currentEl);
21894             //Roo.log(this.currentEl.contains(dom));
21895             if (this.currentEl == el) {
21896                 return;
21897             }
21898             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21899                 return;
21900             }
21901
21902         }
21903         
21904         
21905         
21906         if (this.currentTip.el) {
21907             this.currentTip.el.hide(); // force hiding...
21908         }    
21909         //Roo.log(ev);
21910         var bindEl = el;
21911         
21912         // you can not look for children, as if el is the body.. then everythign is the child..
21913         if (!el.attr('tooltip')) { //
21914             if (!el.select("[tooltip]").elements.length) {
21915                 return;
21916             }
21917             // is the mouse over this child...?
21918             bindEl = el.select("[tooltip]").first();
21919             var xy = ev.getXY();
21920             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21921                 //Roo.log("not in region.");
21922                 return;
21923             }
21924             //Roo.log("child element over..");
21925             
21926         }
21927         this.currentEl = bindEl;
21928         this.currentTip.bind(bindEl);
21929         this.currentRegion = Roo.lib.Region.getRegion(dom);
21930         this.currentTip.enter();
21931         
21932     },
21933     leave : function(ev)
21934     {
21935         var dom = ev.getTarget();
21936         //Roo.log(['leave',dom]);
21937         if (!this.currentEl) {
21938             return;
21939         }
21940         
21941         
21942         if (dom != this.currentEl.dom) {
21943             return;
21944         }
21945         var xy = ev.getXY();
21946         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21947             return;
21948         }
21949         // only activate leave if mouse cursor is outside... bounding box..
21950         
21951         
21952         
21953         
21954         if (this.currentTip) {
21955             this.currentTip.leave();
21956         }
21957         //Roo.log('clear currentEl');
21958         this.currentEl = false;
21959         
21960         
21961     },
21962     alignment : {
21963         'left' : ['r-l', [-2,0], 'right'],
21964         'right' : ['l-r', [2,0], 'left'],
21965         'bottom' : ['t-b', [0,2], 'top'],
21966         'top' : [ 'b-t', [0,-2], 'bottom']
21967     }
21968     
21969 });
21970
21971
21972 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21973     
21974     
21975     bindEl : false,
21976     
21977     delay : null, // can be { show : 300 , hide: 500}
21978     
21979     timeout : null,
21980     
21981     hoverState : null, //???
21982     
21983     placement : 'bottom', 
21984     
21985     getAutoCreate : function(){
21986     
21987         var cfg = {
21988            cls : 'tooltip',
21989            role : 'tooltip',
21990            cn : [
21991                 {
21992                     cls : 'tooltip-arrow'
21993                 },
21994                 {
21995                     cls : 'tooltip-inner'
21996                 }
21997            ]
21998         };
21999         
22000         return cfg;
22001     },
22002     bind : function(el)
22003     {
22004         this.bindEl = el;
22005     },
22006       
22007     
22008     enter : function () {
22009        
22010         if (this.timeout != null) {
22011             clearTimeout(this.timeout);
22012         }
22013         
22014         this.hoverState = 'in';
22015          //Roo.log("enter - show");
22016         if (!this.delay || !this.delay.show) {
22017             this.show();
22018             return;
22019         }
22020         var _t = this;
22021         this.timeout = setTimeout(function () {
22022             if (_t.hoverState == 'in') {
22023                 _t.show();
22024             }
22025         }, this.delay.show);
22026     },
22027     leave : function()
22028     {
22029         clearTimeout(this.timeout);
22030     
22031         this.hoverState = 'out';
22032          if (!this.delay || !this.delay.hide) {
22033             this.hide();
22034             return;
22035         }
22036        
22037         var _t = this;
22038         this.timeout = setTimeout(function () {
22039             //Roo.log("leave - timeout");
22040             
22041             if (_t.hoverState == 'out') {
22042                 _t.hide();
22043                 Roo.bootstrap.Tooltip.currentEl = false;
22044             }
22045         }, delay);
22046     },
22047     
22048     show : function ()
22049     {
22050         if (!this.el) {
22051             this.render(document.body);
22052         }
22053         // set content.
22054         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22055         
22056         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22057         
22058         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22059         
22060         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22061         
22062         var placement = typeof this.placement == 'function' ?
22063             this.placement.call(this, this.el, on_el) :
22064             this.placement;
22065             
22066         var autoToken = /\s?auto?\s?/i;
22067         var autoPlace = autoToken.test(placement);
22068         if (autoPlace) {
22069             placement = placement.replace(autoToken, '') || 'top';
22070         }
22071         
22072         //this.el.detach()
22073         //this.el.setXY([0,0]);
22074         this.el.show();
22075         //this.el.dom.style.display='block';
22076         this.el.addClass(placement);
22077         
22078         //this.el.appendTo(on_el);
22079         
22080         var p = this.getPosition();
22081         var box = this.el.getBox();
22082         
22083         if (autoPlace) {
22084             // fixme..
22085         }
22086         var align = Roo.bootstrap.Tooltip.alignment[placement];
22087         this.el.alignTo(this.bindEl, align[0],align[1]);
22088         //var arrow = this.el.select('.arrow',true).first();
22089         //arrow.set(align[2], 
22090         
22091         this.el.addClass('in fade');
22092         this.hoverState = null;
22093         
22094         if (this.el.hasClass('fade')) {
22095             // fade it?
22096         }
22097         
22098     },
22099     hide : function()
22100     {
22101          
22102         if (!this.el) {
22103             return;
22104         }
22105         //this.el.setXY([0,0]);
22106         this.el.removeClass('in');
22107         //this.el.hide();
22108         
22109     }
22110     
22111 });
22112  
22113
22114  /*
22115  * - LGPL
22116  *
22117  * Location Picker
22118  * 
22119  */
22120
22121 /**
22122  * @class Roo.bootstrap.LocationPicker
22123  * @extends Roo.bootstrap.Component
22124  * Bootstrap LocationPicker class
22125  * @cfg {Number} latitude Position when init default 0
22126  * @cfg {Number} longitude Position when init default 0
22127  * @cfg {Number} zoom default 15
22128  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22129  * @cfg {Boolean} mapTypeControl default false
22130  * @cfg {Boolean} disableDoubleClickZoom default false
22131  * @cfg {Boolean} scrollwheel default true
22132  * @cfg {Boolean} streetViewControl default false
22133  * @cfg {Number} radius default 0
22134  * @cfg {String} locationName
22135  * @cfg {Boolean} draggable default true
22136  * @cfg {Boolean} enableAutocomplete default false
22137  * @cfg {Boolean} enableReverseGeocode default true
22138  * @cfg {String} markerTitle
22139  * 
22140  * @constructor
22141  * Create a new LocationPicker
22142  * @param {Object} config The config object
22143  */
22144
22145
22146 Roo.bootstrap.LocationPicker = function(config){
22147     
22148     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22149     
22150     this.addEvents({
22151         /**
22152          * @event initial
22153          * Fires when the picker initialized.
22154          * @param {Roo.bootstrap.LocationPicker} this
22155          * @param {Google Location} location
22156          */
22157         initial : true,
22158         /**
22159          * @event positionchanged
22160          * Fires when the picker position changed.
22161          * @param {Roo.bootstrap.LocationPicker} this
22162          * @param {Google Location} location
22163          */
22164         positionchanged : true,
22165         /**
22166          * @event resize
22167          * Fires when the map resize.
22168          * @param {Roo.bootstrap.LocationPicker} this
22169          */
22170         resize : true,
22171         /**
22172          * @event show
22173          * Fires when the map show.
22174          * @param {Roo.bootstrap.LocationPicker} this
22175          */
22176         show : true,
22177         /**
22178          * @event hide
22179          * Fires when the map hide.
22180          * @param {Roo.bootstrap.LocationPicker} this
22181          */
22182         hide : true,
22183         /**
22184          * @event mapClick
22185          * Fires when click the map.
22186          * @param {Roo.bootstrap.LocationPicker} this
22187          * @param {Map event} e
22188          */
22189         mapClick : true,
22190         /**
22191          * @event mapRightClick
22192          * Fires when right click the map.
22193          * @param {Roo.bootstrap.LocationPicker} this
22194          * @param {Map event} e
22195          */
22196         mapRightClick : true,
22197         /**
22198          * @event markerClick
22199          * Fires when click the marker.
22200          * @param {Roo.bootstrap.LocationPicker} this
22201          * @param {Map event} e
22202          */
22203         markerClick : true,
22204         /**
22205          * @event markerRightClick
22206          * Fires when right click the marker.
22207          * @param {Roo.bootstrap.LocationPicker} this
22208          * @param {Map event} e
22209          */
22210         markerRightClick : true,
22211         /**
22212          * @event OverlayViewDraw
22213          * Fires when OverlayView Draw
22214          * @param {Roo.bootstrap.LocationPicker} this
22215          */
22216         OverlayViewDraw : true,
22217         /**
22218          * @event OverlayViewOnAdd
22219          * Fires when OverlayView Draw
22220          * @param {Roo.bootstrap.LocationPicker} this
22221          */
22222         OverlayViewOnAdd : true,
22223         /**
22224          * @event OverlayViewOnRemove
22225          * Fires when OverlayView Draw
22226          * @param {Roo.bootstrap.LocationPicker} this
22227          */
22228         OverlayViewOnRemove : true,
22229         /**
22230          * @event OverlayViewShow
22231          * Fires when OverlayView Draw
22232          * @param {Roo.bootstrap.LocationPicker} this
22233          * @param {Pixel} cpx
22234          */
22235         OverlayViewShow : true,
22236         /**
22237          * @event OverlayViewHide
22238          * Fires when OverlayView Draw
22239          * @param {Roo.bootstrap.LocationPicker} this
22240          */
22241         OverlayViewHide : true
22242     });
22243         
22244 };
22245
22246 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22247     
22248     gMapContext: false,
22249     
22250     latitude: 0,
22251     longitude: 0,
22252     zoom: 15,
22253     mapTypeId: false,
22254     mapTypeControl: false,
22255     disableDoubleClickZoom: false,
22256     scrollwheel: true,
22257     streetViewControl: false,
22258     radius: 0,
22259     locationName: '',
22260     draggable: true,
22261     enableAutocomplete: false,
22262     enableReverseGeocode: true,
22263     markerTitle: '',
22264     
22265     getAutoCreate: function()
22266     {
22267
22268         var cfg = {
22269             tag: 'div',
22270             cls: 'roo-location-picker'
22271         };
22272         
22273         return cfg
22274     },
22275     
22276     initEvents: function(ct, position)
22277     {       
22278         if(!this.el.getWidth() || this.isApplied()){
22279             return;
22280         }
22281         
22282         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22283         
22284         this.initial();
22285     },
22286     
22287     initial: function()
22288     {
22289         if(!this.mapTypeId){
22290             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22291         }
22292         
22293         this.gMapContext = this.GMapContext();
22294         
22295         this.initOverlayView();
22296         
22297         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22298         
22299         var _this = this;
22300                 
22301         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22302             _this.setPosition(_this.gMapContext.marker.position);
22303         });
22304         
22305         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22306             _this.fireEvent('mapClick', this, event);
22307             
22308         });
22309
22310         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22311             _this.fireEvent('mapRightClick', this, event);
22312             
22313         });
22314         
22315         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22316             _this.fireEvent('markerClick', this, event);
22317             
22318         });
22319
22320         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22321             _this.fireEvent('markerRightClick', this, event);
22322             
22323         });
22324         
22325         this.setPosition(this.gMapContext.location);
22326         
22327         this.fireEvent('initial', this, this.gMapContext.location);
22328     },
22329     
22330     initOverlayView: function()
22331     {
22332         var _this = this;
22333         
22334         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22335             
22336             draw: function()
22337             {
22338                 _this.fireEvent('OverlayViewDraw', _this);
22339             },
22340             
22341             onAdd: function()
22342             {
22343                 _this.fireEvent('OverlayViewOnAdd', _this);
22344             },
22345             
22346             onRemove: function()
22347             {
22348                 _this.fireEvent('OverlayViewOnRemove', _this);
22349             },
22350             
22351             show: function(cpx)
22352             {
22353                 _this.fireEvent('OverlayViewShow', _this, cpx);
22354             },
22355             
22356             hide: function()
22357             {
22358                 _this.fireEvent('OverlayViewHide', _this);
22359             }
22360             
22361         });
22362     },
22363     
22364     fromLatLngToContainerPixel: function(event)
22365     {
22366         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22367     },
22368     
22369     isApplied: function() 
22370     {
22371         return this.getGmapContext() == false ? false : true;
22372     },
22373     
22374     getGmapContext: function() 
22375     {
22376         return this.gMapContext
22377     },
22378     
22379     GMapContext: function() 
22380     {
22381         var position = new google.maps.LatLng(this.latitude, this.longitude);
22382         
22383         var _map = new google.maps.Map(this.el.dom, {
22384             center: position,
22385             zoom: this.zoom,
22386             mapTypeId: this.mapTypeId,
22387             mapTypeControl: this.mapTypeControl,
22388             disableDoubleClickZoom: this.disableDoubleClickZoom,
22389             scrollwheel: this.scrollwheel,
22390             streetViewControl: this.streetViewControl,
22391             locationName: this.locationName,
22392             draggable: this.draggable,
22393             enableAutocomplete: this.enableAutocomplete,
22394             enableReverseGeocode: this.enableReverseGeocode
22395         });
22396         
22397         var _marker = new google.maps.Marker({
22398             position: position,
22399             map: _map,
22400             title: this.markerTitle,
22401             draggable: this.draggable
22402         });
22403         
22404         return {
22405             map: _map,
22406             marker: _marker,
22407             circle: null,
22408             location: position,
22409             radius: this.radius,
22410             locationName: this.locationName,
22411             addressComponents: {
22412                 formatted_address: null,
22413                 addressLine1: null,
22414                 addressLine2: null,
22415                 streetName: null,
22416                 streetNumber: null,
22417                 city: null,
22418                 district: null,
22419                 state: null,
22420                 stateOrProvince: null
22421             },
22422             settings: this,
22423             domContainer: this.el.dom,
22424             geodecoder: new google.maps.Geocoder()
22425         };
22426     },
22427     
22428     drawCircle: function(center, radius, options) 
22429     {
22430         if (this.gMapContext.circle != null) {
22431             this.gMapContext.circle.setMap(null);
22432         }
22433         if (radius > 0) {
22434             radius *= 1;
22435             options = Roo.apply({}, options, {
22436                 strokeColor: "#0000FF",
22437                 strokeOpacity: .35,
22438                 strokeWeight: 2,
22439                 fillColor: "#0000FF",
22440                 fillOpacity: .2
22441             });
22442             
22443             options.map = this.gMapContext.map;
22444             options.radius = radius;
22445             options.center = center;
22446             this.gMapContext.circle = new google.maps.Circle(options);
22447             return this.gMapContext.circle;
22448         }
22449         
22450         return null;
22451     },
22452     
22453     setPosition: function(location) 
22454     {
22455         this.gMapContext.location = location;
22456         this.gMapContext.marker.setPosition(location);
22457         this.gMapContext.map.panTo(location);
22458         this.drawCircle(location, this.gMapContext.radius, {});
22459         
22460         var _this = this;
22461         
22462         if (this.gMapContext.settings.enableReverseGeocode) {
22463             this.gMapContext.geodecoder.geocode({
22464                 latLng: this.gMapContext.location
22465             }, function(results, status) {
22466                 
22467                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22468                     _this.gMapContext.locationName = results[0].formatted_address;
22469                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22470                     
22471                     _this.fireEvent('positionchanged', this, location);
22472                 }
22473             });
22474             
22475             return;
22476         }
22477         
22478         this.fireEvent('positionchanged', this, location);
22479     },
22480     
22481     resize: function()
22482     {
22483         google.maps.event.trigger(this.gMapContext.map, "resize");
22484         
22485         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22486         
22487         this.fireEvent('resize', this);
22488     },
22489     
22490     setPositionByLatLng: function(latitude, longitude)
22491     {
22492         this.setPosition(new google.maps.LatLng(latitude, longitude));
22493     },
22494     
22495     getCurrentPosition: function() 
22496     {
22497         return {
22498             latitude: this.gMapContext.location.lat(),
22499             longitude: this.gMapContext.location.lng()
22500         };
22501     },
22502     
22503     getAddressName: function() 
22504     {
22505         return this.gMapContext.locationName;
22506     },
22507     
22508     getAddressComponents: function() 
22509     {
22510         return this.gMapContext.addressComponents;
22511     },
22512     
22513     address_component_from_google_geocode: function(address_components) 
22514     {
22515         var result = {};
22516         
22517         for (var i = 0; i < address_components.length; i++) {
22518             var component = address_components[i];
22519             if (component.types.indexOf("postal_code") >= 0) {
22520                 result.postalCode = component.short_name;
22521             } else if (component.types.indexOf("street_number") >= 0) {
22522                 result.streetNumber = component.short_name;
22523             } else if (component.types.indexOf("route") >= 0) {
22524                 result.streetName = component.short_name;
22525             } else if (component.types.indexOf("neighborhood") >= 0) {
22526                 result.city = component.short_name;
22527             } else if (component.types.indexOf("locality") >= 0) {
22528                 result.city = component.short_name;
22529             } else if (component.types.indexOf("sublocality") >= 0) {
22530                 result.district = component.short_name;
22531             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22532                 result.stateOrProvince = component.short_name;
22533             } else if (component.types.indexOf("country") >= 0) {
22534                 result.country = component.short_name;
22535             }
22536         }
22537         
22538         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22539         result.addressLine2 = "";
22540         return result;
22541     },
22542     
22543     setZoomLevel: function(zoom)
22544     {
22545         this.gMapContext.map.setZoom(zoom);
22546     },
22547     
22548     show: function()
22549     {
22550         if(!this.el){
22551             return;
22552         }
22553         
22554         this.el.show();
22555         
22556         this.resize();
22557         
22558         this.fireEvent('show', this);
22559     },
22560     
22561     hide: function()
22562     {
22563         if(!this.el){
22564             return;
22565         }
22566         
22567         this.el.hide();
22568         
22569         this.fireEvent('hide', this);
22570     }
22571     
22572 });
22573
22574 Roo.apply(Roo.bootstrap.LocationPicker, {
22575     
22576     OverlayView : function(map, options)
22577     {
22578         options = options || {};
22579         
22580         this.setMap(map);
22581     }
22582     
22583     
22584 });/*
22585  * - LGPL
22586  *
22587  * Alert
22588  * 
22589  */
22590
22591 /**
22592  * @class Roo.bootstrap.Alert
22593  * @extends Roo.bootstrap.Component
22594  * Bootstrap Alert class
22595  * @cfg {String} title The title of alert
22596  * @cfg {String} html The content of alert
22597  * @cfg {String} weight (  success | info | warning | danger )
22598  * @cfg {String} faicon font-awesomeicon
22599  * 
22600  * @constructor
22601  * Create a new alert
22602  * @param {Object} config The config object
22603  */
22604
22605
22606 Roo.bootstrap.Alert = function(config){
22607     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22608     
22609 };
22610
22611 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22612     
22613     title: '',
22614     html: '',
22615     weight: false,
22616     faicon: false,
22617     
22618     getAutoCreate : function()
22619     {
22620         
22621         var cfg = {
22622             tag : 'div',
22623             cls : 'alert',
22624             cn : [
22625                 {
22626                     tag : 'i',
22627                     cls : 'roo-alert-icon'
22628                     
22629                 },
22630                 {
22631                     tag : 'b',
22632                     cls : 'roo-alert-title',
22633                     html : this.title
22634                 },
22635                 {
22636                     tag : 'span',
22637                     cls : 'roo-alert-text',
22638                     html : this.html
22639                 }
22640             ]
22641         };
22642         
22643         if(this.faicon){
22644             cfg.cn[0].cls += ' fa ' + this.faicon;
22645         }
22646         
22647         if(this.weight){
22648             cfg.cls += ' alert-' + this.weight;
22649         }
22650         
22651         return cfg;
22652     },
22653     
22654     initEvents: function() 
22655     {
22656         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22657     },
22658     
22659     setTitle : function(str)
22660     {
22661         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22662     },
22663     
22664     setText : function(str)
22665     {
22666         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22667     },
22668     
22669     setWeight : function(weight)
22670     {
22671         if(this.weight){
22672             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22673         }
22674         
22675         this.weight = weight;
22676         
22677         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22678     },
22679     
22680     setIcon : function(icon)
22681     {
22682         if(this.faicon){
22683             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22684         }
22685         
22686         this.faicon = icon
22687         
22688         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22689     },
22690     
22691     hide: function() 
22692     {
22693         this.el.hide();   
22694     },
22695     
22696     show: function() 
22697     {  
22698         this.el.show();   
22699     }
22700     
22701 });
22702
22703